1   /*
   2    * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
   3    * Use is subject to license terms.
   4    */
   5   
   6 | #pragma ident        "@(#)g_acquire_cred.c        1.23        04/09/08 SMI"
   6 | #pragma ident        "@(#)g_acquire_cred.c        1.22        04/02/23 SMI"
   7   
   8   /*
   9    *  glue routine for gss_acquire_cred
  10    */
  11   
  12   #include <mechglueP.h>
  13   #include <stdio.h>
  14   #ifdef HAVE_STDLIB_H
  15   #include <stdlib.h>
  16   #endif
  17   #include <string.h>
  18   #include <errno.h>
  19   #include <time.h>
  20   /* local functions */
  21   static gss_OID_set create_actual_mechs(const gss_OID, int);
  22   
  23   static gss_OID_set
  24 | create_actual_mechs(creds)
  25 |         gss_union_cred_t    creds;
  24 | create_actual_mechs(mechs_array, count)
  25 |         const gss_OID        mechs_array;
  26 +         int count;
  27   {
  28           gss_OID_set         actual_mechs;
  29           int                i;
  30 +         OM_uint32        minor;
  31   
  32           actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc));
  33           if (!actual_mechs)
  34                   return (NULL);
  35   
  36           actual_mechs->elements = (gss_OID)
  35 |                 malloc(sizeof (gss_OID_desc) * creds->count);
  37 |                 malloc(sizeof (gss_OID_desc) * count);
  38           if (!actual_mechs->elements) {
  39                   free(actual_mechs);
  40                   return (NULL);
  41           }
  42   
  43           actual_mechs->count = 0;
  44   
  43 |         for (i = 0; i < creds->count; i++) {
  45 |         for (i = 0; i < count; i++) {
  44 -                 actual_mechs->elements[i].elements =
  45 -                         creds->mechs_array[i].length;
  46                   actual_mechs->elements[i].elements = (void *)
  47 |                         malloc(creds->mechs_array[i].length);
  48 |                 memcpy(actual_mechs->elements[i].elements,
  49 |                         creds->mechs_array[i].elements,
  50 |                         creds->mechs_array[i].length);
  47 |                         malloc(mechs_array[i].length);
  48 |                 if (actual_mechs->elements[i].elements == NULL) {
  49 |                         (void) gss_release_oid_set(&minor, &actual_mechs);
  50 |                         return (NULL);
  51                   }
  52 +                 g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
  53 +                 actual_mechs->count++;
  54 +         }
  55   
  56           return (actual_mechs);
  57   }
  58   
  59   
  60   OM_uint32
  61   gss_acquire_cred(minor_status,
  62                           desired_name,
  63                           time_req,
  64                           desired_mechs,
  65                           cred_usage,
  66                           output_cred_handle,
  67                           actual_mechs,
  68                           time_rec)
  69   
  70   OM_uint32 *                minor_status;
  71   const gss_name_t        desired_name;
  72   OM_uint32                time_req;
  73   const gss_OID_set        desired_mechs;
  74   int                        cred_usage;
  75   gss_cred_id_t                 *output_cred_handle;
  76   gss_OID_set *                actual_mechs;
  77   OM_uint32 *                time_rec;
  78   
  79   {
  77 |     OM_uint32           status, temp_minor_status, temp_time_rec = ~0;
  78 |     unsigned int        i, j, creds_acquired = 0;
  80 |         OM_uint32 major = GSS_S_FAILURE;
  81 |         OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
  79 -     int                 k;
  80 -     gss_union_name_t    union_name;
  81 -     gss_name_t          internal_name;
  82 -     gss_union_cred_t    creds;
  82           gss_OID_set_desc default_OID_set;
  83 +         gss_OID_set mechs;
  85 -     gss_OID             specific_mech_type = 0;
  84           gss_OID_desc default_OID;
  85           gss_mechanism mech;
  86 +         int i;
  87 +         gss_union_cred_t creds;
  88   
  88 |     /*                        
  89 |      * This struct is used to keep track of which mech_types are
  90 |      * actually available and to store the credentials returned
  91 |      * from them by each mechanism specific gss_acquire_cred() call.
  89 |         /* start by checking parameters */
  90 |         if (!minor_status)
  91 |                 return (GSS_S_CALL_INACCESSIBLE_WRITE);
  92 |         *minor_status = 0;
  92 -      * The results are used to construct the final union_cred
  93 -      * structure returned by the glue layer gss_acquire_cred() call
  94 -      * and the actual_mechs gss_OID_set returned.
  95 -      */         
  93   
  97 |     struct creds_returned {
  98 |         unsigned char   available;
  94 |         if (!output_cred_handle)
  95 |                 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
  99 -         gss_cred_id_t   cred;
 100 -     } *creds_returned;
  96   
 102 |         gss_initialize();
  97 |         *output_cred_handle = GSS_C_NO_CREDENTIAL;
  98   
 104 |         /* Set this to NULL for now */
  99 |         /* Set output parameters to NULL for now */
 105 - 
 100           if (actual_mechs)
 101                   *actual_mechs = GSS_C_NULL_OID_SET;
 102   
 109 |         if (minor_status)
 110 |                 *minor_status = 0;
 103 |         if (time_rec)
 104 |                 *time_rec = 0;
 112 -         /* No need to continue if we don't have a place to store the creds */
 113 -         if (output_cred_handle == NULL)
 114 -                 return GSS_S_COMPLETE;
 115 - 
 105   
 106           /*
 107            * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
 118 |          * appropriate default.
 108 |          * appropriate default.  We use the first mechanism in the
 109 +          * mechansim list as the default. This set is created with
 110 +          * statics thus needs not be freed
 111            */
 112           if (desired_mechs == GSS_C_NULL_OID_SET) {
 121 |          /*
 113 |                 mech = __gss_get_mechanism(NULL);
 122 -          * If union_name->mech_type is NULL then we get the default
 123 -          * mechanism; otherwise, we get the mechanism for the
 124 -          * mechanism-specific name.
 125 -          */
 126 -                 mech = __gss_get_mechanism(specific_mech_type);
 114                   if (mech == NULL)
 115                           return (GSS_S_BAD_MECH);
 129 |                 desired_mechs = &default_OID_set;
 116 | 
 117 +                 mechs = &default_OID_set;
 118                   default_OID_set.count = 1;
 119                   default_OID_set.elements = &default_OID;
 120                   default_OID.length = mech->mech_type.length;
 134 -             }
 135 - 
 136 -     /*
 137 -      * Now allocate the creds returned array. There is one element
 138 -      * for each member of the desired_mechs argument.
 139 -      */
 140 - 
 141 -     creds_returned = (struct creds_returned *)
 142 -         malloc(sizeof(struct creds_returned) * desired_mechs->count);
 143 -    
 144 -     /*                                                                
 145 -      * For each requested mechanism in desired_mechs, determine if it
 146 -      * is supported. If so, mark the corresponding element in
 147 -      * creds_returned->available as 1 and call the mechanism
 148 -      * specific gss_acquire_cred(), placing the returned cred in
 149 -      * creds_returned->cred. If not, mark creds_returned->available as
 150 -      * 0.
 151 -      */ 
 152 -     status = GSS_S_BAD_MECH;
 153 -     for (j=0; j < desired_mechs->count; j++) {
 154 -         creds_returned[j].available = 0;
 155 -  
 156 -         mech = __gss_get_mechanism (&desired_mechs->elements[j]);
 157 -         if (!mech || !mech->gss_acquire_cred)
 158 -             continue;
 159 -         /*
 160 -          * If this is a mechanism-specific name, then only use the
 161 -          * mechanism of the name.
 162 -          */
 163 -         if (specific_mech_type && !g_OID_equal(specific_mech_type,
 164 -                                                &mech->mech_type))
 165 -             continue;
 166 -         /*
 167 -          * If this is not a mechanism-specific name, then we need to
 168 -          * do an import the external name in union_name first.
 169 -          */
 170 -         if (union_name == 0)
 171 -             internal_name = (gss_name_t) 0;
 172 -         else if (!union_name->mech_type) {
 173 -             if (__gss_import_internal_name(&temp_minor_status,
 174 -                                            &mech->mech_type,
 175 -                                            union_name, &internal_name)) {
 176 -                 continue;
 177 -             }
 121                   default_OID.elements = mech->mech_type.elements;
 122           } else
 179 |             internal_name = union_name->mech_name;
 123 |                 mechs = desired_mechs;
 124   
 181 |         status = mech->gss_acquire_cred(mech->context, minor_status,
 182 |                                         internal_name, time_req,
 125 |         if (mechs->count == NULL)
 126 |                 return (GSS_S_BAD_MECH);
 183 -                                         desired_mechs, cred_usage,
 184 -                                         &creds_returned[j].cred,
 185 -                                         NULL, &temp_time_rec);
 127   
 187 |         /* Release the internal name, if allocated above */
 188 |         if (union_name && !union_name->mech_type) {
 189 |             (void) __gss_release_internal_name(&temp_minor_status,
 190 |                                                &mech->mech_type,
 128 |         /* allocate the output credential structure */
 129 |         creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
 130 |         if (creds == NULL)
 131 |                 return (GSS_S_FAILURE);
 191 -                                                &internal_name);
 192 -         }
 132   
 194 |         if (status != GSS_S_COMPLETE)
 195 |             continue;
 133 |         /* initialize to 0s */
 134 |         (void) memset(creds, 0, sizeof (gss_union_cred_desc));
 135   
 136 +         /* for each requested mech attempt to obtain a credential */
 137 +         for (i = 0; i < mechs->count; i++) {
 138 +                 major = gss_add_cred(minor_status, (gss_cred_id_t)creds,
 139 +                                 desired_name,
 140 +                                 &mechs->elements[i],
 141 +                                 cred_usage, time_req, time_req, NULL,
 142 +                                 NULL, &initTimeOut, &acceptTimeOut);
 143 +                 if (major == GSS_S_COMPLETE) {
 144 +                         /* update the credential's time */
 145 +                         if (cred_usage == GSS_C_ACCEPT) {
 146 +                                 if (outTime > acceptTimeOut)
 147 +                                         outTime = acceptTimeOut;
 148 +                         } else if (cred_usage == GSS_C_INITIATE) {
 149 +                                 if (outTime > initTimeOut)
 150 +                                         outTime = initTimeOut;
 151 +                         } else {
 152                                   /*
 198 |          * Add this into the creds_returned structure, if we got
 199 |          * a good credential for this mechanism.
 153 |                                  * time_rec is the lesser of the
 154 |                                  * init/accept times
 155                                    */
 201 |         if (time_rec) {
 202 |             *time_rec = *time_rec > temp_time_rec ? temp_time_rec : *time_rec;
 203 |             temp_time_rec = *time_rec;
 156 |                                 if (initTimeOut > acceptTimeOut)
 157 |                                         outTime = (outTime > acceptTimeOut) ?
 158 |                                                 acceptTimeOut : outTime;
 159 +                                 else
 160 +                                         outTime = (outTime > initTimeOut) ?
 161 +                                                 initTimeOut : outTime;
 205 -  
 206 -         creds_returned[j].available = 1;
 207 -         creds_acquired++;
 208 -  
 209 -         /*
 210 -          * If union_name is set, then we're done.  Continue, and
 211 -          * declare success.  Otherwise, if do an inquire credentials
 212 -          * from the first mechanism that succeeds and use that as the
 213 -          * union name.
 214 -          */
 215 -         if (union_name)
 216 -             continue;
 217 -  
 218 -         status = mech->gss_inquire_cred(mech->context, &temp_minor_status,
 219 -                                         creds_returned[j].cred,
 220 -                                         &internal_name, 0, 0, 0);
 221 -         if (status) {
 222 -             /* Should never happen */
 223 -             creds_returned[j].available = 0;
 224 -             creds_acquired--;
 225 -             if (mech->gss_release_cred)
 226 -                 mech->gss_release_cred(mech->context, minor_status,
 227 -                                        &creds_returned[j].cred);
 228 -             continue;
 162                           }
 163                   }
 164 +         } /* for */
 165   
 231 |         status = __gss_convert_name_to_union_name(&temp_minor_status, mech,
 232 |                                                   internal_name,
 233 |                                                   (gss_name_t *) &union_name);
 166 |         /* ensure that we have at least one credential element */
 167 |         if (creds->count < 1) {
 168 |                 free(creds);
 169 +                 return (major);
 170           }
 171   
 172           /*
 237 |      * Now allocate the creds struct, which will be cast as a gss_cred_id_t
 238 |      * and returned in the output_cred_handle argument. If there were
 173 |          * fill in output parameters
 174 |          * setup the actual mechs output parameter
 239 -      * no credentials found, return an error. Also, allocate the
 240 -      * actual_mechs data.
 242 -     if (creds_acquired == 0) {
 243 -         free (creds_returned);
 244 -         return (status);
 245 -     }
 246 - 
 247 -     creds = (gss_union_cred_t) malloc(sizeof(gss_union_cred_desc));
 248 -      
 249 -     creds->count = creds_acquired;                                  
 250 - 
 251 -     creds->mechs_array = (gss_OID) 
 252 -         malloc(sizeof(gss_OID_desc) * creds_acquired);
 253 -     
 254 -     creds->cred_array = (gss_cred_id_t *)
 255 -         malloc(sizeof(gss_cred_id_t) * creds_acquired);
 256 -     
 175            */
 176           if (actual_mechs != NULL) {
 258 |         *actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
 259 |  
 260 |         (*actual_mechs)->count = creds_acquired;
 261 |  
 262 |         (*actual_mechs)->elements = (gss_OID)
 263 |             malloc(sizeof(gss_OID_desc) * creds_acquired);
 177 |                 if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
 178 |                                         creds->count)) == NULL) {
 179 |                         (void) gss_release_cred(minor_status,
 180 |                                 (gss_cred_id_t *)&creds);
 181 |                         *minor_status = 0;
 182 |                         return (GSS_S_FAILURE);
 265 -        
 266 -     /*
 267 -      * copy the mechanisms found and their allocated credentials into the
 268 -      * creds structure. At the same time, build up the actual_mechs
 269 -      * data.
 270 -      */
 271 -     
 272 -     j = 0;
 273 -     
 274 -     for (i=0; i<desired_mechs->count; i++) {
 275 -         if(creds_returned[i].available) {
 276 -  
 277 -             creds->mechs_array[j].length =
 278 -                 desired_mechs->elements[i].length;
 279 -             creds->mechs_array[j].elements = (void *)
 280 -                 malloc(desired_mechs->elements[i].length);
 281 -             memcpy(creds->mechs_array[j].elements,
 282 -                    desired_mechs->elements[i].elements,
 283 -                    desired_mechs->elements[i].length);
 284 -             creds->cred_array[j] = creds_returned[i].cred;
 285 -             if (actual_mechs) {
 286 -                     (*actual_mechs)->elements[j].length =
 287 -                         desired_mechs->elements[i].length;
 288 -                     (*actual_mechs)->elements[j].elements = (void *)
 289 -                         malloc(desired_mechs->elements[i].length);
 290 -                     memcpy((*actual_mechs)->elements[j].elements,
 291 -                            desired_mechs->elements[i].elements,
 292 -                            desired_mechs->elements[i].length);
 183                   }
 294 -             j++;
 295 -         }    
 296 -     }
 184           }
 185   
 298 |     /* free the creds_returned struct, since we are done with it. */
 186 |         if (time_rec)
 187 +                 *time_rec = outTime;
 300 -     free(creds_returned);
 188   
 302 -     /* record the information needed for gss_inquire_cred() */
 303 -     
 304 -     creds->auxinfo.creation_time = time(0);                    
 305 -     creds->auxinfo.time_rec = temp_time_rec;
 306 -     creds->auxinfo.cred_usage =  cred_usage;
 307 -     
 308 -     /*                                       
 309 -      * we can't just record the internal name, desired_name, since
 310 -      * it may be destroyed between now and the time gss_inquire_cred()
 311 -      * is called.  So we must record the printable name in a
 312 -      * gss_buffer_t, calling gss_display_name() to fill it in. When
 313 -      * gss_inquire_name() is called, we must then call gss_import_name()
 314 -      * to get the internal name that is required at that point.
 315 -      */
 316 -     if (desired_name) {
 317 -         status = gss_display_name(&temp_minor_status, desired_name,
 318 -                                   &creds->auxinfo.name,
 319 -                                   &creds->auxinfo.name_type);
 320 -         if (status) {
 321 -             status = GSS_S_BAD_NAME;
 322 -             goto error_out;
 323 -         }
 324 -     } else {
 325 -         status = gss_display_name(&temp_minor_status, union_name,
 326 -                                   &creds->auxinfo.name,
 327 -                                   &creds->auxinfo.name_type);
 328 -         if (status) {
 329 -             status = GSS_S_BAD_NAME;
 330 -             goto error_out;
 331 -         }
 332 -     }
 333 - 
 189   
 190           *output_cred_handle = (gss_cred_id_t)creds;
 336 -  
 337 - error_out:
 338 -     for (k=0; k < creds->count; k++) {
 339 -         free(creds->mechs_array[k].elements);
 340 -         if (actual_mechs)
 341 -             free((*actual_mechs)->elements[k].elements);
 191           return (GSS_S_COMPLETE);
 192   }
 344 -     if (actual_mechs) {
 345 -         free((*actual_mechs)->elements);
 346 -         free(*actual_mechs);
 347 -         *actual_mechs = GSS_C_NULL_OID_SET;
 348 -     }
 349 -     free(creds->cred_array);
 350 -     free(creds->mechs_array);
 351 -     free(creds);
 352 - 
 353 -     return(status);
 354 - }
 355 - 
 193   
 194   /* V2 INTERFACE */
 195   OM_uint32
 196   gss_add_cred(minor_status, input_cred_handle,
 197                           desired_name, desired_mech, cred_usage,
 198                           initiator_time_req, acceptor_time_req,
 199                           output_cred_handle, actual_mechs,
 200                           initiator_time_rec, acceptor_time_rec)
 201           OM_uint32                *minor_status;
 202           const gss_cred_id_t        input_cred_handle;
 203           const gss_name_t        desired_name;
 204           const gss_OID                desired_mech;
 205           gss_cred_usage_t        cred_usage;
 206           OM_uint32                initiator_time_req;
 207           OM_uint32                acceptor_time_req;
 208           gss_cred_id_t                *output_cred_handle;
 209           gss_OID_set                *actual_mechs;
 210           OM_uint32                *initiator_time_rec;
 211           OM_uint32                *acceptor_time_rec;
 212   {
 213           OM_uint32                status, time_req, time_rec, temp_minor_status;
 214           gss_mechanism                 mech;
 215           gss_union_name_t        union_name = NULL;
 216           gss_union_cred_t        union_cred, new_union_cred;
 217           gss_name_t                internal_name = GSS_C_NO_NAME;
 218           gss_name_t                allocated_name = GSS_C_NO_NAME;
 219           gss_cred_id_t                cred = NULL;
 220           gss_OID                        new_mechs_array = NULL;
 221           gss_cred_id_t                *new_cred_array = NULL;
 222   
 385 |         if (input_cred_handle == GSS_C_NO_CREDENTIAL)
 386 |                 return (GSS_S_NO_CRED);
 223 |         /* check input parameters */
 224 |         if (minor_status == NULL)
 225 +                 return (GSS_S_CALL_INACCESSIBLE_WRITE);
 226 +         *minor_status = 0;
 227   
 388 |         union_cred = (gss_union_cred_t) input_cred_handle;
 228 |         if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
 229 +                 output_cred_handle == NULL)
 230 +                 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
 231   
 232 +         if (output_cred_handle)
 233 +                 *output_cred_handle = GSS_C_NO_CREDENTIAL;
 234 + 
 235 +         if (actual_mechs)
 236 +                 *actual_mechs = NULL;
 237 + 
 238 +         if (acceptor_time_rec)
 239 +                 *acceptor_time_rec = 0;
 240 + 
 241 +         if (initiator_time_rec)
 242 +                 *initiator_time_rec = 0;
 243 + 
 244           mech = __gss_get_mechanism(desired_mech);
 245           if (!mech)
 246                   return (GSS_S_BAD_MECH);
 247 +         else if (!mech->gss_acquire_cred)
 248 +                 return (GSS_S_UNAVAILABLE);
 249   
 250 +         if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
 251 +                 union_cred = malloc(sizeof (gss_union_cred_desc));
 252 +                 if (union_cred == NULL)
 253 +                         return (GSS_S_FAILURE);
 254 + 
 255 +                 (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
 256 + 
 257 +                 /* for default credentials we will use GSS_C_NO_NAME */
 258 +                 internal_name = GSS_C_NO_NAME;
 259 +         } else {
 260 +                 union_cred = (gss_union_cred_t)input_cred_handle;
 261                   if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
 262                           GSS_C_NO_CREDENTIAL)
 396 |         return GSS_S_DUPLICATE_ELEMENT;
 263 |                         return (GSS_S_DUPLICATE_ELEMENT);
 264   
 265 +                 /* may need to create a mechanism specific name */
 266 +                 if (desired_name) {
 267                           union_name = (gss_union_name_t)desired_name;
 399 |     if (union_name->mech_type) {
 400 |         if (!g_OID_equal(desired_mech, union_name->mech_type))
 401 |             return GSS_S_BAD_NAMETYPE;
 268 |                         if (union_name->mech_type &&
 269 |                                 g_OID_equal(union_name->mech_type,
 270 |                                                 &mech->mech_type))
 271                                   internal_name = union_name->mech_name;
 403 |     } else {
 404 |         if (__gss_import_internal_name(minor_status, desired_mech,
 405 |                                        union_name, &internal_name))
 272 |                         else {
 273 |                                 if (__gss_import_internal_name(minor_status,
 274 |                                         &mech->mech_type, union_name,
 275 +                                         &allocated_name) != GSS_S_COMPLETE)
 276                                           return (GSS_S_BAD_NAME);
 277 +                                 internal_name = allocated_name;
 278                           }
 279 +                 }
 280 +         }
 281   
 282 + 
 283           if (cred_usage == GSS_C_ACCEPT)
 284                   time_req = acceptor_time_req;
 285           else if (cred_usage == GSS_C_INITIATE)
 286                   time_req = initiator_time_req;
 287           else if (cred_usage == GSS_C_BOTH)
 288                   time_req = (acceptor_time_req > initiator_time_req) ?
 289                           acceptor_time_req : initiator_time_req;
 290   
 291           status = mech->gss_acquire_cred(mech->context, minor_status,
 292                                   internal_name, time_req,
 293                                   GSS_C_NULL_OID_SET, cred_usage,
 294                                   &cred, NULL, &time_rec);
 295 + 
 296           if (status != GSS_S_COMPLETE)
 297                   goto errout;
 298   
 299 +         /* may need to set credential auxinfo strucutre */
 300 +         if (union_cred->auxinfo.creation_time == 0) {
 301 +                 union_cred->auxinfo.creation_time = time(NULL);
 302 +                 union_cred->auxinfo.time_rec = time_rec;
 303 +                 union_cred->auxinfo.cred_usage = cred_usage;
 304 + 
 305 +                 /*
 306 +                  * we must set the name; if name is not supplied
 307 +                  * we must do inquire cred to get it
 308 +                  */
 309 +                 if (internal_name == NULL) {
 310 +                         if (mech->gss_inquire_cred == NULL ||
 311 +                                 ((status = mech->gss_inquire_cred(
 312 +                                                 mech->context,
 313 +                                                 &temp_minor_status, cred,
 314 +                                                 &allocated_name, NULL, NULL,
 315 +                                                 NULL)) != GSS_S_COMPLETE))
 316 +                                 goto errout;
 317 +                         internal_name = allocated_name;
 318 +                 }
 319 + 
 320 +                 if ((status = mech->gss_display_name(mech->context,
 321 +                                 &temp_minor_status, internal_name,
 322 +                                 &union_cred->auxinfo.name,
 323 +                                 &union_cred->auxinfo.name_type)) !=
 324 +                         GSS_S_COMPLETE)
 325 +                         goto errout;
 326 +         }
 327 + 
 328 +         /* now add the new credential elements */
 329           new_mechs_array = (gss_OID)
 330                   malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
 331   
 332           new_cred_array = (gss_cred_id_t *)
 333                   malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
 334   
 431 -         *minor_status = ENOMEM;
 335           if (!new_mechs_array || !new_cred_array) {
 336                   status = GSS_S_FAILURE;
 337                   goto errout;
 338           }
 436 -  
 339   
 340           if (acceptor_time_rec)
 341                   if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
 342                           *acceptor_time_rec = time_rec;
 343           if (initiator_time_rec)
 344                   if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
 345                           *initiator_time_rec = time_rec;
 346   
 347           /*
 445 |      * OK, expand the mechanism array in the union credentials
 348 |          * OK, expand the mechanism array and the credential array
 446 -      * (Look for the union label...)
 349            */
 448 |     memcpy(new_mechs_array, union_cred->mechs_array,
 350 |         (void) memcpy(new_mechs_array, union_cred->mechs_array,
 351                   sizeof (gss_OID_desc) * union_cred->count);
 450 |     memcpy(new_cred_array, union_cred->cred_array,
 352 |         (void) memcpy(new_cred_array, union_cred->cred_array,
 353                   sizeof (gss_cred_id_t) * union_cred->count);
 354   
 355           new_cred_array[union_cred->count] = cred;
 454 |     new_mechs_array[union_cred->count].length = desired_mech->length;
 455 |     new_mechs_array[union_cred->count].elements = malloc(desired_mech->length);
 356 |         if ((new_mechs_array[union_cred->count].elements =
 357 |                         malloc(mech->mech_type.length)) == NULL)
 456 -     if (!new_mechs_array[union_cred->count].elements) {
 457 -         *minor_status = ENOMEM;
 358                   goto errout;
 359 + 
 360 +         g_OID_copy(&new_mechs_array[union_cred->count],
 361 +                         &mech->mech_type);
 362 + 
 363 +         if (actual_mechs) {
 364 +                 *actual_mechs = create_actual_mechs(new_mechs_array,
 365 +                                         union_cred->count + 1);
 366 +                 if (*actual_mechs == NULL) {
 367 +                         free(new_mechs_array[union_cred->count].elements);
 368 +                         goto errout;
 369                   }
 460 |     memcpy(new_mechs_array[union_cred->count].elements, desired_mech->elements,
 370 |         }
 461 -            desired_mech->length);
 371   
 372           if (output_cred_handle == NULL) {
 373                   free(union_cred->mechs_array);
 374                   free(union_cred->cred_array);
 375                   new_union_cred = union_cred;
 376           } else {
 377                   new_union_cred = malloc(sizeof (gss_union_cred_desc));
 378                   if (new_union_cred == NULL) {
 470 |             *minor_status = ENOMEM;
 379 |                         free(new_mechs_array[union_cred->count].elements);
 380                           goto errout;
 381                   }
 382                   *new_union_cred = *union_cred;
 474 |         *output_cred_handle = new_union_cred;
 383 |                 *output_cred_handle = (gss_cred_id_t)new_union_cred;
 384           }
 385 + 
 386           new_union_cred->mechs_array = new_mechs_array;
 387           new_union_cred->cred_array = new_cred_array;
 479 -     new_mechs_array = 0;
 480 -     new_cred_array = 0;
 388           new_union_cred->count++;
 389   
 482 |     if (actual_mechs)
 390 |         /* We're done with the internal name. Free it if we allocated it. */
 483 -         *actual_mechs = create_actual_mechs(new_union_cred);
 391   
 485 |     status = GSS_S_COMPLETE;                                 
 392 |         if (allocated_name)
 393 +                 (void) __gss_release_internal_name(&temp_minor_status,
 394 +                                         &mech->mech_type,
 395 +                                         &allocated_name);
 396   
 397 +         return (GSS_S_COMPLETE);
 398 + 
 399   errout:
 400           if (new_mechs_array)
 401                   free(new_mechs_array);
 402           if (new_cred_array)
 403                   free(new_cred_array);
 492 |     if (!union_name->mech_type) {
 404 | 
 405 +         if (cred != NULL && mech->gss_release_cred)
 406 +                 mech->gss_release_cred(mech->context,
 407 +                                 &temp_minor_status, &cred);
 408 + 
 409 +         if (allocated_name)
 410                   (void) __gss_release_internal_name(&temp_minor_status,
 494 |                                            desired_mech, &internal_name);
 411 |                                         &mech->mech_type,
 412 +                                         &allocated_name);
 413 + 
 414 +         if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
 415 +                 if (union_cred->auxinfo.name.value)
 416 +                         free(union_cred->auxinfo.name.value);
 417 +                 free(union_cred);
 418           }
 419   
 420           return (status);
 421   }

 ----Unchanged portion omitted----