import less(1)
[unleashed/tickless.git] / usr / src / lib / gss_mechs / mech_krb5 / mech / acquire_cred.c
blobce3b63427d23b4013e3e2e07b2e9f284c0fac0a5
1 /*
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Copyright 2000 by the Massachusetts Institute of Technology.
6 * All Rights Reserved.
8 * Export of this software from the United States of America may
9 * require a specific license from the United States Government.
10 * It is the responsibility of any person or organization contemplating
11 * export to obtain such a license before exporting.
13 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14 * distribute this software and its documentation for any purpose and
15 * without fee is hereby granted, provided that the above copyright
16 * notice appear in all copies and that both that copyright notice and
17 * this permission notice appear in supporting documentation, and that
18 * the name of M.I.T. not be used in advertising or publicity pertaining
19 * to distribution of the software without specific, written prior
20 * permission. Furthermore if you modify this software you must label
21 * your software as modified software and not distribute it in such a
22 * fashion that it might be confused with the original M.I.T. software.
23 * M.I.T. makes no representations about the suitability of
24 * this software for any purpose. It is provided "as is" without express
25 * or implied warranty.
29 * Copyright 1993 by OpenVision Technologies, Inc.
31 * Permission to use, copy, modify, distribute, and sell this software
32 * and its documentation for any purpose is hereby granted without fee,
33 * provided that the above copyright notice appears in all copies and
34 * that both that copyright notice and this permission notice appear in
35 * supporting documentation, and that the name of OpenVision not be used
36 * in advertising or publicity pertaining to distribution of the software
37 * without specific, written prior permission. OpenVision makes no
38 * representations about the suitability of this software for any
39 * purpose. It is provided "as is" without express or implied warranty.
41 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
42 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
43 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
44 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
45 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
46 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
47 * PERFORMANCE OF THIS SOFTWARE.
51 * Copyright (C) 1998 by the FundsXpress, INC.
53 * All rights reserved.
55 * Export of this software from the United States of America may require
56 * a specific license from the United States Government. It is the
57 * responsibility of any person or organization contemplating export to
58 * obtain such a license before exporting.
60 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
61 * distribute this software and its documentation for any purpose and
62 * without fee is hereby granted, provided that the above copyright
63 * notice appear in all copies and that both that copyright notice and
64 * this permission notice appear in supporting documentation, and that
65 * the name of FundsXpress. not be used in advertising or publicity pertaining
66 * to distribution of the software without specific, written prior
67 * permission. FundsXpress makes no representations about the suitability of
68 * this software for any purpose. It is provided "as is" without express
69 * or implied warranty.
71 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
72 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
73 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
76 #include "k5-int.h"
77 #include "gss_libinit.h"
78 #include "gssapiP_krb5.h"
79 #include "mglueP.h"
80 #ifdef HAVE_STRING_H
81 #include <string.h>
82 #else
83 #include <strings.h>
84 #endif
85 #include <syslog.h>
86 #include <locale.h> /* Solaris Kerberos */
87 #include "file/ktfile.h" /* Solaris Kerberos */
89 #if defined(USE_LOGIN_LIBRARY)
90 #include <Kerberos/KerberosLoginPrivate.h>
91 #elif defined(USE_LEASH)
92 #ifdef _WIN64
93 #define LEASH_DLL "leashw64.dll"
94 #else
95 #define LEASH_DLL "leashw32.dll"
96 #endif
97 static void (*pLeash_AcquireInitialTicketsIfNeeded)(krb5_context,krb5_principal,char*,int) = NULL;
98 static HANDLE hLeashDLL = INVALID_HANDLE_VALUE;
99 #endif
101 k5_mutex_t gssint_krb5_keytab_lock = K5_MUTEX_PARTIAL_INITIALIZER;
102 static char *krb5_gss_keytab = NULL;
104 /* Heimdal calls this gsskrb5_register_acceptor_identity. */
105 OM_uint32 KRB5_CALLCONV
106 krb5_gss_register_acceptor_identity(const char *keytab)
108 size_t len;
109 char *new, *old;
110 int err;
112 err = gssint_initialize_library();
113 if (err != 0)
114 return GSS_S_FAILURE;
116 if (keytab == NULL)
117 return GSS_S_FAILURE;
119 len = strlen(keytab);
120 new = malloc(len + 1);
121 if (new == NULL)
122 return GSS_S_FAILURE;
123 strcpy(new, keytab);
125 err = k5_mutex_lock(&gssint_krb5_keytab_lock);
126 if (err) {
127 free(new);
128 return GSS_S_FAILURE;
130 old = krb5_gss_keytab;
131 krb5_gss_keytab = new;
132 k5_mutex_unlock(&gssint_krb5_keytab_lock);
133 free(old);
134 return GSS_S_COMPLETE;
137 /* get credentials corresponding to a key in the krb5 keytab.
138 If the default name is requested, return the name in output_princ.
139 If output_princ is non-NULL, the caller will use or free it, regardless
140 of the return value.
141 If successful, set the keytab-specific fields in cred
144 static OM_uint32
145 acquire_accept_cred(context, minor_status, desired_name, output_princ, cred)
146 krb5_context context;
147 OM_uint32 *minor_status;
148 gss_name_t desired_name;
149 krb5_principal *output_princ;
150 krb5_gss_cred_id_rec *cred;
152 krb5_error_code code;
153 krb5_principal princ;
154 krb5_keytab kt;
155 krb5_keytab_entry entry;
157 *output_princ = NULL;
158 cred->keytab = NULL;
160 /* open the default keytab */
162 code = gssint_initialize_library();
163 if (code != 0) {
164 *minor_status = code;
165 return GSS_S_FAILURE;
167 code = k5_mutex_lock(&gssint_krb5_keytab_lock);
168 if (code) {
169 *minor_status = code;
170 return GSS_S_FAILURE;
172 if (krb5_gss_keytab != NULL) {
173 code = krb5_kt_resolve(context, krb5_gss_keytab, &kt);
174 k5_mutex_unlock(&gssint_krb5_keytab_lock);
175 } else {
176 k5_mutex_unlock(&gssint_krb5_keytab_lock);
177 code = krb5_kt_default(context, &kt);
180 if (code) {
181 *minor_status = code;
182 /* Solaris Kerb NOTE: GSS_S_CRED_UNAVAIL is not RFC 2743 compliant */
183 return(GSS_S_NO_CRED);
186 if (desired_name != GSS_C_NO_NAME) {
187 princ = (krb5_principal) desired_name;
188 if ((code = krb5_kt_get_entry(context, kt, princ, 0, 0, &entry))) {
189 if (code == KRB5_KT_NOTFOUND) {
190 char *s_name;
191 if (krb5_unparse_name(context, princ, &s_name) == 0) {
192 krb5_set_error_message(context, KG_KEYTAB_NOMATCH,
193 dgettext(TEXT_DOMAIN,
194 "No principal in keytab ('%s') matches desired name %s"),
195 KTFILENAME(kt),
196 s_name);
197 krb5_free_unparsed_name(context, s_name);
199 *minor_status = KG_KEYTAB_NOMATCH;
200 } else
201 *minor_status = code;
202 /* Solaris Kerb NOTE: GSS_S_CRED_UNAVAIL is not RFC 2743 compliant */
203 (void) krb5_kt_close(context, kt);
204 return(GSS_S_NO_CRED);
206 krb5_kt_free_entry(context, &entry);
208 /* Open the replay cache for this principal. */
209 if ((code = krb5_get_server_rcache(context,
210 krb5_princ_component(context, princ, 0),
211 &cred->rcache))) {
212 *minor_status = code;
213 return(GSS_S_FAILURE);
218 /* hooray. we made it */
220 cred->keytab = kt;
222 return(GSS_S_COMPLETE);
225 /* get credentials corresponding to the default credential cache.
226 If the default name is requested, return the name in output_princ.
227 If output_princ is non-NULL, the caller will use or free it, regardless
228 of the return value.
229 If successful, set the ccache-specific fields in cred.
232 static OM_uint32
233 acquire_init_cred(context, minor_status, desired_name, output_princ, cred)
234 krb5_context context;
235 OM_uint32 *minor_status;
236 gss_name_t desired_name;
237 krb5_principal *output_princ;
238 krb5_gss_cred_id_rec *cred;
240 krb5_error_code code;
241 krb5_ccache ccache;
242 krb5_principal princ, tmp_princ;
243 krb5_flags flags;
244 krb5_cc_cursor cur;
245 krb5_creds creds;
246 int got_endtime;
247 int caller_provided_ccache_name = 0;
249 cred->ccache = NULL;
251 /* load the GSS ccache name into the kg_context */
253 if (GSS_ERROR(kg_sync_ccache_name(context, minor_status)))
254 return(GSS_S_FAILURE);
256 /* check to see if the caller provided a ccache name if so
257 * we will just use that and not search the cache collection */
258 if (GSS_ERROR(kg_caller_provided_ccache_name (minor_status, &caller_provided_ccache_name))) {
259 return(GSS_S_FAILURE);
262 #if defined(USE_LOGIN_LIBRARY) || defined(USE_LEASH)
263 if (desired_name && !caller_provided_ccache_name) {
264 #if defined(USE_LOGIN_LIBRARY)
265 KLStatus err = klNoErr;
266 char *ccache_name = NULL;
267 KLPrincipal kl_desired_princ = NULL;
269 err = __KLCreatePrincipalFromKerberos5Principal ((krb5_principal) desired_name,
270 &kl_desired_princ);
272 if (!err) {
273 err = KLAcquireInitialTickets (kl_desired_princ, NULL, NULL, &ccache_name);
276 if (!err) {
277 err = krb5_cc_resolve (context, ccache_name, &ccache);
280 if (err) {
281 *minor_status = err;
282 return(GSS_S_CRED_UNAVAIL);
285 if (kl_desired_princ != NULL) { KLDisposePrincipal (kl_desired_princ); }
286 if (ccache_name != NULL) { KLDisposeString (ccache_name); }
288 #elif defined(USE_LEASH)
289 if ( hLeashDLL == INVALID_HANDLE_VALUE ) {
290 hLeashDLL = LoadLibrary(LEASH_DLL);
291 if ( hLeashDLL != INVALID_HANDLE_VALUE ) {
292 (FARPROC) pLeash_AcquireInitialTicketsIfNeeded =
293 GetProcAddress(hLeashDLL, "not_an_API_Leash_AcquireInitialTicketsIfNeeded");
297 if ( pLeash_AcquireInitialTicketsIfNeeded ) {
298 char ccname[256]="";
299 pLeash_AcquireInitialTicketsIfNeeded(context, (krb5_principal) desired_name, ccname, sizeof(ccname));
300 if (!ccname[0]) {
301 *minor_status = KRB5_CC_NOTFOUND;
302 return(GSS_S_NO_CRED);
305 if ((code = krb5_cc_resolve (context, ccname, &ccache))) {
306 *minor_status = code;
307 return(GSS_S_NO_CRED);
309 } else {
310 /* leash dll not available, open the default credential cache */
312 if ((code = krb5int_cc_default(context, &ccache))) {
313 *minor_status = code;
314 return(GSS_S_NO_CRED);
317 #endif /* USE_LEASH */
318 } else
319 #endif /* USE_LOGIN_LIBRARY || USE_LEASH */
321 /* open the default credential cache */
323 if ((code = krb5int_cc_default(context, &ccache))) {
324 *minor_status = code;
325 return(GSS_S_NO_CRED);
329 /* turn off OPENCLOSE mode while extensive frobbing is going on */
331 * SUNW14resync
332 * Added calls to krb5_cc_set_flags(... KRB5_TC_OPENCLOSE)
333 * on the error returns cuz the 1.4 krb5_cc_close does not always close
334 * the file like it used to and caused STC test gss.27 to fail.
336 flags = 0; /* turns off OPENCLOSE mode */
337 if ((code = krb5_cc_set_flags(context, ccache, flags))) {
338 (void)krb5_cc_close(context, ccache);
339 *minor_status = code;
340 return(GSS_S_NO_CRED);
343 /* get out the principal name and see if it matches */
345 if ((code = krb5_cc_get_principal(context, ccache, &princ))) {
346 /* Solaris Kerberos */
347 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
348 (void)krb5_cc_close(context, ccache);
349 *minor_status = code;
350 return(GSS_S_FAILURE);
353 if (desired_name != (gss_name_t) NULL) {
354 if (! krb5_principal_compare(context, princ, (krb5_principal) desired_name)) {
355 (void)krb5_free_principal(context, princ);
356 /* Solaris Kerberos */
357 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
358 (void)krb5_cc_close(context, ccache);
359 *minor_status = KG_CCACHE_NOMATCH;
360 return(GSS_S_NO_CRED);
362 (void)krb5_free_principal(context, princ);
363 princ = (krb5_principal) desired_name;
364 } else {
365 *output_princ = princ;
368 /* iterate over the ccache, find the tgt */
370 if ((code = krb5_cc_start_seq_get(context, ccache, &cur))) {
371 /* Solaris Kerberos */
372 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
373 (void)krb5_cc_close(context, ccache);
374 *minor_status = code;
375 return(GSS_S_FAILURE);
378 /* this is hairy. If there's a tgt for the principal's local realm
379 in here, that's what we want for the expire time. But if
380 there's not, then we want to use the first key. */
382 got_endtime = 0;
384 code = krb5_build_principal_ext(context, &tmp_princ,
385 krb5_princ_realm(context, princ)->length,
386 krb5_princ_realm(context, princ)->data,
387 6, "krbtgt",
388 krb5_princ_realm(context, princ)->length,
389 krb5_princ_realm(context, princ)->data,
391 if (code) {
392 /* Solaris Kerberos */
393 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
394 (void)krb5_cc_close(context, ccache);
395 *minor_status = code;
396 return(GSS_S_FAILURE);
398 while (!(code = krb5_cc_next_cred(context, ccache, &cur, &creds))) {
399 if (krb5_principal_compare(context, tmp_princ, creds.server)) {
400 cred->tgt_expire = creds.times.endtime;
401 got_endtime = 1;
402 *minor_status = 0;
403 code = 0;
404 krb5_free_cred_contents(context, &creds);
405 break;
407 if (got_endtime == 0) {
408 cred->tgt_expire = creds.times.endtime;
409 got_endtime = 1;
411 krb5_free_cred_contents(context, &creds);
413 krb5_free_principal(context, tmp_princ);
415 if (code && code != KRB5_CC_END) {
416 /* this means some error occurred reading the ccache */
417 (void)krb5_cc_end_seq_get(context, ccache, &cur);
418 /* Solaris Kerberos */
419 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
420 (void)krb5_cc_close(context, ccache);
421 *minor_status = code;
422 return(GSS_S_FAILURE);
423 } else if (! got_endtime) {
424 /* this means the ccache was entirely empty */
425 (void)krb5_cc_end_seq_get(context, ccache, &cur);
426 /* Solaris Kerberos */
427 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
428 (void)krb5_cc_close(context, ccache);
429 *minor_status = KG_EMPTY_CCACHE;
430 return(GSS_S_FAILURE);
431 } else {
432 /* this means that we found an endtime to use. */
433 if ((code = krb5_cc_end_seq_get(context, ccache, &cur))) {
434 /* Solaris Kerberos */
435 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
436 (void)krb5_cc_close(context, ccache);
437 *minor_status = code;
438 return(GSS_S_FAILURE);
440 flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */
441 if ((code = krb5_cc_set_flags(context, ccache, flags))) {
442 (void)krb5_cc_close(context, ccache);
443 *minor_status = code;
444 return(GSS_S_FAILURE);
448 /* the credentials match and are valid */
450 cred->ccache = ccache;
451 /* minor_status is set while we are iterating over the ccache */
452 return(GSS_S_COMPLETE);
455 /*ARGSUSED*/
456 OM_uint32
457 krb5_gss_acquire_cred(minor_status, desired_name, time_req,
458 desired_mechs, cred_usage, output_cred_handle,
459 actual_mechs, time_rec)
460 OM_uint32 *minor_status;
461 gss_name_t desired_name;
462 OM_uint32 time_req;
463 gss_OID_set desired_mechs;
464 gss_cred_usage_t cred_usage;
465 gss_cred_id_t *output_cred_handle;
466 gss_OID_set *actual_mechs;
467 OM_uint32 *time_rec;
469 krb5_context context;
470 size_t i;
471 krb5_gss_cred_id_t cred;
472 gss_OID_set ret_mechs;
473 int req_old, req_new;
474 OM_uint32 ret;
475 krb5_error_code code;
477 code = gssint_initialize_library();
478 if (code) {
479 *minor_status = code;
480 return GSS_S_FAILURE;
483 code = krb5_gss_init_context(&context);
484 if (code) {
485 *minor_status = code;
486 return GSS_S_FAILURE;
489 /* make sure all outputs are valid */
491 *output_cred_handle = NULL;
492 if (actual_mechs)
493 *actual_mechs = NULL;
494 if (time_rec)
495 *time_rec = 0;
497 /* validate the name */
499 /*SUPPRESS 29*/
500 if ((desired_name != (gss_name_t) NULL) &&
501 (! kg_validate_name(desired_name))) {
502 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
503 krb5_free_context(context);
504 return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
507 /* verify that the requested mechanism set is the default, or
508 contains krb5 */
510 if (desired_mechs == GSS_C_NULL_OID_SET) {
511 req_old = 1;
512 req_new = 1;
513 } else {
514 req_old = 0;
515 req_new = 0;
517 for (i=0; i<desired_mechs->count; i++) {
518 if (g_OID_equal(gss_mech_krb5_old, &(desired_mechs->elements[i])))
519 req_old++;
520 if (g_OID_equal(gss_mech_krb5, &(desired_mechs->elements[i])))
521 req_new++;
524 if (!req_old && !req_new) {
525 *minor_status = 0;
526 krb5_free_context(context);
527 return(GSS_S_BAD_MECH);
531 /* create the gss cred structure */
533 if ((cred =
534 (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec))) == NULL) {
535 *minor_status = ENOMEM;
536 krb5_free_context(context);
537 return(GSS_S_FAILURE);
539 memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
541 cred->usage = cred_usage;
542 cred->princ = NULL;
543 cred->prerfc_mech = req_old;
544 cred->rfc_mech = req_new;
546 cred->keytab = NULL;
547 cred->ccache = NULL;
549 code = k5_mutex_init(&cred->lock);
550 if (code) {
551 *minor_status = code;
552 krb5_free_context(context);
553 return GSS_S_FAILURE;
555 /* Note that we don't need to lock this GSSAPI credential record
556 here, because no other thread can gain access to it until we
557 return it. */
559 if ((cred_usage != GSS_C_INITIATE) &&
560 (cred_usage != GSS_C_ACCEPT) &&
561 (cred_usage != GSS_C_BOTH)) {
562 k5_mutex_destroy(&cred->lock);
563 xfree(cred);
564 *minor_status = (OM_uint32) G_BAD_USAGE;
565 krb5_free_context(context);
566 return(GSS_S_FAILURE);
569 /* if requested, acquire credentials for accepting */
570 /* this will fill in cred->princ if the desired_name is not specified */
572 if ((cred_usage == GSS_C_ACCEPT) ||
573 (cred_usage == GSS_C_BOTH))
574 if ((ret = acquire_accept_cred(context, minor_status, desired_name,
575 &(cred->princ), cred))
576 != GSS_S_COMPLETE) {
577 if (cred->princ)
578 krb5_free_principal(context, cred->princ);
579 k5_mutex_destroy(&cred->lock);
580 xfree(cred);
581 /* minor_status set by acquire_accept_cred() */
582 save_error_info(*minor_status, context);
583 krb5_free_context(context);
584 return(ret);
587 /* if requested, acquire credentials for initiation */
588 /* this will fill in cred->princ if it wasn't set above, and
589 the desired_name is not specified */
591 if ((cred_usage == GSS_C_INITIATE) ||
592 (cred_usage == GSS_C_BOTH))
593 if ((ret =
594 acquire_init_cred(context, minor_status,
595 cred->princ?(gss_name_t)cred->princ:desired_name,
596 &(cred->princ), cred))
597 != GSS_S_COMPLETE) {
598 if (cred->keytab)
599 krb5_kt_close(context, cred->keytab);
600 if (cred->princ)
601 krb5_free_principal(context, cred->princ);
602 k5_mutex_destroy(&cred->lock);
603 xfree(cred);
604 /* minor_status set by acquire_init_cred() */
605 save_error_info(*minor_status, context);
606 krb5_free_context(context);
607 return(ret);
610 /* Solaris Kerberos:
611 * if the princ wasn't filled in already, fill it in now unless
612 * a cred with no associated princ is requested (will invoke default
613 * behaviour when gss_accept_init_context() is called).
614 * Note MIT 1.4 has GSS_C_NO_CREDENTIAL instead of GSS_C_NO_NAME
616 if (!cred->princ && (desired_name != GSS_C_NO_NAME))
617 if ((code = krb5_copy_principal(context, (krb5_principal) desired_name,
618 &(cred->princ)))) {
619 if (cred->ccache)
620 (void)krb5_cc_close(context, cred->ccache);
621 if (cred->keytab)
622 (void)krb5_kt_close(context, cred->keytab);
623 k5_mutex_destroy(&cred->lock);
624 xfree(cred);
625 *minor_status = code;
626 save_error_info(*minor_status, context);
627 krb5_free_context(context);
628 return(GSS_S_FAILURE);
631 /*** at this point, the cred structure has been completely created */
633 /* compute time_rec */
635 if (cred_usage == GSS_C_ACCEPT) {
636 if (time_rec)
637 *time_rec = GSS_C_INDEFINITE;
638 } else {
639 krb5_timestamp now;
641 if ((code = krb5_timeofday(context, &now))) {
642 if (cred->ccache)
643 (void)krb5_cc_close(context, cred->ccache);
644 if (cred->keytab)
645 (void)krb5_kt_close(context, cred->keytab);
646 if (cred->princ)
647 krb5_free_principal(context, cred->princ);
648 k5_mutex_destroy(&cred->lock);
649 xfree(cred);
650 *minor_status = code;
651 save_error_info(*minor_status, context);
652 krb5_free_context(context);
653 return(GSS_S_FAILURE);
656 if (time_rec)
657 *time_rec = (cred->tgt_expire > now) ? (cred->tgt_expire - now) : 0;
660 /* create mechs */
662 if (actual_mechs) {
663 if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status,
664 &ret_mechs)) ||
665 (cred->prerfc_mech &&
666 GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
667 (const gss_OID) gss_mech_krb5_old,
668 &ret_mechs))) ||
669 (cred->rfc_mech &&
670 GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
671 (const gss_OID) gss_mech_krb5,
672 &ret_mechs)))) {
673 if (cred->ccache)
674 (void)krb5_cc_close(context, cred->ccache);
675 if (cred->keytab)
676 (void)krb5_kt_close(context, cred->keytab);
677 if (cred->princ)
678 krb5_free_principal(context, cred->princ);
679 k5_mutex_destroy(&cred->lock);
680 xfree(cred);
681 /* *minor_status set above */
682 krb5_free_context(context);
683 return(ret);
687 /* intern the credential handle */
689 if (! kg_save_cred_id((gss_cred_id_t) cred)) {
690 free(ret_mechs->elements);
691 free(ret_mechs);
692 if (cred->ccache)
693 (void)krb5_cc_close(context, cred->ccache);
694 if (cred->keytab)
695 (void)krb5_kt_close(context, cred->keytab);
696 if (cred->princ)
697 krb5_free_principal(context, cred->princ);
698 k5_mutex_destroy(&cred->lock);
699 xfree(cred);
700 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
701 save_error_string(*minor_status, "error saving credentials");
702 krb5_free_context(context);
703 return(GSS_S_FAILURE);
706 /* return success */
708 *minor_status = 0;
709 *output_cred_handle = (gss_cred_id_t) cred;
710 if (actual_mechs)
711 *actual_mechs = ret_mechs;
713 krb5_free_context(context);
714 return(GSS_S_COMPLETE);