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.
7 *
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.
12 *
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.
26 *
27 */
28 /*
29 * Copyright 1993 by OpenVision Technologies, Inc.
30 *
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.
40 *
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.
48 */
49
50 /*
51 * Copyright (C) 1998 by the FundsXpress, INC.
52 *
53 * All rights reserved.
54 *
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.
59 *
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.
70 *
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.
74 */
75
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 */
88
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
100
101 k5_mutex_t gssint_krb5_keytab_lock = K5_MUTEX_PARTIAL_INITIALIZER;
102 static char *krb5_gss_keytab = NULL;
103
104 /* Heimdal calls this gsskrb5_register_acceptor_identity. */
105 OM_uint32 KRB5_CALLCONV
krb5_gss_register_acceptor_identity(const char * keytab)106 krb5_gss_register_acceptor_identity(const char *keytab)
107 {
108 size_t len;
109 char *new, *old;
110 int err;
111
112 err = gssint_initialize_library();
113 if (err != 0)
114 return GSS_S_FAILURE;
115
116 if (keytab == NULL)
117 return GSS_S_FAILURE;
118
119 len = strlen(keytab);
120 new = malloc(len + 1);
121 if (new == NULL)
122 return GSS_S_FAILURE;
123 strcpy(new, keytab);
124
125 err = k5_mutex_lock(&gssint_krb5_keytab_lock);
126 if (err) {
127 free(new);
128 return GSS_S_FAILURE;
129 }
130 old = krb5_gss_keytab;
131 krb5_gss_keytab = new;
132 k5_mutex_unlock(&gssint_krb5_keytab_lock);
133 if (old != NULL)
134 free(old);
135 return GSS_S_COMPLETE;
136 }
137
138 /* get credentials corresponding to a key in the krb5 keytab.
139 If the default name is requested, return the name in output_princ.
140 If output_princ is non-NULL, the caller will use or free it, regardless
141 of the return value.
142 If successful, set the keytab-specific fields in cred
143 */
144
145 static OM_uint32
acquire_accept_cred(context,minor_status,desired_name,output_princ,cred)146 acquire_accept_cred(context, minor_status, desired_name, output_princ, cred)
147 krb5_context context;
148 OM_uint32 *minor_status;
149 gss_name_t desired_name;
150 krb5_principal *output_princ;
151 krb5_gss_cred_id_rec *cred;
152 {
153 krb5_error_code code;
154 krb5_principal princ;
155 krb5_keytab kt;
156 krb5_keytab_entry entry;
157
158 *output_princ = NULL;
159 cred->keytab = NULL;
160
161 /* open the default keytab */
162
163 code = gssint_initialize_library();
164 if (code != 0) {
165 *minor_status = code;
166 return GSS_S_FAILURE;
167 }
168 code = k5_mutex_lock(&gssint_krb5_keytab_lock);
169 if (code) {
170 *minor_status = code;
171 return GSS_S_FAILURE;
172 }
173 if (krb5_gss_keytab != NULL) {
174 code = krb5_kt_resolve(context, krb5_gss_keytab, &kt);
175 k5_mutex_unlock(&gssint_krb5_keytab_lock);
176 } else {
177 k5_mutex_unlock(&gssint_krb5_keytab_lock);
178 code = krb5_kt_default(context, &kt);
179 }
180
181 if (code) {
182 *minor_status = code;
183 /* Solaris Kerb NOTE: GSS_S_CRED_UNAVAIL is not RFC 2743 compliant */
184 return(GSS_S_NO_CRED);
185 }
186
187 if (desired_name != GSS_C_NO_NAME) {
188 princ = (krb5_principal) desired_name;
189 if ((code = krb5_kt_get_entry(context, kt, princ, 0, 0, &entry))) {
190 if (code == KRB5_KT_NOTFOUND) {
191 char *s_name;
192 if (krb5_unparse_name(context, princ, &s_name) == 0) {
193 krb5_set_error_message(context, KG_KEYTAB_NOMATCH,
194 dgettext(TEXT_DOMAIN,
195 "No principal in keytab ('%s') matches desired name %s"),
196 KTFILENAME(kt),
197 s_name);
198 krb5_free_unparsed_name(context, s_name);
199 }
200 *minor_status = KG_KEYTAB_NOMATCH;
201 } else
202 *minor_status = code;
203 /* Solaris Kerb NOTE: GSS_S_CRED_UNAVAIL is not RFC 2743 compliant */
204 (void) krb5_kt_close(context, kt);
205 return(GSS_S_NO_CRED);
206 }
207 krb5_kt_free_entry(context, &entry);
208
209 /* Open the replay cache for this principal. */
210 if ((code = krb5_get_server_rcache(context,
211 krb5_princ_component(context, princ, 0),
212 &cred->rcache))) {
213 *minor_status = code;
214 return(GSS_S_FAILURE);
215 }
216
217 }
218
219 /* hooray. we made it */
220
221 cred->keytab = kt;
222
223 return(GSS_S_COMPLETE);
224 }
225
226 /* get credentials corresponding to the default credential cache.
227 If the default name is requested, return the name in output_princ.
228 If output_princ is non-NULL, the caller will use or free it, regardless
229 of the return value.
230 If successful, set the ccache-specific fields in cred.
231 */
232
233 static OM_uint32
acquire_init_cred(context,minor_status,desired_name,output_princ,cred)234 acquire_init_cred(context, minor_status, desired_name, output_princ, cred)
235 krb5_context context;
236 OM_uint32 *minor_status;
237 gss_name_t desired_name;
238 krb5_principal *output_princ;
239 krb5_gss_cred_id_rec *cred;
240 {
241 krb5_error_code code;
242 krb5_ccache ccache;
243 krb5_principal princ, tmp_princ;
244 krb5_flags flags;
245 krb5_cc_cursor cur;
246 krb5_creds creds;
247 int got_endtime;
248 int caller_provided_ccache_name = 0;
249
250 cred->ccache = NULL;
251
252 /* load the GSS ccache name into the kg_context */
253
254 if (GSS_ERROR(kg_sync_ccache_name(context, minor_status)))
255 return(GSS_S_FAILURE);
256
257 /* check to see if the caller provided a ccache name if so
258 * we will just use that and not search the cache collection */
259 if (GSS_ERROR(kg_caller_provided_ccache_name (minor_status, &caller_provided_ccache_name))) {
260 return(GSS_S_FAILURE);
261 }
262
263 #if defined(USE_LOGIN_LIBRARY) || defined(USE_LEASH)
264 if (desired_name && !caller_provided_ccache_name) {
265 #if defined(USE_LOGIN_LIBRARY)
266 KLStatus err = klNoErr;
267 char *ccache_name = NULL;
268 KLPrincipal kl_desired_princ = NULL;
269
270 err = __KLCreatePrincipalFromKerberos5Principal ((krb5_principal) desired_name,
271 &kl_desired_princ);
272
273 if (!err) {
274 err = KLAcquireInitialTickets (kl_desired_princ, NULL, NULL, &ccache_name);
275 }
276
277 if (!err) {
278 err = krb5_cc_resolve (context, ccache_name, &ccache);
279 }
280
281 if (err) {
282 *minor_status = err;
283 return(GSS_S_CRED_UNAVAIL);
284 }
285
286 if (kl_desired_princ != NULL) { KLDisposePrincipal (kl_desired_princ); }
287 if (ccache_name != NULL) { KLDisposeString (ccache_name); }
288
289 #elif defined(USE_LEASH)
290 if ( hLeashDLL == INVALID_HANDLE_VALUE ) {
291 hLeashDLL = LoadLibrary(LEASH_DLL);
292 if ( hLeashDLL != INVALID_HANDLE_VALUE ) {
293 (FARPROC) pLeash_AcquireInitialTicketsIfNeeded =
294 GetProcAddress(hLeashDLL, "not_an_API_Leash_AcquireInitialTicketsIfNeeded");
295 }
296 }
297
298 if ( pLeash_AcquireInitialTicketsIfNeeded ) {
299 char ccname[256]="";
300 pLeash_AcquireInitialTicketsIfNeeded(context, (krb5_principal) desired_name, ccname, sizeof(ccname));
301 if (!ccname[0]) {
302 *minor_status = KRB5_CC_NOTFOUND;
303 return(GSS_S_NO_CRED);
304 }
305
306 if ((code = krb5_cc_resolve (context, ccname, &ccache))) {
307 *minor_status = code;
308 return(GSS_S_NO_CRED);
309 }
310 } else {
311 /* leash dll not available, open the default credential cache */
312
313 if ((code = krb5int_cc_default(context, &ccache))) {
314 *minor_status = code;
315 return(GSS_S_NO_CRED);
316 }
317 }
318 #endif /* USE_LEASH */
319 } else
320 #endif /* USE_LOGIN_LIBRARY || USE_LEASH */
321 {
322 /* open the default credential cache */
323
324 if ((code = krb5int_cc_default(context, &ccache))) {
325 *minor_status = code;
326 return(GSS_S_NO_CRED);
327 }
328 }
329
330 /* turn off OPENCLOSE mode while extensive frobbing is going on */
331 /*
332 * SUNW14resync
333 * Added calls to krb5_cc_set_flags(... KRB5_TC_OPENCLOSE)
334 * on the error returns cuz the 1.4 krb5_cc_close does not always close
335 * the file like it used to and caused STC test gss.27 to fail.
336 */
337 flags = 0; /* turns off OPENCLOSE mode */
338 if ((code = krb5_cc_set_flags(context, ccache, flags))) {
339 (void)krb5_cc_close(context, ccache);
340 *minor_status = code;
341 return(GSS_S_NO_CRED);
342 }
343
344 /* get out the principal name and see if it matches */
345
346 if ((code = krb5_cc_get_principal(context, ccache, &princ))) {
347 /* Solaris Kerberos */
348 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
349 (void)krb5_cc_close(context, ccache);
350 *minor_status = code;
351 return(GSS_S_FAILURE);
352 }
353
354 if (desired_name != (gss_name_t) NULL) {
355 if (! krb5_principal_compare(context, princ, (krb5_principal) desired_name)) {
356 (void)krb5_free_principal(context, princ);
357 /* Solaris Kerberos */
358 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
359 (void)krb5_cc_close(context, ccache);
360 *minor_status = KG_CCACHE_NOMATCH;
361 return(GSS_S_NO_CRED);
362 }
363 (void)krb5_free_principal(context, princ);
364 princ = (krb5_principal) desired_name;
365 } else {
366 *output_princ = princ;
367 }
368
369 /* iterate over the ccache, find the tgt */
370
371 if ((code = krb5_cc_start_seq_get(context, ccache, &cur))) {
372 /* Solaris Kerberos */
373 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
374 (void)krb5_cc_close(context, ccache);
375 *minor_status = code;
376 return(GSS_S_FAILURE);
377 }
378
379 /* this is hairy. If there's a tgt for the principal's local realm
380 in here, that's what we want for the expire time. But if
381 there's not, then we want to use the first key. */
382
383 got_endtime = 0;
384
385 code = krb5_build_principal_ext(context, &tmp_princ,
386 krb5_princ_realm(context, princ)->length,
387 krb5_princ_realm(context, princ)->data,
388 6, "krbtgt",
389 krb5_princ_realm(context, princ)->length,
390 krb5_princ_realm(context, princ)->data,
391 0);
392 if (code) {
393 /* Solaris Kerberos */
394 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
395 (void)krb5_cc_close(context, ccache);
396 *minor_status = code;
397 return(GSS_S_FAILURE);
398 }
399 while (!(code = krb5_cc_next_cred(context, ccache, &cur, &creds))) {
400 if (krb5_principal_compare(context, tmp_princ, creds.server)) {
401 cred->tgt_expire = creds.times.endtime;
402 got_endtime = 1;
403 *minor_status = 0;
404 code = 0;
405 krb5_free_cred_contents(context, &creds);
406 break;
407 }
408 if (got_endtime == 0) {
409 cred->tgt_expire = creds.times.endtime;
410 got_endtime = 1;
411 }
412 krb5_free_cred_contents(context, &creds);
413 }
414 krb5_free_principal(context, tmp_princ);
415
416 if (code && code != KRB5_CC_END) {
417 /* this means some error occurred reading the ccache */
418 (void)krb5_cc_end_seq_get(context, ccache, &cur);
419 /* Solaris Kerberos */
420 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
421 (void)krb5_cc_close(context, ccache);
422 *minor_status = code;
423 return(GSS_S_FAILURE);
424 } else if (! got_endtime) {
425 /* this means the ccache was entirely empty */
426 (void)krb5_cc_end_seq_get(context, ccache, &cur);
427 /* Solaris Kerberos */
428 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
429 (void)krb5_cc_close(context, ccache);
430 *minor_status = KG_EMPTY_CCACHE;
431 return(GSS_S_FAILURE);
432 } else {
433 /* this means that we found an endtime to use. */
434 if ((code = krb5_cc_end_seq_get(context, ccache, &cur))) {
435 /* Solaris Kerberos */
436 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
437 (void)krb5_cc_close(context, ccache);
438 *minor_status = code;
439 return(GSS_S_FAILURE);
440 }
441 flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */
442 if ((code = krb5_cc_set_flags(context, ccache, flags))) {
443 (void)krb5_cc_close(context, ccache);
444 *minor_status = code;
445 return(GSS_S_FAILURE);
446 }
447 }
448
449 /* the credentials match and are valid */
450
451 cred->ccache = ccache;
452 /* minor_status is set while we are iterating over the ccache */
453 return(GSS_S_COMPLETE);
454 }
455
456 /*ARGSUSED*/
457 OM_uint32
krb5_gss_acquire_cred(minor_status,desired_name,time_req,desired_mechs,cred_usage,output_cred_handle,actual_mechs,time_rec)458 krb5_gss_acquire_cred(minor_status, desired_name, time_req,
459 desired_mechs, cred_usage, output_cred_handle,
460 actual_mechs, time_rec)
461 OM_uint32 *minor_status;
462 gss_name_t desired_name;
463 OM_uint32 time_req;
464 gss_OID_set desired_mechs;
465 gss_cred_usage_t cred_usage;
466 gss_cred_id_t *output_cred_handle;
467 gss_OID_set *actual_mechs;
468 OM_uint32 *time_rec;
469 {
470 krb5_context context;
471 size_t i;
472 krb5_gss_cred_id_t cred;
473 gss_OID_set ret_mechs;
474 int req_old, req_new;
475 OM_uint32 ret;
476 krb5_error_code code;
477
478 code = gssint_initialize_library();
479 if (code) {
480 *minor_status = code;
481 return GSS_S_FAILURE;
482 }
483
484 code = krb5_gss_init_context(&context);
485 if (code) {
486 *minor_status = code;
487 return GSS_S_FAILURE;
488 }
489
490 /* make sure all outputs are valid */
491
492 *output_cred_handle = NULL;
493 if (actual_mechs)
494 *actual_mechs = NULL;
495 if (time_rec)
496 *time_rec = 0;
497
498 /* validate the name */
499
500 /*SUPPRESS 29*/
501 if ((desired_name != (gss_name_t) NULL) &&
502 (! kg_validate_name(desired_name))) {
503 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
504 krb5_free_context(context);
505 return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
506 }
507
508 /* verify that the requested mechanism set is the default, or
509 contains krb5 */
510
511 if (desired_mechs == GSS_C_NULL_OID_SET) {
512 req_old = 1;
513 req_new = 1;
514 } else {
515 req_old = 0;
516 req_new = 0;
517
518 for (i=0; i<desired_mechs->count; i++) {
519 if (g_OID_equal(gss_mech_krb5_old, &(desired_mechs->elements[i])))
520 req_old++;
521 if (g_OID_equal(gss_mech_krb5, &(desired_mechs->elements[i])))
522 req_new++;
523 }
524
525 if (!req_old && !req_new) {
526 *minor_status = 0;
527 krb5_free_context(context);
528 return(GSS_S_BAD_MECH);
529 }
530 }
531
532 /* create the gss cred structure */
533
534 if ((cred =
535 (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec))) == NULL) {
536 *minor_status = ENOMEM;
537 krb5_free_context(context);
538 return(GSS_S_FAILURE);
539 }
540 memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
541
542 cred->usage = cred_usage;
543 cred->princ = NULL;
544 cred->prerfc_mech = req_old;
545 cred->rfc_mech = req_new;
546
547 cred->keytab = NULL;
548 cred->ccache = NULL;
549
550 code = k5_mutex_init(&cred->lock);
551 if (code) {
552 *minor_status = code;
553 krb5_free_context(context);
554 return GSS_S_FAILURE;
555 }
556 /* Note that we don't need to lock this GSSAPI credential record
557 here, because no other thread can gain access to it until we
558 return it. */
559
560 if ((cred_usage != GSS_C_INITIATE) &&
561 (cred_usage != GSS_C_ACCEPT) &&
562 (cred_usage != GSS_C_BOTH)) {
563 k5_mutex_destroy(&cred->lock);
564 xfree(cred);
565 *minor_status = (OM_uint32) G_BAD_USAGE;
566 krb5_free_context(context);
567 return(GSS_S_FAILURE);
568 }
569
570 /* if requested, acquire credentials for accepting */
571 /* this will fill in cred->princ if the desired_name is not specified */
572
573 if ((cred_usage == GSS_C_ACCEPT) ||
574 (cred_usage == GSS_C_BOTH))
575 if ((ret = acquire_accept_cred(context, minor_status, desired_name,
576 &(cred->princ), cred))
577 != GSS_S_COMPLETE) {
578 if (cred->princ)
579 krb5_free_principal(context, cred->princ);
580 k5_mutex_destroy(&cred->lock);
581 xfree(cred);
582 /* minor_status set by acquire_accept_cred() */
583 save_error_info(*minor_status, context);
584 krb5_free_context(context);
585 return(ret);
586 }
587
588 /* if requested, acquire credentials for initiation */
589 /* this will fill in cred->princ if it wasn't set above, and
590 the desired_name is not specified */
591
592 if ((cred_usage == GSS_C_INITIATE) ||
593 (cred_usage == GSS_C_BOTH))
594 if ((ret =
595 acquire_init_cred(context, minor_status,
596 cred->princ?(gss_name_t)cred->princ:desired_name,
597 &(cred->princ), cred))
598 != GSS_S_COMPLETE) {
599 if (cred->keytab)
600 krb5_kt_close(context, cred->keytab);
601 if (cred->princ)
602 krb5_free_principal(context, cred->princ);
603 k5_mutex_destroy(&cred->lock);
604 xfree(cred);
605 /* minor_status set by acquire_init_cred() */
606 save_error_info(*minor_status, context);
607 krb5_free_context(context);
608 return(ret);
609 }
610
611 /* Solaris Kerberos:
612 * if the princ wasn't filled in already, fill it in now unless
613 * a cred with no associated princ is requested (will invoke default
614 * behaviour when gss_accept_init_context() is called).
615 * Note MIT 1.4 has GSS_C_NO_CREDENTIAL instead of GSS_C_NO_NAME
616 */
617 if (!cred->princ && (desired_name != GSS_C_NO_NAME))
618 if ((code = krb5_copy_principal(context, (krb5_principal) desired_name,
619 &(cred->princ)))) {
620 if (cred->ccache)
621 (void)krb5_cc_close(context, cred->ccache);
622 if (cred->keytab)
623 (void)krb5_kt_close(context, cred->keytab);
624 k5_mutex_destroy(&cred->lock);
625 xfree(cred);
626 *minor_status = code;
627 save_error_info(*minor_status, context);
628 krb5_free_context(context);
629 return(GSS_S_FAILURE);
630 }
631
632 /*** at this point, the cred structure has been completely created */
633
634 /* compute time_rec */
635
636 if (cred_usage == GSS_C_ACCEPT) {
637 if (time_rec)
638 *time_rec = GSS_C_INDEFINITE;
639 } else {
640 krb5_timestamp now;
641
642 if ((code = krb5_timeofday(context, &now))) {
643 if (cred->ccache)
644 (void)krb5_cc_close(context, cred->ccache);
645 if (cred->keytab)
646 (void)krb5_kt_close(context, cred->keytab);
647 if (cred->princ)
648 krb5_free_principal(context, cred->princ);
649 k5_mutex_destroy(&cred->lock);
650 xfree(cred);
651 *minor_status = code;
652 save_error_info(*minor_status, context);
653 krb5_free_context(context);
654 return(GSS_S_FAILURE);
655 }
656
657 if (time_rec)
658 *time_rec = (cred->tgt_expire > now) ? (cred->tgt_expire - now) : 0;
659 }
660
661 /* create mechs */
662
663 if (actual_mechs) {
664 if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status,
665 &ret_mechs)) ||
666 (cred->prerfc_mech &&
667 GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
668 (const gss_OID) gss_mech_krb5_old,
669 &ret_mechs))) ||
670 (cred->rfc_mech &&
671 GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
672 (const gss_OID) gss_mech_krb5,
673 &ret_mechs)))) {
674 if (cred->ccache)
675 (void)krb5_cc_close(context, cred->ccache);
676 if (cred->keytab)
677 (void)krb5_kt_close(context, cred->keytab);
678 if (cred->princ)
679 krb5_free_principal(context, cred->princ);
680 k5_mutex_destroy(&cred->lock);
681 xfree(cred);
682 /* *minor_status set above */
683 krb5_free_context(context);
684 return(ret);
685 }
686 }
687
688 /* intern the credential handle */
689
690 if (! kg_save_cred_id((gss_cred_id_t) cred)) {
691 free(ret_mechs->elements);
692 free(ret_mechs);
693 if (cred->ccache)
694 (void)krb5_cc_close(context, cred->ccache);
695 if (cred->keytab)
696 (void)krb5_kt_close(context, cred->keytab);
697 if (cred->princ)
698 krb5_free_principal(context, cred->princ);
699 k5_mutex_destroy(&cred->lock);
700 xfree(cred);
701 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
702 save_error_string(*minor_status, "error saving credentials");
703 krb5_free_context(context);
704 return(GSS_S_FAILURE);
705 }
706
707 /* return success */
708
709 *minor_status = 0;
710 *output_cred_handle = (gss_cred_id_t) cred;
711 if (actual_mechs)
712 *actual_mechs = ret_mechs;
713
714 krb5_free_context(context);
715 return(GSS_S_COMPLETE);
716 }
717