Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
2.  A Walk-Through of the Sample GSS-API Programs Server-Side GSS-API: gss-server Overview: main() (Server)  Previous   Contents   Next 
   
 

Creating an OID for the Mechanism

As with the gss-client program example, the sample server program allows the user to specify a mechanism. However, it is strongly recommended that all applications use the default mechanism provided by the GSS-API implementation. The default mechanism is obtained by setting the gss_OID that represents the mechanism to GSS_C_NULL_OID. Interested readers can refer to the code itself in "createMechOid()" and read about using non-default mechanisms in Appendix C, Specifying an OID.

Acquiring Credentials

As with the client application, neither the server application nor the GSS-API create credentials; they are created by the underlying mechanism(s). Unlike the client program, the server needs to explicitly acquire the credentials it needs. (Some client applications might want to acquire credentials explicitly, in which case they do so in the same manner as shown here. But generally the client has acquired credentials before that, at login time, and GSS-API acquires those automatically.)

The gss-server program has its own function, server_acquire_creds(), to get the credentials for the service being provided. It takes as its input the name of the service, and the security mechanism being used, then returns the credentials for the service.

server_acquire_creds() uses the GSS-API function gss_acquire_cred() to get the credentials for the service that the server provides. Before it can do this, however, it must do two things.

If a single credential can be shared by multiple mechanisms, gss_acquire_cred() returns credentials for all those mechanisms. Therefore, it takes as input not a single mechanism, but a set of mechanisms. (See "Credentials".) However, in most cases, including this one, a single credential might not work for multiple mechanisms. Besides, in the server application, either a single mechanism is specified on the command line or the default mechanism is used. Therefore, the first thing to do is make sure that the set of mechanisms passed to gss_acquire_cred() contains a single mechanism, default or otherwise:

if (mechOid != GSS_C_NULL_OID) {
     desiredMechs = &mechOidSet;
     mechOidSet.count = 1;
     mechOidSet.elements = mechOid;
} else
     desiredMechs = GSS_C_NULL_OID_SET;

GSS_C_NULL_OID_SET indicates that the default mechanism should be used.

Because gss_acquire_cred() takes the service name in the form of a gss_name_t structure, the second thing to do is import the name of the service into that format. To do this, use gss_import_name(). Because this function, like all GSS-API functions, requires arguments to be GSS-API types, the service name has to be copied to a GSS-API buffer first:

     name_buf.value = service_name;
     name_buf.length = strlen(name_buf.value) + 1;
     maj_stat = gss_import_name(&min_stat, &name_buf,
                (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name);
     if (maj_stat != GSS_S_COMPLETE) {
          display_status("importing name", maj_stat, min_stat);
          if (mechOid != GSS_C_NO_OID)
                gss_release_oid(&min_stat, &mechOid);
          return -1;
     }

Note again the use of the nonstandard function gss_release_oid(). See "Overview: main() (Client)".

The input is the service name, as a string in name_buf, and the output is the pointer to a gss_name_t structure, server_name. The third argument, GSS_C_NT_HOSTBASED_SERVICE, is the name type for the string in name_buf; in this case it indicates that the string should be interpreted as a service of the format service@host.

Now the server program can call gss_acquire_cred():

maj_stat = gss_acquire_cred(&min_stat, server_name, 0,
                                 desiredMechs, GSS_C_ACCEPT,
                                 server_creds, NULL, NULL);

Where:

  • min_stat is the error code returned by the function.

  • server_name is, as explained above, the name of the server.

  • 0 indicates that the program isn't interested the maximum lifetime of the credential.

  • desiredMechs is, as explained above, the set of mechanisms for which this credential applies.

  • GSS_C_ACCEPT means that the credential can be used only to accept security contexts.

  • server_creds is the credential handle to be returned by the function.

  • NULL, NULL indicates that the program is not interested in knowing either the specific mechanism being employed nor the amount of time the credential will be valid.

Accepting a Context, Getting and Signing Data

Having acquired credentials for the service, the server program checks to see if the user has specified using inetd (see "Overview: main() (Server)") and then calls sign_server(), which does the main work of the program. The first thing that sign_server() does is establish the context by calling server_establish_context().


Note - inetd is not covered here. Basically, if inetd has been specified, the program calls sign_server() on the standard input. If not, it creates a socket, accepts a connection, and then calls sign_server() on that connection.


sign_server() does the following:

  1. Accepts the context.

  2. Unwraps the data.

  3. Signs the data.

  4. Returns the data.

Accepting a Context

Because establishing a context can involve 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. Indeed, the loop for accepting a context is very similar to that for establishing one, although rather in reverse. (Compare with "Establishing a Context".)

  1. The first thing the server does is look for a token that the client should have sent as part of the context initialization process. Remember, the GSS-API does not send or receive tokens itself, so programs must have their own routines for performing these tasks. The one the server uses for receiving the token is called recv_token() (it can be found at "recv_token()"):

         do {
              if (recv_token(s, &recv_tok) < 0)
                   return -1;
  2. Next, the program 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 */

    where

    • 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 being 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 "Channel Bindings").

    • 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.

    • NULL and NULL indicate that the program is not interested in the length of time the context will be valid, nor in whether the server can act as a client's proxy.

    The acceptance loop continues (barring an error) as long as gss_accept_sec_context() sets maj_stat to GSS_S_CONTINUE_NEEDED. If maj_stat is not equal to either that value nor to GSS_S_COMPLETE, there's a problem and the loop exits.

  3. gss_accept_sec_context() returns a positive value for the length of send_tok if there is a token to send back to the client. The next step is to see if there's a token to send, and, if so, to send it:

         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);
              }
 
 
 
  Previous   Contents   Next