Sdiff g_acquire_cred.c
  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" 
  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; 

 26 {
 27         gss_OID_set     actual_mechs;
 28         int             i;

 29 
 30         actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc));
 31         if (!actual_mechs)
 32                 return (NULL);
 33 
 34         actual_mechs->elements = (gss_OID)
 35                 malloc(sizeof (gss_OID_desc) * creds->count); 
 36         if (!actual_mechs->elements) {
 37                 free(actual_mechs);
 38                 return (NULL);
 39         }
 40 
 41         actual_mechs->count = 0;
 42 
 43         for (i = 0; i < creds->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); 
 51         }



 52 
 53         return (actual_mechs);
 54 }
 55 
 56 
 57 OM_uint32
 58 gss_acquire_cred(minor_status,
 59                         desired_name,
 60                         time_req,
 61                         desired_mechs,
 62                         cred_usage,
 63                         output_cred_handle,
 64                         actual_mechs,
 65                         time_rec)
 66 
 67 OM_uint32 *             minor_status;
 68 const gss_name_t        desired_name;
 69 OM_uint32               time_req;
 70 const gss_OID_set       desired_mechs;
 71 int                     cred_usage;
 72 gss_cred_id_t           *output_cred_handle;
 73 gss_OID_set *           actual_mechs;
 74 OM_uint32 *             time_rec;
 75 
 76 {
 77     OM_uint32           status, temp_minor_status, temp_time_rec = ~0; 
 78     unsigned int        i, j, creds_acquired = 0; 
 79     int                 k; 
 80     gss_union_name_t    union_name; 
 81     gss_name_t          internal_name; 
 82     gss_union_cred_t    creds; 
 83     gss_OID_set_desc    default_OID_set;

 84     gss_OID_desc        default_OID;
 85     gss_OID             specific_mech_type = 0; 
 86     gss_mechanism       mech;


 87 
 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. 
 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      */          
 96 
 97     struct creds_returned { 
 98         unsigned char   available; 
 99         gss_cred_id_t   cred; 
100     } *creds_returned; 
101 
102         gss_initialize(); 
103 
104         /* Set this to NULL for now */ 
105  
106         if (actual_mechs)
107                 *actual_mechs = GSS_C_NULL_OID_SET;
108 
109         if (minor_status) 
110                 *minor_status = 0; 
111 
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  
116         /*
117          * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
118          * appropriate default. 


119          */
120         if (desired_mechs == GSS_C_NULL_OID_SET) {
121          /* 
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); 
127                 if (mech == NULL)
128                         return (GSS_S_BAD_MECH);
129                 desired_mechs = &default_OID_set; 

130                 default_OID_set.count = 1 ;
131                 default_OID_set.elements = &default_OID;
132                 default_OID.length = mech->mech_type.length;
133                 default_OID.elements = mech->mech_type.elements;
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             } 
178         } else 
179             internal_name = union_name->mech_name; 
180  
181         status = mech->gss_acquire_cred(mech->context, minor_status, 
182                                         internal_name, time_req, 
183                                         desired_mechs, cred_usage, 
184                                         &creds_returned[j].cred, 
185                                         NULL, &temp_time_rec); 
186 
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, 
191                                                &internal_name); 
192         } 
193  
194         if (status != GSS_S_COMPLETE) 
195             continue; 
196  
















197         /*
198          * Add this into the creds_returned structure, if we got 
199          * a good credential for this mechanism. 
200          */
201         if (time_rec) { 
202             *time_rec = *time_rec > temp_time_rec ? temp_time_rec : *time_rec; 
203             temp_time_rec = *time_rec; 



204         }
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; 
229         }      

230  
231         status = __gss_convert_name_to_union_name(&temp_minor_status, mech, 
232                                                   internal_name, 
233                                                   (gss_name_t *) &union_name); 

234     }
235 
236     /*
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 
239      * no credentials found, return an error. Also, allocate the 
240      * actual_mechs data. 
241      */
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      
257     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); 
264     }
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); 
293             }
294             j++; 
295         }     
296     } 
297     
298     /* free the creds_returned struct, since we are done with it. */ 

