GSS-API Programming Guide

Establishing a Context

After the connection is established, call_server() uses the function client_establish_context() to, yes, establish the security context:


int client_establish_context(s, service_name, deleg_flag, oid, 
     &context, &ret_flags)

where

To initiate the context, the application uses the function gss_init_sec_context(). As this function, like most GSS-API functions, requires names to be in internal GSS-API format, the application must first translate the service name from a string to internal format. For that, it can use gss_import_name():


maj_stat = gss_import_name(&min_stat, &send_tok, 
     (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &target_name);

This function takes the name of the service (stored in an opaque GSS_API buffer, send_tok) and converts it to the GSS_API internal name target_name. (send_tok is used to save space, instead of declaring a new gss_buffer_desc.) The third argument is a gss_OID type that indicates the name format that send_tok has. In this case, it is GSS_C_NT_HOSTBASED_SERVICE, which means a service of the format service@host. (See Name Types for other possible values for this argument.)

Once the service has been rendered in GSS-API internal format, we can proceed with establishing the context. In order to maximize portability, context-establishment should always be performed as a loop (see Context Initiation (Client)).

First, the application initializes the context to be null:


*gss_context = GSS_C_NO_CONTEXT;

It does the same for the token that we'll receive from the server:


token_ptr = GSS_C_NO_BUFFER;

The application now enters the loop. The loop proceeds by checking two things: the status returned by gss_init_sec_context() and the size of the token to be sent to the server (also generated by gss_init_sec_context()). If the token's size is zero, then the server is not expecting another token from the client. The pseudocode for the loop that follows looks like this:

do
     gss_init_sec_context()
     if no context was created
         uh-oh.  Exit with error;
    if the status is neither "complete" nor "in process"
         uh-oh.  Release the service namespace and exit with error;
    if there's a token to send to the server (= if its size is nonzero)
          send it;
         if sending it fails,
               oops!  release the token and the service 
                    namespaces and exit with error;
         release the namespace for the token we've just sent;
     if we're not done setting up the context
          receive a token from the server;
while the context is not complete

First, the call to gss_init_sec_context():


do {
     maj_stat = gss_init_sec_context(&min_stat,
                           GSS_C_NO_CREDENTIAL,
                           gss_context,
                           target_name
                           oid
                           GSS_C_MUTUAL_FLAG | 
                              GSS_C_REPLAY_FLAG |
                              deleg_flag,
                           0,
                           NULL,
                           &send_tok,
                           ret_flags,
                           NULL);

where the arguments are as follows:

You might have noticed that the client does not need to acquire credentials before initiating a context. On the client side, credential management is handled transparently by the GSS-API. That is, the GSS-API “knows” how to get credentials created by this mechanism for this principal (usually at login time). That is why the application passes gss_init_sec_context() a default credential. On the server side, however, a server application must explicitly acquire credentials for a service before accepting a context. See Acquiring Credentials.

After checking that it has a context (but not necessarily a complete one) and that gss_init_sec_context() is returning valid status, the application sees if gss_init_sec_context() has given it a token to send to the server. If it hasn't, it's because the server has indicated that it doesn't need (another) one. If it has, then send it to the server. If sending it fails, release the namespaces for it and the service, and exit. Remember, you can check for the presence of a token by looking at its length:


if (send_tok_length != 0) {
               if (send_token(s, &send_tok) < 0) {
                    (void) gss_release_buffer(&min_stat, &send_tok);
                    (void) gss_release_name(&min_stat, &target_name);
                    return -1;
               }
          }

send_token() is not a GSS-API function; it is a basic write-to-file function written by the user. (You can see it at send_token().) Note that the GSS-API does not send or receive tokens itself. It is the responsibility of the calling applications to send and receive any tokens created by the GSS-API.

If the server doesn't have any (more) tokens to send, then gss_init_sec_context() returns GSS_S_COMPLETE. So if gss_init_sec_context()hasn't returned this value, the application knows there's another token out there to fetch. If the fetch fails it releases the service namespace and quit:


if (maj_stat == GSS_S_CONTINUE_NEEDED) {
               if (recv_token(s, &recv_tok) < 0) {
                    (void) gss_release_name(&min_stat, &target_name);
                    return -1;

Finally, the program resets its token pointers, and continues the loop until the context is completely established. Thus its do loop ends as follows:


} while (maj_stat == GSS_S_CONTINUE_NEEDED);