Converts the name of the security mechanism provided on the command line (if any is provided) to an OID for GSS-API to work with.
This is the centerpiece of the program.
/*
* Function: call_server
*
* Purpose: Call the "sign" service.
*
* Arguments:
*
* host (r) the host providing the service
* port (r) the port to connect to on host
* service_name (r) the GSS-API service name to authenticate to
* msg (r) the message to have "signed"
*
* Returns: 0 on success, -1 on failure
*
* Effects:
*
* call_server opens a TCP connection to <host:port> and establishes a
* GSS-API context with service_name over the connection. It then
* wraps msg in a GSS-API token with gss_wrap, sends it to the server,
* reads back a GSS-API signature block for msg from the server, and
* verifies it with gss_verify. -1 is returned if any step fails,
* otherwise 0 is returned.
*/
int call_server(host, port, oid, service_name, deleg_flag, msg, use_file)
char *host;
u_short port;
gss_OID oid;
char *service_name;
OM_uint32 deleg_flag;
char *msg;
int use_file;
{
gss_ctx_id_t context;
gss_buffer_desc in_buf, out_buf, context_token;
int s, state;
OM_uint32 ret_flags;
OM_uint32 maj_stat, min_stat;
gss_name_t src_name, targ_name;
gss_buffer_desc sname, tname;
OM_uint32 lifetime;
gss_OID mechanism, name_type;
int is_local;
OM_uint32 context_flags;
int is_open;
gss_qop_t qop_state;
gss_OID_set mech_names;
gss_buffer_desc oid_name;
int i;
int conf_req_flag = 0;
int req_output_size = 1012;
OM_uint32 max_input_size = 0;
char *mechStr;
/* Open connection */
if ((s = connect_to_server(host, port)) < 0)
return -1;
/* Establish context */
if (client_establish_context(s, service_name, deleg_flag, oid, &context,
&ret_flags) < 0) {
(void) close(s);
return -1;
}
/* Save and then restore the context */
maj_stat = gss_export_sec_context(&min_stat,
&context,
&context_token);
if (maj_stat != GSS_S_COMPLETE) {
display_status("exporting context", maj_stat, min_stat);
return -1;
}
maj_stat = gss_import_sec_context(&min_stat,
&context_token,
&context);
if (maj_stat != GSS_S_COMPLETE) {
display_status("importing context", maj_stat, min_stat);
return -1;
}
(void) gss_release_buffer(&min_stat, &context_token);
/* display the flags */
display_ctx_flags(ret_flags);
/* Get context information */
maj_stat = gss_inquire_context(&min_stat, context,
&src_name, &targ_name, &lifetime,
&mechanism, &context_flags,
&is_local,
&is_open);
if (maj_stat != GSS_S_COMPLETE) {
display_status("inquiring context", maj_stat, min_stat);
return -1;
}
if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
printf(" context expired\n");
display_status("Context is expired", maj_stat, min_stat);
return -1;
}
/* Test gss_wrap_size_limit */
maj_stat = gss_wrap_size_limit(&min_stat, context,
conf_req_flag,
GSS_C_QOP_DEFAULT,
req_output_size,
&max_input_size
);
if (maj_stat != GSS_S_COMPLETE) {
display_status("wrap_size_limit call", maj_stat, min_stat);
} else
fprintf (stderr, "gss_wrap_size_limit returned "
"max input size = %d \n"
"for req_output_size = %d with Integrity only\n",
max_input_size , req_output_size , conf_req_flag);
conf_req_flag = 1;
maj_stat = gss_wrap_size_limit(&min_stat, context,
conf_req_flag,
GSS_C_QOP_DEFAULT,
req_output_size,
&max_input_size
);
if (maj_stat != GSS_S_COMPLETE) {
display_status("wrap_size_limit call", maj_stat, min_stat);
} else
fprintf (stderr, "gss_wrap_size_limit returned "
" max input size = %d \n"
"for req_output_size = %d with "
"Integrity & Privacy \n",
max_input_size , req_output_size );
maj_stat = gss_display_name(&min_stat, src_name, &sname,
&name_type);
if (maj_stat != GSS_S_COMPLETE) {
display_status("displaying source name", maj_stat, min_stat);
return -1;
}
maj_stat = gss_display_name(&min_stat, targ_name, &tname,
(gss_OID *) NULL);
if (maj_stat != GSS_S_COMPLETE) {
display_status("displaying target name", maj_stat, min_stat);
return -1;
}
fprintf(stderr, "\"%.*s\" to \"%.*s\", lifetime %u, flags %x, %s, %s\n",
(int) sname.length, (char *) sname.value,
(int) tname.length, (char *) tname.value, lifetime,
context_flags,
(is_local) ? "locally initiated" : "remotely initiated",
(is_open) ? "open" : "closed");
(void) gss_release_name(&min_stat, &src_name);
(void) gss_release_name(&min_stat, &targ_name);
(void) gss_release_buffer(&min_stat, &sname);
(void) gss_release_buffer(&min_stat, &tname);
maj_stat = gss_oid_to_str(&min_stat,
name_type,
&oid_name);
if (maj_stat != GSS_S_COMPLETE) {
display_status("converting oid->string", maj_stat, min_stat);
return -1;
}
fprintf(stderr, "Name type of source name is %.*s.\n",
(int) oid_name.length, (char *) oid_name.value);
(void) gss_release_buffer(&min_stat, &oid_name);
/* Now get the names supported by the mechanism */
maj_stat = gss_inquire_names_for_mech(&min_stat,
mechanism,
&mech_names);
if (maj_stat != GSS_S_COMPLETE) {
display_status("inquiring mech names", maj_stat, min_stat);
return -1;
}
maj_stat = gss_oid_to_str(&min_stat,
mechanism,
&oid_name);
if (maj_stat != GSS_S_COMPLETE) {
display_status("converting oid->string", maj_stat, min_stat);
return -1;
}
mechStr = (char *)__gss_oid_to_mech(mechanism);
fprintf(stderr, "Mechanism %.*s (%s) supports %d names\n",
(int) oid_name.length, (char *) oid_name.value,
(mechStr == NULL ? "NULL" : mechStr),
mech_names->count);
(void) gss_release_buffer(&min_stat, &oid_name);
for (i=0; i < mech_names->count; i++) {
maj_stat = gss_oid_to_str(&min_stat,
&mech_names->elements[i],
&oid_name);
if (maj_stat != GSS_S_COMPLETE) {
display_status("converting oid->string", maj_stat, min_stat);
return -1;
}
fprintf(stderr, " %d: %.*s\n", i,
(int) oid_name.length, (char *) oid_name.value);
(void) gss_release_buffer(&min_stat, &oid_name);
}
(void) gss_release_oid_set(&min_stat, &mech_names);
if (use_file) {
read_file(msg, &in_buf);
} else {
/* Seal the message */
in_buf.value = msg;
in_buf.length = strlen(msg) + 1;
}
if (ret_flag & GSS_C_CONF_FLAG) {
state = 1;
else
state = 0;
}
maj_stat = gss_wrap(&min_stat, context, 1, GSS_C_QOP_DEFAULT,
&in_buf, &state, &out_buf);
if (maj_stat != GSS_S_COMPLETE) {
display_status("wrapping message", maj_stat, min_stat);
(void) close(s);
(void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
return -1;
} else if (! state) {
fprintf(stderr, "Warning! Message not encrypted.\n");
}
/* Send to server */
if (send_token(s, &out_buf) < 0) {
(void) close(s);
(void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
return -1;
}
(void) gss_release_buffer(&min_stat, &out_buf);
/* Read signature block into out_buf */
if (recv_token(s, &out_buf) < 0) {
(void) close(s);
(void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
return -1;
}
/* Verify signature block */
maj_stat = gss_verify_mic(&min_stat, context, &in_buf,
&out_buf, &qop_state);
if (maj_stat != GSS_S_COMPLETE) {
display_status("verifying signature", maj_stat, min_stat);
(void) close(s);
(void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
return -1;
}
(void) gss_release_buffer(&min_stat, &out_buf);
if (use_file)
free(in_buf.value);
printf("Signature verified.\n");
/* Delete context */
maj_stat = gss_delete_sec_context(&min_stat, &context, &out_buf);
if (maj_stat != GSS_S_COMPLETE) {
display_status("deleting context", maj_stat, min_stat);
(void) close(s);
(void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
return -1;
}
(void) gss_release_buffer(&min_stat, &out_buf);
(void) close(s);
return 0;
}
|