299      
300     free(creds_returned); 
301     
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  
334     *output_cred_handle = (gss_cred_id_t) creds;
335     return(GSS_S_COMPLETE);
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); 
342     }
343 
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  
356 /* V2 INTERFACE */
357 OM_uint32
358 gss_add_cred(minor_status, input_cred_handle,
359                         desired_name, desired_mech, cred_usage,
360                         initiator_time_req, acceptor_time_req,
361                         output_cred_handle, actual_mechs,
362                         initiator_time_rec, acceptor_time_rec)
363         OM_uint32               *minor_status;
364         const gss_cred_id_t     input_cred_handle;
365         const gss_name_t        desired_name;
366         const gss_OID           desired_mech;
367         gss_cred_usage_t        cred_usage;
368         OM_uint32               initiator_time_req;
369         OM_uint32               acceptor_time_req;
370         gss_cred_id_t           *output_cred_handle;
371         gss_OID_set             *actual_mechs;
372         OM_uint32               *initiator_time_rec;
373         OM_uint32               *acceptor_time_rec;
374 {
375         OM_uint32               status, time_req, time_rec, temp_minor_status;
376         gss_mechanism           mech;
377         gss_union_name_t        union_name = NULL;
378         gss_union_cred_t        union_cred, new_union_cred;
379         gss_name_t              internal_name = GSS_C_NO_NAME;
380         gss_name_t              allocated_name = GSS_C_NO_NAME;
381         gss_cred_id_t           cred = NULL;
382         gss_OID                 new_mechs_array = NULL;
383         gss_cred_id_t           *new_cred_array = NULL;
384 
385         if (input_cred_handle == GSS_C_NO_CREDENTIAL) 
386                 return (GSS_S_NO_CRED); 


387 
388         union_cred = (gss_union_cred_t) input_cred_handle; 


389 












390         mech = __gss_get_mechanism(desired_mech);
391         if (!mech)
392                 return (GSS_S_BAD_MECH);


393 











394     if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
395         GSS_C_NO_CREDENTIAL)
396         return GSS_S_DUPLICATE_ELEMENT; 
397  


398     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; 
402         internal_name = union_name->mech_name;
403     } else { 
404         if (__gss_import_internal_name(minor_status, desired_mech, 
405                                        union_name, &internal_name)) 

406             return (GSS_S_BAD_NAME);

407     }


408      

409     if (cred_usage == GSS_C_ACCEPT)
410         time_req = acceptor_time_req;
411     else if (cred_usage == GSS_C_INITIATE)
412         time_req = initiator_time_req;
413     else if (cred_usage == GSS_C_BOTH)
414         time_req = (acceptor_time_req > initiator_time_req) ?
415             acceptor_time_req : initiator_time_req;
416  
417     status = mech->gss_acquire_cred(mech->context, minor_status,
418                                     internal_name, time_req,
419                                     GSS_C_NULL_OID_SET, cred_usage,
420                                     &cred, NULL, &time_rec);

421     if (status != GSS_S_COMPLETE)
422         goto errout;
423  






























424     new_mechs_array = (gss_OID)
425         malloc(sizeof(gss_OID_desc) * (union_cred->count+1));
426 
427     new_cred_array = (gss_cred_id_t *)                        
428         malloc(sizeof(gss_cred_id_t) * (union_cred->count+1));
429 
430     if (!new_mechs_array || !new_cred_array) {
431         *minor_status = ENOMEM; 
432         status = GSS_S_FAILURE;
433         goto errout;
434     }
435  
436   
437     if (acceptor_time_rec)
438         if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
439             *acceptor_time_rec = time_rec;
440     if (initiator_time_rec)
441         if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
442             *initiator_time_rec = time_rec;
443  
444     /*
445      * OK, expand the mechanism array in the union credentials 
446      * (Look for the union label...) 
447      */
448     memcpy(new_mechs_array, union_cred->mechs_array, 
449            sizeof(gss_OID_desc) * union_cred->count);
450     memcpy(new_cred_array, union_cred->cred_array, 
451            sizeof(gss_cred_id_t) * union_cred->count);
452      
453     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); 
456     if (!new_mechs_array[union_cred->count].elements) { 
457         *minor_status = ENOMEM; 
458         goto errout;










459     }
460     memcpy(new_mechs_array[union_cred->count].elements, desired_mech->elements, 
461            desired_mech->length); 
462  
463     if (output_cred_handle == NULL) {
464         free(union_cred->mechs_array);
465         free(union_cred->cred_array);
466         new_union_cred = union_cred;
467     } else {
468         new_union_cred = malloc(sizeof(gss_union_cred_desc));
469         if (new_union_cred == NULL) {
470             *minor_status = ENOMEM; 
471             goto errout;
472         }
473         *new_union_cred = *union_cred;
474         *output_cred_handle = new_union_cred; 
475     }

