GSS-API Programming Guide

call_server()

This is the centerpiece of the program.


Example A–4 call_server()

/*
 * 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;
}