Cdiff g_acquire_cred.c
--- /net/etna.eng/build7/semery/mit2/webrev/usr/src/lib/libgss/g_acquire_cred.c-        Wed Sep  8 17:00:14 2004
+++ g_acquire_cred.c    Wed Sep  8 13:42:01 2004
@@ -1,11 +1,11 @@
 /*
  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident  "@(#)g_acquire_cred.c   1.23    04/09/08 SMI"
+#pragma ident  "@(#)g_acquire_cred.c   1.22    04/02/23 SMI"
 
 /*
  *  glue routine for gss_acquire_cred
  */
 
@@ -19,38 +19,41 @@
 #include <time.h>
 /* local functions */
 static gss_OID_set create_actual_mechs(const gss_OID, int);
 
 static gss_OID_set
-create_actual_mechs(creds)
-       gss_union_cred_t    creds;
+create_actual_mechs(mechs_array, count)
+       const gss_OID   mechs_array;
+       int count;
 {
        gss_OID_set     actual_mechs;
        int             i;
+       OM_uint32       minor;
 
        actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc));
        if (!actual_mechs)
                return (NULL);
 
        actual_mechs->elements = (gss_OID)
-               malloc(sizeof (gss_OID_desc) * creds->count);
+               malloc(sizeof (gss_OID_desc) * count);
        if (!actual_mechs->elements) {
                free(actual_mechs);
                return (NULL);
        }
 
        actual_mechs->count = 0;
 
-       for (i = 0; i < creds->count; i++) {
-               actual_mechs->elements[i].elements =
-                       creds->mechs_array[i].length;
+       for (i = 0; i < count; i++) {
                actual_mechs->elements[i].elements = (void *)
-                       malloc(creds->mechs_array[i].length);
-               memcpy(actual_mechs->elements[i].elements,
-                       creds->mechs_array[i].elements,
-                       creds->mechs_array[i].length);
+                       malloc(mechs_array[i].length);
+               if (actual_mechs->elements[i].elements == NULL) {
+                       (void) gss_release_oid_set(&minor, &actual_mechs);
+                       return (NULL);
        }
+               g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
+               actual_mechs->count++;
+       }
 
        return (actual_mechs);
 }
 
 