476     new_union_cred->mechs_array = new_mechs_array;
477     new_union_cred->cred_array = new_cred_array;
478     new_union_cred->count++;
479     new_mechs_array = 0; 
480     new_cred_array = 0; 
481  
482     if (actual_mechs) 
483         *actual_mechs = create_actual_mechs(new_union_cred); 
484 
485     status = GSS_S_COMPLETE;                                  



486 


487 errout:                      
488     if (new_mechs_array)
489         free(new_mechs_array);
490     if (new_cred_array)
491         free(new_cred_array);
492     if (!union_name->mech_type) { 





493         (void) __gss_release_internal_name(&temp_minor_status,
494                                            desired_mech, &internal_name); 






495     }
496             
497     return(status);
498 }
  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.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(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)
 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 
 45         for (i = 0; i < count; i++) { 


 46                 actual_mechs->elements[i].elements = (void *)
 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 {
 80         OM_uint32 major = GSS_S_FAILURE; 
 81         OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE; 




 82         gss_OID_set_desc default_OID_set;
 83         gss_OID_set mechs;
 84         gss_OID_desc default_OID;

 85         gss_mechanism mech;
 86         int i;
 87         gss_union_cred_t creds;
 88 
 89         /* start by checking parameters */ 
 90         if (!minor_status) 
 91                 return (GSS_S_CALL_INACCESSIBLE_WRITE); 
 92         *minor_status = 0; 




 93 
 94         if (!output_cred_handle) 
 95                 return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED); 


 96 
 97         *output_cred_handle = GSS_C_NO_CREDENTIAL; 
 98 
 99         /* Set output parameters to NULL for now */ 

100         if (actual_mechs)
101                 *actual_mechs = GSS_C_NULL_OID_SET;
102 
103         if (time_rec) 
104                 *time_rec = 0; 
105 




106         /*
107          * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
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) {
113                 mech = __gss_get_mechanism(NULL); 





114                 if (mech == NULL)
115                         return (GSS_S_BAD_MECH);
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;
121                 default_OID.elements = mech->mech_type.elements;












































122         } else
123                 mechs = desired_mechs; 
124 
125         if (mechs->count == NULL) 
126                 return (GSS_S_BAD_MECH); 



127 
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); 


132 
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                                 /*
153                                  * time_rec is the lesser of the 
154                                  * init/accept times 
155                                  */
156                                 if (initTimeOut > acceptTimeOut) 
157                                         outTime = (outTime > acceptTimeOut) ? 
158                                                 acceptTimeOut : outTime; 
159                                 else 
160                                         outTime = (outTime > initTimeOut) ? 
161                                                 initTimeOut : outTime; 
162                         }
























163                 }
164         } /* for */
165 
166         /* ensure that we have at least one credential element */ 
167         if (creds->count < 1) { 
168                 free(creds); 
169                 return (major); 
170         }
171 
172         /*
173          * fill in output parameters 
174          * setup the actual mechs output parameter 


175          */















176         if (actual_mechs != NULL) {
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); 
183                 }




























184         }



185 
186         if (time_rec) 
187                 *time_rec = outTime; 
188 

189 
































190         *output_cred_handle = (gss_cred_id_t)creds;
191         return (GSS_S_COMPLETE);






192 }
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 
223         /* check input parameters */ 
224         if (minor_status == NULL) 
225                 return (GSS_S_CALL_INACCESSIBLE_WRITE); 
226         *minor_status = 0; 
227 
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)
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;
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;
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 
335         if (!new_mechs_array || !new_cred_array) {

336                 status = GSS_S_FAILURE;
337                 goto errout;
338         }
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         /*
348          * OK, expand the mechanism array and the credential array 

349          */
350         (void) memcpy(new_mechs_array, union_cred->mechs_array, 
351                 sizeof (gss_OID_desc) * union_cred->count);
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;
356         if ((new_mechs_array[union_cred->count].elements = 
357                         malloc(mech->mech_type.length)) == NULL) 


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                 }
370         } 

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) {
379                         free(new_mechs_array[union_cred->count].elements); 
380                         goto errout;
381                 }
382                 *new_union_cred = *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;
388         new_union_cred->count++;


389 
390         /* We're done with the internal name. Free it if we allocated it. */ 

391 
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);
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,
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 }