Establishing a context typically involves a series of token exchanges between the client and the server. Both context acceptance and context initialization should be performed in loops to maintain program portability. The loop for accepting a context is very similar to the loop for establishing a context, although in reverse. Compare with Establishing a Security Context With the Server.
The following source code illustrates the server_establish_context() function.
The source code for this example is also available through the Sun download center. See http://www.sun.com/download/products.xml?id=41912db5.
/*
* Function: server_establish_context
*
* Purpose: establishes a GSS-API context as a specified service with
* an incoming client, and returns the context handle and associated
* client name
*
* Arguments:
*
* s (r) an established TCP connection to the client
* service_creds (r) server credentials, from gss_acquire_cred
* context (w) the established GSS-API context
* client_name (w) the client's ASCII name
*
* Returns: 0 on success, -1 on failure
*
* Effects:
*
* Any valid client request is accepted. If a context is established,
* its handle is returned in context and the client name is returned
* in client_name and 0 is returned. If unsuccessful, an error
* message is displayed and -1 is returned.
*/
int server_establish_context(s, server_creds, context, client_name, ret_flags)
int s;
gss_cred_id_t server_creds;
gss_ctx_id_t *context;
gss_buffer_t client_name;
OM_uint32 *ret_flags;
{
gss_buffer_desc send_tok, recv_tok;
gss_name_t client;
gss_OID doid;
OM_uint32 maj_stat, min_stat, acc_sec_min_stat;
gss_buffer_desc oid_name;
*context = GSS_C_NO_CONTEXT;
do {
if (recv_token(s, &recv_tok) < 0)
return -1;
if (verbose && log) {
fprintf(log, "Received token (size=%d): \n", recv_tok.length);
print_token(&recv_tok);
}
maj_stat =
gss_accept_sec_context(&acc_sec_min_stat,
context,
server_creds,
&recv_tok,
GSS_C_NO_CHANNEL_BINDINGS,
&client,
&doid,
&send_tok,
ret_flags,
NULL, /* ignore time_rec */
NULL); /* ignore del_cred_handle */
(void) gss_release_buffer(&min_stat, &recv_tok);
if (send_tok.length != 0) {
if (verbose && log) {
fprintf(log,
"Sending accept_sec_context token (size=%d):\n",
send_tok.length);
print_token(&send_tok);
}
if (send_token(s, &send_tok) < 0) {
fprintf(log, "failure sending token\n");
return -1;
}
(void) gss_release_buffer(&min_stat, &send_tok);
}
if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
display_status("accepting context", maj_stat,
acc_sec_min_stat);
if (*context == GSS_C_NO_CONTEXT)
gss_delete_sec_context(&min_stat, context,
GSS_C_NO_BUFFER);
return -1;
}
if (verbose && log) {
if (maj_stat == GSS_S_CONTINUE_NEEDED)
fprintf(log, "continue needed...\n");
else
fprintf(log, "\n");
fflush(log);
}
} while (maj_stat == GSS_S_CONTINUE_NEEDED);
/* display the flags */
display_ctx_flags(*ret_flags);
if (verbose && log) {
maj_stat = gss_oid_to_str(&min_stat, doid, &oid_name);
if (maj_stat != GSS_S_COMPLETE) {
display_status("converting oid->string", maj_stat, min_stat);
return -1;
}
fprintf(log, "Accepted connection using mechanism OID %.*s.\n",
(int) oid_name.length, (char *) oid_name.value);
(void) gss_release_buffer(&min_stat, &oid_name);
}
maj_stat = gss_display_name(&min_stat, client, client_name, &doid);
if (maj_stat != GSS_S_COMPLETE) {
display_status("displaying name", maj_stat, min_stat);
return -1;
}
maj_stat = gss_release_name(&min_stat, &client);
if (maj_stat != GSS_S_COMPLETE) {
display_status("releasing name", maj_stat, min_stat);
return -1;
}
return 0;
}
The sign_server() function uses the following source code to call server_establish_context() to accept the context.
/* Establish a context with the client */
if (server_establish_context(s, server_creds, &context,
&client_name, &ret_flags) < 0)
return(-1);
The server_establish_context() function first looks for a token that the client sends as part of the context initialization process. Because, GSS-API does not send or receive tokens itself, programs must have their own routines for performing these tasks. The server uses recv_token() for receiving the token:
do {
if (recv_token(s, &recv_tok) < 0)
return -1;
Next, server_establish_context() calls the GSS-API function gss_accept_sec_context():
maj_stat = gss_accept_sec_context(&min_stat,
context,
server_creds,
&recv_tok,
GSS_C_NO_CHANNEL_BINDINGS,
&client,
&doid,
&send_tok,
ret_flags,
NULL, /* ignore time_rec */
NULL); /* ignore del_cred_handle */
min_stat is the error status returned by the underlying mechanism.
context is the context being established.
server_creds is the credential for the service to be provided (see Acquiring Credentials).
recv_tok is the token received from the client by recv_token().
GSS_C_NO_CHANNEL_BINDINGS is a flag indicating not to use channel bindings (see Using Channel Bindings in GSS-API).
client is the ASCII name of the client.
oid is the mechanism (in OID format).
send_tok is the token to send to the client.
ret_flags are various flags indicating whether the context supports a given option, such as message-sequence-detection.
The two NULL arguments indicate that the program does not need to know the length of time that the context will be valid, or whether the server can act as a client's proxy.
The acceptance loop continues, barring any errors, as long as gss_accept_sec_context() sets maj_stat to GSS_S_CONTINUE_NEEDED. If maj_stat is not equal to that value or to GSS_S_COMPLETE, a problem exists and the loop exits.
gss_accept_sec_context() returns a positive value for the length of send_tok whether a token exists to send back to the client. The next step is to see a token exists to be sent, and, if so, to send the token:
if (send_tok.length != 0) {
. . .
if (send_token(s, &send_tok) < 0) {
fprintf(log, "failure sending token\n");
return -1;
}
(void) gss_release_buffer(&min_stat, &send_tok);
}