@@ -72,289 +75,124 @@
 gss_cred_id_t          *output_cred_handle;
 gss_OID_set *          actual_mechs;
 OM_uint32 *            time_rec;
 
 {
-    OM_uint32           status, temp_minor_status, temp_time_rec = ~0;
-    unsigned int        i, j, creds_acquired = 0;
-    int                 k;
-    gss_union_name_t    union_name;
-    gss_name_t          internal_name;
-    gss_union_cred_t    creds;
+       OM_uint32 major = GSS_S_FAILURE;
+       OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
     gss_OID_set_desc    default_OID_set;
+       gss_OID_set mechs;
     gss_OID_desc        default_OID;
-    gss_OID             specific_mech_type = 0;
     gss_mechanism       mech;
+       int i;
+       gss_union_cred_t creds;
 
-    /*                        
-     * This struct is used to keep track of which mech_types are
-     * actually available and to store the credentials returned
-     * from them by each mechanism specific gss_acquire_cred() call.
-     * The results are used to construct the final union_cred
-     * structure returned by the glue layer gss_acquire_cred() call
-     * and the actual_mechs gss_OID_set returned.
-     */         
+       /* start by checking parameters */
+       if (!minor_status)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+       *minor_status = 0;
 
-    struct creds_returned {
-        unsigned char   available;
-        gss_cred_id_t   cred;
-    } *creds_returned;
+       if (!output_cred_handle)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
 
-       gss_initialize();
+       *output_cred_handle = GSS_C_NO_CREDENTIAL;
 
-       /* Set this to NULL for now */
-
+       /* Set output parameters to NULL for now */
        if (actual_mechs)
                *actual_mechs = GSS_C_NULL_OID_SET;
 
-       if (minor_status)
-               *minor_status = 0;
+       if (time_rec)
+               *time_rec = 0;
 
-       /* No need to continue if we don't have a place to store the creds */
-       if (output_cred_handle == NULL)
-               return GSS_S_COMPLETE;
-
        /*
         * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
-        * appropriate default.
+        * appropriate default.  We use the first mechanism in the
+        * mechansim list as the default. This set is created with
+        * statics thus needs not be freed
         */
        if (desired_mechs == GSS_C_NULL_OID_SET) {
-        /*
-         * If union_name->mech_type is NULL then we get the default
-         * mechanism; otherwise, we get the mechanism for the
-         * mechanism-specific name.
-         */
-               mech = __gss_get_mechanism(specific_mech_type);
+               mech = __gss_get_mechanism(NULL);
                if (mech == NULL)
                        return (GSS_S_BAD_MECH);
-               desired_mechs = &default_OID_set;
+
+               mechs = &default_OID_set;
                default_OID_set.count = 1 ;
                default_OID_set.elements = &default_OID;
                default_OID.length = mech->mech_type.length;
                default_OID.elements = mech->mech_type.elements;
-       }
-
-    /*
-     * Now allocate the creds returned array. There is one element
-     * for each member of the desired_mechs argument.
-     */
-
-    creds_returned = (struct creds_returned *)
-        malloc(sizeof(struct creds_returned) * desired_mechs->count);
-   
-    /*                                                                
-     * For each requested mechanism in desired_mechs, determine if it
-     * is supported. If so, mark the corresponding element in
-     * creds_returned->available as 1 and call the mechanism
-     * specific gss_acquire_cred(), placing the returned cred in
-     * creds_returned->cred. If not, mark creds_returned->available as
-     * 0.
-     */ 
-    status = GSS_S_BAD_MECH;
-    for (j=0; j < desired_mechs->count; j++) {
-        creds_returned[j].available = 0;
- 
-        mech = __gss_get_mechanism (&desired_mechs->elements[j]);
-        if (!mech || !mech->gss_acquire_cred)
-            continue;
-        /*
-         * If this is a mechanism-specific name, then only use the
-         * mechanism of the name.
-         */
-        if (specific_mech_type && !g_OID_equal(specific_mech_type,
-                                               &mech->mech_type))
-            continue;
-        /*
-         * If this is not a mechanism-specific name, then we need to
-         * do an import the external name in union_name first.
-         */
-        if (union_name == 0)
-            internal_name = (gss_name_t) 0;
-        else if (!union_name->mech_type) {
-            if (__gss_import_internal_name(&temp_minor_status,
-                                           &mech->mech_type,
-                                           union_name, &internal_name)) {
-                continue;
-            }
         } else 
-            internal_name = union_name->mech_name;
+               mechs = desired_mechs;
  
-        status = mech->gss_acquire_cred(mech->context, minor_status,
-                                        internal_name, time_req,
-                                        desired_mechs, cred_usage,
-                                        &creds_returned[j].cred,
-                                        NULL, &temp_time_rec);
+       if (mechs->count == NULL)
+               return (GSS_S_BAD_MECH);
 
-        /* Release the internal name, if allocated above */
-        if (union_name && !union_name->mech_type) {
-            (void) __gss_release_internal_name(&temp_minor_status,
-                                               &mech->mech_type,
-                                               &internal_name);
-        }
+       /* allocate the output credential structure */
+       creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
+       if (creds == NULL)
+               return (GSS_S_FAILURE);
  
-        if (status != GSS_S_COMPLETE)
-            continue;
+       /* initialize to 0s */
+       (void) memset(creds, 0, sizeof (gss_union_cred_desc));
  
+       /* for each requested mech attempt to obtain a credential */
+       for (i = 0; i < mechs->count; i++) {
+               major = gss_add_cred(minor_status, (gss_cred_id_t)creds,
+                               desired_name,
+                               &mechs->elements[i],
+                               cred_usage, time_req, time_req, NULL,
+                               NULL, &initTimeOut, &acceptTimeOut);
+               if (major == GSS_S_COMPLETE) {
+                       /* update the credential's time */
+                       if (cred_usage == GSS_C_ACCEPT) {
+                               if (outTime > acceptTimeOut)
+                                       outTime = acceptTimeOut;
+                       } else if (cred_usage == GSS_C_INITIATE) {
+                               if (outTime > initTimeOut)
+                                       outTime = initTimeOut;
+                       } else {
         /*
-         * Add this into the creds_returned structure, if we got
-         * a good credential for this mechanism.
+                                * time_rec is the lesser of the
+                                * init/accept times
          */
-        if (time_rec) {
-            *time_rec = *time_rec > temp_time_rec ? temp_time_rec : *time_rec;
-            temp_time_rec = *time_rec;
+                               if (initTimeOut > acceptTimeOut)
+                                       outTime = (outTime > acceptTimeOut) ?
+                                               acceptTimeOut : outTime;
+                               else
+                                       outTime = (outTime > initTimeOut) ?
+                                               initTimeOut : outTime;
         }
- 
-        creds_returned[j].available = 1;
-        creds_acquired++;
- 
-        /*
-         * If union_name is set, then we're done.  Continue, and
-         * declare success.  Otherwise, if do an inquire credentials
-         * from the first mechanism that succeeds and use that as the
-         * union name.
-         */
-        if (union_name)
-            continue;
- 
-        status = mech->gss_inquire_cred(mech->context, &temp_minor_status,
-                                        creds_returned[j].cred,
-                                        &internal_name, 0, 0, 0);
-        if (status) {
-            /* Should never happen */
-            creds_returned[j].available = 0;
-            creds_acquired--;
-            if (mech->gss_release_cred)
-                mech->gss_release_cred(mech->context, minor_status,
-                                       &creds_returned[j].cred);
-            continue;
         }      
+       } /* for */
  
-        status = __gss_convert_name_to_union_name(&temp_minor_status, mech,
-                                                  internal_name,
-                                                  (gss_name_t *) &union_name);
+       /* ensure that we have at least one credential element */
+       if (creds->count < 1) {
+               free(creds);
+               return (major);
     }
 
     /*
-     * Now allocate the creds struct, which will be cast as a gss_cred_id_t
-     * and returned in the output_cred_handle argument. If there were
-     * no credentials found, return an error. Also, allocate the
-     * actual_mechs data.
+        * fill in output parameters
+        * setup the actual mechs output parameter
      */
-    if (creds_acquired == 0) {
-        free (creds_returned);
-        return (status);
-    }
-
-    creds = (gss_union_cred_t) malloc(sizeof(gss_union_cred_desc));
-     
-    creds->count = creds_acquired;                                  
-
-    creds->mechs_array = (gss_OID) 
-        malloc(sizeof(gss_OID_desc) * creds_acquired);
-    
-    creds->cred_array = (gss_cred_id_t *)
-        malloc(sizeof(gss_cred_id_t) * creds_acquired);
-    
     if(actual_mechs != NULL) {
-        *actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
- 
-        (*actual_mechs)->count = creds_acquired;
- 
-        (*actual_mechs)->elements = (gss_OID)
-            malloc(sizeof(gss_OID_desc) * creds_acquired);
+               if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
+                                       creds->count)) == NULL) {
+                       (void) gss_release_cred(minor_status,
+                               (gss_cred_id_t *)&creds);
+                       *minor_status = 0;
+                       return (GSS_S_FAILURE);
     }
-       
-    /*
-     * copy the mechanisms found and their allocated credentials into the
-     * creds structure. At the same time, build up the actual_mechs
-     * data.
-     */
-    
-    j = 0;
-    
-    for (i=0; i<desired_mechs->count; i++) {
-        if(creds_returned[i].available) {
- 
-            creds->mechs_array[j].length =
-                desired_mechs->elements[i].length;
-            creds->mechs_array[j].elements = (void *)
-                malloc(desired_mechs->elements[i].length);
-            memcpy(creds->mechs_array[j].elements,
-                   desired_mechs->elements[i].elements,
-                   desired_mechs->elements[i].length);
-            creds->cred_array[j] = creds_returned[i].cred;
-            if (actual_mechs) {
-                    (*actual_mechs)->elements[j].length =
-                        desired_mechs->elements[i].length;
-                    (*actual_mechs)->elements[j].elements = (void *)
-                        malloc(desired_mechs->elements[i].length);
-                    memcpy((*actual_mechs)->elements[j].elements,
-                           desired_mechs->elements[i].elements,
-                           desired_mechs->elements[i].length);
             }
-            j++;
-        }    
-    }
     
-    /* free the creds_returned struct, since we are done with it. */
+       if (time_rec)
+               *time_rec = outTime;
      
-    free(creds_returned);
     
-    /* record the information needed for gss_inquire_cred() */
-    
-    creds->auxinfo.creation_time = time(0);                    
-    creds->auxinfo.time_rec = temp_time_rec;
-    creds->auxinfo.cred_usage =  cred_usage;
-    
-    /*                                       
-     * we can't just record the internal name, desired_name, since
-     * it may be destroyed between now and the time gss_inquire_cred()
-     * is called.  So we must record the printable name in a
-     * gss_buffer_t, calling gss_display_name() to fill it in. When
-     * gss_inquire_name() is called, we must then call gss_import_name()
-     * to get the internal name that is required at that point.
-     */
-    if (desired_name) {
-        status = gss_display_name(&temp_minor_status, desired_name,
-                                  &creds->auxinfo.name,
-                                  &creds->auxinfo.name_type);
-        if (status) {
-            status = GSS_S_BAD_NAME;
-            goto error_out;
-        }
-    } else {
-        status = gss_display_name(&temp_minor_status, union_name,
-                                  &creds->auxinfo.name,
-                                  &creds->auxinfo.name_type);
-        if (status) {
-            status = GSS_S_BAD_NAME;
-            goto error_out;
-        }
-    }
-
     *output_cred_handle = (gss_cred_id_t) creds;
     return(GSS_S_COMPLETE);
- 
-error_out:
-    for (k=0; k < creds->count; k++) {
-        free(creds->mechs_array[k].elements);
-        if (actual_mechs)
-            free((*actual_mechs)->elements[k].elements);
     }
 
-    if (actual_mechs) {
-        free((*actual_mechs)->elements);
-        free(*actual_mechs);
-        *actual_mechs = GSS_C_NULL_OID_SET;
-    }
-    free(creds->cred_array);
-    free(creds->mechs_array);
-    free(creds);
-
-    return(status);
-}
-
 /* V2 INTERFACE */
 OM_uint32
 gss_add_cred(minor_status, input_cred_handle,
                        desired_name, desired_mech, cred_usage,
                        initiator_time_req, acceptor_time_req,
@@ -380,34 +218,70 @@
        gss_name_t              allocated_name = GSS_C_NO_NAME;
        gss_cred_id_t           cred = NULL;
        gss_OID                 new_mechs_array = NULL;
        gss_cred_id_t           *new_cred_array = NULL;
 
-       if (input_cred_handle == GSS_C_NO_CREDENTIAL)
-               return (GSS_S_NO_CRED);
+       /* check input parameters */
+       if (minor_status == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE);
+       *minor_status = 0;
 
-       union_cred = (gss_union_cred_t) input_cred_handle;
+       if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+               output_cred_handle == NULL)
+               return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
 
+       if (output_cred_handle)
+               *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+       if (actual_mechs)
+               *actual_mechs = NULL;
+
+       if (acceptor_time_rec)
+               *acceptor_time_rec = 0;
+
+       if (initiator_time_rec)
+               *initiator_time_rec = 0;
+
        mech = __gss_get_mechanism(desired_mech);
        if (!mech)
                return (GSS_S_BAD_MECH);
+       else if (!mech->gss_acquire_cred)
+               return (GSS_S_UNAVAILABLE);
 
+       if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+               union_cred = malloc(sizeof (gss_union_cred_desc));
+               if (union_cred == NULL)
+                       return (GSS_S_FAILURE);
+
+               (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+
+               /* for default credentials we will use GSS_C_NO_NAME */
+               internal_name = GSS_C_NO_NAME;
+       } else {
+               union_cred = (gss_union_cred_t)input_cred_handle;
     if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
         GSS_C_NO_CREDENTIAL)
-        return GSS_S_DUPLICATE_ELEMENT;
+                       return (GSS_S_DUPLICATE_ELEMENT);
  
+               /* may need to create a mechanism specific name */
+               if (desired_name) {
     union_name = (gss_union_name_t) desired_name;
-    if (union_name->mech_type) {
-        if (!g_OID_equal(desired_mech, union_name->mech_type))
-            return GSS_S_BAD_NAMETYPE;
+                       if (union_name->mech_type &&
+                               g_OID_equal(union_name->mech_type,
+                                               &mech->mech_type))
         internal_name = union_name->mech_name;
-    } else {
-        if (__gss_import_internal_name(minor_status, desired_mech,
-                                       union_name, &internal_name))
+                       else {
+                               if (__gss_import_internal_name(minor_status,
+                                       &mech->mech_type, union_name,
+                                       &allocated_name) != GSS_S_COMPLETE)
             return (GSS_S_BAD_NAME);
+                               internal_name = allocated_name;
     }
+               }
+       }
      
+
     if (cred_usage == GSS_C_ACCEPT)
         time_req = acceptor_time_req;
     else if (cred_usage == GSS_C_INITIATE)
         time_req = initiator_time_req;
     else if (cred_usage == GSS_C_BOTH)
@@ -416,83 +290,132 @@
  
     status = mech->gss_acquire_cred(mech->context, minor_status,
                                     internal_name, time_req,
                                     GSS_C_NULL_OID_SET, cred_usage,
                                     &cred, NULL, &time_rec);
+
     if (status != GSS_S_COMPLETE)
         goto errout;
  
+       /* may need to set credential auxinfo strucutre */
+       if (union_cred->auxinfo.creation_time == 0) {
+               union_cred->auxinfo.creation_time = time(NULL);
+               union_cred->auxinfo.time_rec = time_rec;
+               union_cred->auxinfo.cred_usage = cred_usage;
+
+               /*
+                * we must set the name; if name is not supplied
+                * we must do inquire cred to get it
+                */
+               if (internal_name == NULL) {
+                       if (mech->gss_inquire_cred == NULL ||
+                               ((status = mech->gss_inquire_cred(
+                                               mech->context,
+                                               &temp_minor_status, cred,
+                                               &allocated_name, NULL, NULL,
+                                               NULL)) != GSS_S_COMPLETE))
+                               goto errout;
+                       internal_name = allocated_name;
+               }
+
+               if ((status = mech->gss_display_name(mech->context,
+                               &temp_minor_status, internal_name,
+                               &union_cred->auxinfo.name,
+                               &union_cred->auxinfo.name_type)) !=
+                       GSS_S_COMPLETE)
+                       goto errout;
+       }
+
+       /* now add the new credential elements */
     new_mechs_array = (gss_OID)
         malloc(sizeof(gss_OID_desc) * (union_cred->count+1));
 
     new_cred_array = (gss_cred_id_t *)                        
         malloc(sizeof(gss_cred_id_t) * (union_cred->count+1));
 
     if (!new_mechs_array || !new_cred_array) {
-        *minor_status = ENOMEM;
         status = GSS_S_FAILURE;
         goto errout;
     }
  
- 
     if (acceptor_time_rec)
         if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
             *acceptor_time_rec = time_rec;
     if (initiator_time_rec)
         if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
             *initiator_time_rec = time_rec;
  
     /*
-     * OK, expand the mechanism array in the union credentials
-     * (Look for the union label...)
+        * OK, expand the mechanism array and the credential array
      */
-    memcpy(new_mechs_array, union_cred->mechs_array,
+       (void) memcpy(new_mechs_array, union_cred->mechs_array,
            sizeof(gss_OID_desc) * union_cred->count);
-    memcpy(new_cred_array, union_cred->cred_array,
+       (void) memcpy(new_cred_array, union_cred->cred_array,
            sizeof(gss_cred_id_t) * union_cred->count);
      
     new_cred_array[union_cred->count] = cred;
-    new_mechs_array[union_cred->count].length = desired_mech->length;
-    new_mechs_array[union_cred->count].elements = malloc(desired_mech->length);
-    if (!new_mechs_array[union_cred->count].elements) {
-        *minor_status = ENOMEM;
+       if ((new_mechs_array[union_cred->count].elements =
+                       malloc(mech->mech_type.length)) == NULL)
         goto errout;
+
+       g_OID_copy(&new_mechs_array[union_cred->count],
+                       &mech->mech_type);
+
+       if (actual_mechs) {
+               *actual_mechs = create_actual_mechs(new_mechs_array,
+                                       union_cred->count + 1);
+               if (*actual_mechs == NULL) {
+                       free(new_mechs_array[union_cred->count].elements);
+                       goto errout;
     }
-    memcpy(new_mechs_array[union_cred->count].elements, desired_mech->elements,
-           desired_mech->length);
+       }
  
     if (output_cred_handle == NULL) {
         free(union_cred->mechs_array);
         free(union_cred->cred_array);
         new_union_cred = union_cred;
     } else {
         new_union_cred = malloc(sizeof(gss_union_cred_desc));
         if (new_union_cred == NULL) {
-            *minor_status = ENOMEM;
+                       free(new_mechs_array[union_cred->count].elements);
             goto errout;
         }
         *new_union_cred = *union_cred;
-        *output_cred_handle = new_union_cred;
+               *output_cred_handle = (gss_cred_id_t)new_union_cred;
     }
+
     new_union_cred->mechs_array = new_mechs_array;
     new_union_cred->cred_array = new_cred_array;
     new_union_cred->count++;
-    new_mechs_array = 0;
-    new_cred_array = 0;
  
-    if (actual_mechs)
-        *actual_mechs = create_actual_mechs(new_union_cred);
+       /* We're done with the internal name. Free it if we allocated it. */
 
-    status = GSS_S_COMPLETE;                                 
+       if (allocated_name)
+               (void) __gss_release_internal_name(&temp_minor_status,
+                                       &mech->mech_type,
+                                       &allocated_name);
 
+       return (GSS_S_COMPLETE);
+
 errout:                      
     if (new_mechs_array)
         free(new_mechs_array);
     if (new_cred_array)
         free(new_cred_array);
-    if (!union_name->mech_type) {
+
+       if (cred != NULL && mech->gss_release_cred)
+               mech->gss_release_cred(mech->context,
+                               &temp_minor_status, &cred);
+
+       if (allocated_name)
         (void) __gss_release_internal_name(&temp_minor_status,
-                                           desired_mech, &internal_name);
+                                       &mech->mech_type,
+                                       &allocated_name);
+
+       if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
+               if (union_cred->auxinfo.name.value)
+                       free(union_cred->auxinfo.name.value);
+               free(union_cred);
     }
             
     return(status);
 }