17c478bd9Sstevel@tonic-gate /*
25e01956fSGlenn Barry  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
37c478bd9Sstevel@tonic-gate  */
47c478bd9Sstevel@tonic-gate /*
57c478bd9Sstevel@tonic-gate  * Copyright 2000 by the Massachusetts Institute of Technology.
67c478bd9Sstevel@tonic-gate  * All Rights Reserved.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
97c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
107c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
117c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
12*55fea89dSDan Cross  *
137c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
147c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
157c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
167c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
177c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
187c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
197c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
207c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
217c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
227c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
237c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
247c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
257c478bd9Sstevel@tonic-gate  * or implied warranty.
26*55fea89dSDan Cross  *
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Copyright 1993 by OpenVision Technologies, Inc.
30*55fea89dSDan Cross  *
317c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, distribute, and sell this software
327c478bd9Sstevel@tonic-gate  * and its documentation for any purpose is hereby granted without fee,
337c478bd9Sstevel@tonic-gate  * provided that the above copyright notice appears in all copies and
347c478bd9Sstevel@tonic-gate  * that both that copyright notice and this permission notice appear in
357c478bd9Sstevel@tonic-gate  * supporting documentation, and that the name of OpenVision not be used
367c478bd9Sstevel@tonic-gate  * in advertising or publicity pertaining to distribution of the software
377c478bd9Sstevel@tonic-gate  * without specific, written prior permission. OpenVision makes no
387c478bd9Sstevel@tonic-gate  * representations about the suitability of this software for any
397c478bd9Sstevel@tonic-gate  * purpose.  It is provided "as is" without express or implied warranty.
40*55fea89dSDan Cross  *
417c478bd9Sstevel@tonic-gate  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
427c478bd9Sstevel@tonic-gate  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
437c478bd9Sstevel@tonic-gate  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
447c478bd9Sstevel@tonic-gate  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
457c478bd9Sstevel@tonic-gate  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
467c478bd9Sstevel@tonic-gate  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
477c478bd9Sstevel@tonic-gate  * PERFORMANCE OF THIS SOFTWARE.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
52*55fea89dSDan Cross  *
537c478bd9Sstevel@tonic-gate  * All rights reserved.
54*55fea89dSDan Cross  *
557c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may require
567c478bd9Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
577c478bd9Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
587c478bd9Sstevel@tonic-gate  * obtain such a license before exporting.
59*55fea89dSDan Cross  *
607c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
617c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
627c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
637c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
647c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
657c478bd9Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
667c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
677c478bd9Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
687c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
697c478bd9Sstevel@tonic-gate  * or implied warranty.
70*55fea89dSDan Cross  *
717c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
727c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
737c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
747c478bd9Sstevel@tonic-gate  */
757c478bd9Sstevel@tonic-gate 
76ab9b2e15Sgtb #include "k5-int.h"
77ab9b2e15Sgtb #include "gss_libinit.h"
78ab9b2e15Sgtb #include "gssapiP_krb5.h"
79ab9b2e15Sgtb #include "mglueP.h"
807c478bd9Sstevel@tonic-gate #ifdef HAVE_STRING_H
817c478bd9Sstevel@tonic-gate #include <string.h>
827c478bd9Sstevel@tonic-gate #else
837c478bd9Sstevel@tonic-gate #include <strings.h>
847c478bd9Sstevel@tonic-gate #endif
855e01956fSGlenn Barry #include <syslog.h>
865e01956fSGlenn Barry #include <locale.h> /* Solaris Kerberos */
875e01956fSGlenn Barry #include "file/ktfile.h" /* Solaris Kerberos */
887c478bd9Sstevel@tonic-gate 
89ab9b2e15Sgtb #if defined(USE_LOGIN_LIBRARY)
90ab9b2e15Sgtb #include <Kerberos/KerberosLoginPrivate.h>
91ab9b2e15Sgtb #elif defined(USE_LEASH)
92159d09a2SMark Phalan #ifdef _WIN64
93159d09a2SMark Phalan #define LEASH_DLL "leashw64.dll"
94159d09a2SMark Phalan #else
95159d09a2SMark Phalan #define LEASH_DLL "leashw32.dll"
96159d09a2SMark Phalan #endif
97ab9b2e15Sgtb static void (*pLeash_AcquireInitialTicketsIfNeeded)(krb5_context,krb5_principal,char*,int) = NULL;
98ab9b2e15Sgtb static HANDLE hLeashDLL = INVALID_HANDLE_VALUE;
99ab9b2e15Sgtb #endif
100ab9b2e15Sgtb 
101ab9b2e15Sgtb k5_mutex_t gssint_krb5_keytab_lock = K5_MUTEX_PARTIAL_INITIALIZER;
102ab9b2e15Sgtb static char *krb5_gss_keytab = NULL;
103ab9b2e15Sgtb 
104ab9b2e15Sgtb /* Heimdal calls this gsskrb5_register_acceptor_identity. */
105ab9b2e15Sgtb OM_uint32 KRB5_CALLCONV
krb5_gss_register_acceptor_identity(const char * keytab)106ab9b2e15Sgtb krb5_gss_register_acceptor_identity(const char *keytab)
107ab9b2e15Sgtb {
108ab9b2e15Sgtb     size_t	len;
109ab9b2e15Sgtb     char *new, *old;
110ab9b2e15Sgtb     int err;
111ab9b2e15Sgtb 
112ab9b2e15Sgtb     err = gssint_initialize_library();
113ab9b2e15Sgtb     if (err != 0)
114ab9b2e15Sgtb 	return GSS_S_FAILURE;
115ab9b2e15Sgtb 
116ab9b2e15Sgtb     if (keytab == NULL)
117ab9b2e15Sgtb 	return GSS_S_FAILURE;
118ab9b2e15Sgtb 
119ab9b2e15Sgtb     len = strlen(keytab);
120ab9b2e15Sgtb     new = malloc(len + 1);
121ab9b2e15Sgtb     if (new == NULL)
122ab9b2e15Sgtb 	return GSS_S_FAILURE;
123ab9b2e15Sgtb     strcpy(new, keytab);
124ab9b2e15Sgtb 
125ab9b2e15Sgtb     err = k5_mutex_lock(&gssint_krb5_keytab_lock);
126ab9b2e15Sgtb     if (err) {
127ab9b2e15Sgtb 	free(new);
128ab9b2e15Sgtb 	return GSS_S_FAILURE;
129ab9b2e15Sgtb     }
130ab9b2e15Sgtb     old = krb5_gss_keytab;
131ab9b2e15Sgtb     krb5_gss_keytab = new;
132ab9b2e15Sgtb     k5_mutex_unlock(&gssint_krb5_keytab_lock);
133ab9b2e15Sgtb     if (old != NULL)
134ab9b2e15Sgtb 	free(old);
135ab9b2e15Sgtb     return GSS_S_COMPLETE;
136ab9b2e15Sgtb }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /* get credentials corresponding to a key in the krb5 keytab.
1397c478bd9Sstevel@tonic-gate    If the default name is requested, return the name in output_princ.
1407c478bd9Sstevel@tonic-gate      If output_princ is non-NULL, the caller will use or free it, regardless
1417c478bd9Sstevel@tonic-gate      of the return value.
1427c478bd9Sstevel@tonic-gate    If successful, set the keytab-specific fields in cred
1437c478bd9Sstevel@tonic-gate    */
1447c478bd9Sstevel@tonic-gate 
145*55fea89dSDan Cross static OM_uint32
acquire_accept_cred(context,minor_status,desired_name,output_princ,cred)1467c478bd9Sstevel@tonic-gate acquire_accept_cred(context, minor_status, desired_name, output_princ, cred)
1477c478bd9Sstevel@tonic-gate      krb5_context context;
1487c478bd9Sstevel@tonic-gate      OM_uint32 *minor_status;
1497c478bd9Sstevel@tonic-gate      gss_name_t desired_name;
1507c478bd9Sstevel@tonic-gate      krb5_principal *output_princ;
1517c478bd9Sstevel@tonic-gate      krb5_gss_cred_id_rec *cred;
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate    krb5_error_code code;
1547c478bd9Sstevel@tonic-gate    krb5_principal princ;
1557c478bd9Sstevel@tonic-gate    krb5_keytab kt;
1567c478bd9Sstevel@tonic-gate    krb5_keytab_entry entry;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate    *output_princ = NULL;
1597c478bd9Sstevel@tonic-gate    cred->keytab = NULL;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate    /* open the default keytab */
1627c478bd9Sstevel@tonic-gate 
163ab9b2e15Sgtb    code = gssint_initialize_library();
164ab9b2e15Sgtb    if (code != 0) {
165ab9b2e15Sgtb        *minor_status = code;
166ab9b2e15Sgtb        return GSS_S_FAILURE;
167ab9b2e15Sgtb    }
168ab9b2e15Sgtb    code = k5_mutex_lock(&gssint_krb5_keytab_lock);
169ab9b2e15Sgtb    if (code) {
170ab9b2e15Sgtb        *minor_status = code;
171ab9b2e15Sgtb        return GSS_S_FAILURE;
172ab9b2e15Sgtb    }
173ab9b2e15Sgtb    if (krb5_gss_keytab != NULL) {
174ab9b2e15Sgtb       code = krb5_kt_resolve(context, krb5_gss_keytab, &kt);
175ab9b2e15Sgtb       k5_mutex_unlock(&gssint_krb5_keytab_lock);
176ab9b2e15Sgtb    } else {
177ab9b2e15Sgtb       k5_mutex_unlock(&gssint_krb5_keytab_lock);
178ab9b2e15Sgtb       code = krb5_kt_default(context, &kt);
179ab9b2e15Sgtb    }
180ab9b2e15Sgtb 
181ab9b2e15Sgtb    if (code) {
1827c478bd9Sstevel@tonic-gate       *minor_status = code;
183ab9b2e15Sgtb       /* Solaris Kerb NOTE: GSS_S_CRED_UNAVAIL is not RFC 2743 compliant */
1847c478bd9Sstevel@tonic-gate       return(GSS_S_NO_CRED);
1857c478bd9Sstevel@tonic-gate    }
1867c478bd9Sstevel@tonic-gate 
1875e01956fSGlenn Barry     if (desired_name != GSS_C_NO_NAME) {
1885e01956fSGlenn Barry         princ = (krb5_principal) desired_name;
1895e01956fSGlenn Barry         if ((code = krb5_kt_get_entry(context, kt, princ, 0, 0, &entry))) {
1905e01956fSGlenn Barry 	    if (code == KRB5_KT_NOTFOUND) {
1915e01956fSGlenn Barry 	        char *s_name;
1925e01956fSGlenn Barry 	        if (krb5_unparse_name(context, princ, &s_name) == 0) {
1935e01956fSGlenn Barry 		    krb5_set_error_message(context, KG_KEYTAB_NOMATCH,
1945e01956fSGlenn Barry 					dgettext(TEXT_DOMAIN,
1955e01956fSGlenn Barry 						"No principal in keytab ('%s') matches desired name %s"),
1965e01956fSGlenn Barry 					KTFILENAME(kt),
1975e01956fSGlenn Barry 					s_name);
1985e01956fSGlenn Barry 	            krb5_free_unparsed_name(context, s_name);
1995e01956fSGlenn Barry 		}
2005e01956fSGlenn Barry 		*minor_status = KG_KEYTAB_NOMATCH;
2015e01956fSGlenn Barry 	    } else
2025e01956fSGlenn Barry 	        *minor_status = code;
203ab9b2e15Sgtb 	 /* Solaris Kerb NOTE: GSS_S_CRED_UNAVAIL is not RFC 2743 compliant */
2045e01956fSGlenn Barry 	    (void) krb5_kt_close(context, kt);
2055e01956fSGlenn Barry 	    return(GSS_S_NO_CRED);
2065e01956fSGlenn Barry 	}
2075e01956fSGlenn Barry 	krb5_kt_free_entry(context, &entry);
2083dba6097Smp 
2093dba6097Smp       /* Open the replay cache for this principal. */
2103dba6097Smp       if ((code = krb5_get_server_rcache(context,
2113dba6097Smp 					 krb5_princ_component(context, princ, 0),
2123dba6097Smp 					 &cred->rcache))) {
2137c478bd9Sstevel@tonic-gate 	 *minor_status = code;
2147c478bd9Sstevel@tonic-gate 	 return(GSS_S_FAILURE);
2157c478bd9Sstevel@tonic-gate       }
2167c478bd9Sstevel@tonic-gate 
2175e01956fSGlenn Barry     }
2187c478bd9Sstevel@tonic-gate 
219ab9b2e15Sgtb /* hooray.  we made it */
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate    cred->keytab = kt;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate    return(GSS_S_COMPLETE);
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate /* get credentials corresponding to the default credential cache.
2277c478bd9Sstevel@tonic-gate    If the default name is requested, return the name in output_princ.
2287c478bd9Sstevel@tonic-gate      If output_princ is non-NULL, the caller will use or free it, regardless
2297c478bd9Sstevel@tonic-gate      of the return value.
2307c478bd9Sstevel@tonic-gate    If successful, set the ccache-specific fields in cred.
2317c478bd9Sstevel@tonic-gate    */
2327c478bd9Sstevel@tonic-gate 
233*55fea89dSDan Cross static OM_uint32
acquire_init_cred(context,minor_status,desired_name,output_princ,cred)2347c478bd9Sstevel@tonic-gate acquire_init_cred(context, minor_status, desired_name, output_princ, cred)
2357c478bd9Sstevel@tonic-gate      krb5_context context;
2367c478bd9Sstevel@tonic-gate      OM_uint32 *minor_status;
2377c478bd9Sstevel@tonic-gate      gss_name_t desired_name;
2387c478bd9Sstevel@tonic-gate      krb5_principal *output_princ;
2397c478bd9Sstevel@tonic-gate      krb5_gss_cred_id_rec *cred;
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate    krb5_error_code code;
2427c478bd9Sstevel@tonic-gate    krb5_ccache ccache;
2437c478bd9Sstevel@tonic-gate    krb5_principal princ, tmp_princ;
2447c478bd9Sstevel@tonic-gate    krb5_flags flags;
2457c478bd9Sstevel@tonic-gate    krb5_cc_cursor cur;
2467c478bd9Sstevel@tonic-gate    krb5_creds creds;
2477c478bd9Sstevel@tonic-gate    int got_endtime;
248159d09a2SMark Phalan    int caller_provided_ccache_name = 0;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate    cred->ccache = NULL;
2517c478bd9Sstevel@tonic-gate 
252505d05c7Sgtb    /* load the GSS ccache name into the kg_context */
253*55fea89dSDan Cross 
254505d05c7Sgtb    if (GSS_ERROR(kg_sync_ccache_name(context, minor_status)))
255505d05c7Sgtb        return(GSS_S_FAILURE);
2567c478bd9Sstevel@tonic-gate 
257*55fea89dSDan Cross    /* check to see if the caller provided a ccache name if so
258159d09a2SMark Phalan     * we will just use that and not search the cache collection */
259159d09a2SMark Phalan    if (GSS_ERROR(kg_caller_provided_ccache_name (minor_status, &caller_provided_ccache_name))) {
260159d09a2SMark Phalan        return(GSS_S_FAILURE);
261159d09a2SMark Phalan    }
262159d09a2SMark Phalan 
263ab9b2e15Sgtb #if defined(USE_LOGIN_LIBRARY) || defined(USE_LEASH)
264159d09a2SMark Phalan    if (desired_name && !caller_provided_ccache_name) {
265ab9b2e15Sgtb #if defined(USE_LOGIN_LIBRARY)
266159d09a2SMark Phalan        KLStatus err = klNoErr;
267ab9b2e15Sgtb        char *ccache_name = NULL;
268ab9b2e15Sgtb        KLPrincipal kl_desired_princ = NULL;
269159d09a2SMark Phalan 
270159d09a2SMark Phalan        err = __KLCreatePrincipalFromKerberos5Principal ((krb5_principal) desired_name,
271159d09a2SMark Phalan                                                         &kl_desired_princ);
272*55fea89dSDan Cross 
273159d09a2SMark Phalan        if (!err) {
274159d09a2SMark Phalan            err = KLAcquireInitialTickets (kl_desired_princ, NULL, NULL, &ccache_name);
275ab9b2e15Sgtb        }
276159d09a2SMark Phalan 
277159d09a2SMark Phalan        if (!err) {
278159d09a2SMark Phalan            err = krb5_cc_resolve (context, ccache_name, &ccache);
279ab9b2e15Sgtb        }
280*55fea89dSDan Cross 
281159d09a2SMark Phalan        if (err) {
282159d09a2SMark Phalan            *minor_status = err;
283159d09a2SMark Phalan            return(GSS_S_CRED_UNAVAIL);
284ab9b2e15Sgtb        }
285*55fea89dSDan Cross 
286ab9b2e15Sgtb        if (kl_desired_princ != NULL) { KLDisposePrincipal (kl_desired_princ); }
287ab9b2e15Sgtb        if (ccache_name      != NULL) { KLDisposeString (ccache_name); }
288*55fea89dSDan Cross 
289ab9b2e15Sgtb #elif defined(USE_LEASH)
290ab9b2e15Sgtb        if ( hLeashDLL == INVALID_HANDLE_VALUE ) {
291159d09a2SMark Phalan 	   hLeashDLL = LoadLibrary(LEASH_DLL);
292ab9b2e15Sgtb 	   if ( hLeashDLL != INVALID_HANDLE_VALUE ) {
293ab9b2e15Sgtb 	       (FARPROC) pLeash_AcquireInitialTicketsIfNeeded =
294ab9b2e15Sgtb 		   GetProcAddress(hLeashDLL, "not_an_API_Leash_AcquireInitialTicketsIfNeeded");
295ab9b2e15Sgtb 	   }
296ab9b2e15Sgtb        }
297*55fea89dSDan Cross 
298ab9b2e15Sgtb        if ( pLeash_AcquireInitialTicketsIfNeeded ) {
299ab9b2e15Sgtb 	   char ccname[256]="";
300ab9b2e15Sgtb 	   pLeash_AcquireInitialTicketsIfNeeded(context, (krb5_principal) desired_name, ccname, sizeof(ccname));
301ab9b2e15Sgtb 	   if (!ccname[0]) {
302ab9b2e15Sgtb 	       *minor_status = KRB5_CC_NOTFOUND;
303ab9b2e15Sgtb 	       return(GSS_S_NO_CRED);
304ab9b2e15Sgtb 	   }
305ab9b2e15Sgtb 
306ab9b2e15Sgtb 	   if ((code = krb5_cc_resolve (context, ccname, &ccache))) {
307ab9b2e15Sgtb 	       *minor_status = code;
308ab9b2e15Sgtb 	       return(GSS_S_NO_CRED);
309ab9b2e15Sgtb 	   }
310ab9b2e15Sgtb        } else {
311ab9b2e15Sgtb 	   /* leash dll not available, open the default credential cache */
312*55fea89dSDan Cross 
313ab9b2e15Sgtb 	   if ((code = krb5int_cc_default(context, &ccache))) {
314ab9b2e15Sgtb 	       *minor_status = code;
315ab9b2e15Sgtb 	       return(GSS_S_NO_CRED);
316ab9b2e15Sgtb 	   }
317ab9b2e15Sgtb        }
318ab9b2e15Sgtb #endif /* USE_LEASH */
319ab9b2e15Sgtb    } else
320ab9b2e15Sgtb #endif /* USE_LOGIN_LIBRARY || USE_LEASH */
321ab9b2e15Sgtb    {
322ab9b2e15Sgtb        /* open the default credential cache */
323*55fea89dSDan Cross 
324ab9b2e15Sgtb        if ((code = krb5int_cc_default(context, &ccache))) {
325ab9b2e15Sgtb 	   *minor_status = code;
326ab9b2e15Sgtb 	   return(GSS_S_NO_CRED);
327ab9b2e15Sgtb        }
3287c478bd9Sstevel@tonic-gate    }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate    /* turn off OPENCLOSE mode while extensive frobbing is going on */
331505d05c7Sgtb    /*
332505d05c7Sgtb     * SUNW14resync
333505d05c7Sgtb     * Added calls to krb5_cc_set_flags(... KRB5_TC_OPENCLOSE)
334505d05c7Sgtb     * on the error returns cuz the 1.4 krb5_cc_close does not always close
335505d05c7Sgtb     * the file like it used to and caused STC test gss.27 to fail.
336505d05c7Sgtb     */
3377c478bd9Sstevel@tonic-gate    flags = 0;		/* turns off OPENCLOSE mode */
338ab9b2e15Sgtb    if ((code = krb5_cc_set_flags(context, ccache, flags))) {
339505d05c7Sgtb       (void)krb5_cc_close(context, ccache);
3407c478bd9Sstevel@tonic-gate       *minor_status = code;
3417c478bd9Sstevel@tonic-gate       return(GSS_S_NO_CRED);
3427c478bd9Sstevel@tonic-gate    }
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate    /* get out the principal name and see if it matches */
3457c478bd9Sstevel@tonic-gate 
346ab9b2e15Sgtb    if ((code = krb5_cc_get_principal(context, ccache, &princ))) {
347159d09a2SMark Phalan       /* Solaris Kerberos */
348505d05c7Sgtb       (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
3497c478bd9Sstevel@tonic-gate       (void)krb5_cc_close(context, ccache);
3507c478bd9Sstevel@tonic-gate       *minor_status = code;
3517c478bd9Sstevel@tonic-gate       return(GSS_S_FAILURE);
3527c478bd9Sstevel@tonic-gate    }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate    if (desired_name != (gss_name_t) NULL) {
3557c478bd9Sstevel@tonic-gate       if (! krb5_principal_compare(context, princ, (krb5_principal) desired_name)) {
3567c478bd9Sstevel@tonic-gate 	 (void)krb5_free_principal(context, princ);
357159d09a2SMark Phalan 	 /* Solaris Kerberos */
358ab9b2e15Sgtb 	 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
3597c478bd9Sstevel@tonic-gate 	 (void)krb5_cc_close(context, ccache);
3607c478bd9Sstevel@tonic-gate 	 *minor_status = KG_CCACHE_NOMATCH;
3617c478bd9Sstevel@tonic-gate 	 return(GSS_S_NO_CRED);
3627c478bd9Sstevel@tonic-gate       }
3637c478bd9Sstevel@tonic-gate       (void)krb5_free_principal(context, princ);
3647c478bd9Sstevel@tonic-gate       princ = (krb5_principal) desired_name;
3657c478bd9Sstevel@tonic-gate    } else {
3667c478bd9Sstevel@tonic-gate       *output_princ = princ;
3677c478bd9Sstevel@tonic-gate    }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate    /* iterate over the ccache, find the tgt */
3707c478bd9Sstevel@tonic-gate 
371ab9b2e15Sgtb    if ((code = krb5_cc_start_seq_get(context, ccache, &cur))) {
372159d09a2SMark Phalan       /* Solaris Kerberos */
373505d05c7Sgtb       (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
3747c478bd9Sstevel@tonic-gate       (void)krb5_cc_close(context, ccache);
3757c478bd9Sstevel@tonic-gate       *minor_status = code;
3767c478bd9Sstevel@tonic-gate       return(GSS_S_FAILURE);
3777c478bd9Sstevel@tonic-gate    }
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate    /* this is hairy.  If there's a tgt for the principal's local realm
3807c478bd9Sstevel@tonic-gate       in here, that's what we want for the expire time.  But if
3817c478bd9Sstevel@tonic-gate       there's not, then we want to use the first key.  */
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate    got_endtime = 0;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate    code = krb5_build_principal_ext(context, &tmp_princ,
3867c478bd9Sstevel@tonic-gate 				   krb5_princ_realm(context, princ)->length,
3877c478bd9Sstevel@tonic-gate 				   krb5_princ_realm(context, princ)->data,
3887c478bd9Sstevel@tonic-gate 				   6, "krbtgt",
3897c478bd9Sstevel@tonic-gate 				   krb5_princ_realm(context, princ)->length,
3907c478bd9Sstevel@tonic-gate 				   krb5_princ_realm(context, princ)->data,
3917c478bd9Sstevel@tonic-gate 				   0);
3927c478bd9Sstevel@tonic-gate    if (code) {
393159d09a2SMark Phalan       /* Solaris Kerberos */
394505d05c7Sgtb       (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
3957c478bd9Sstevel@tonic-gate       (void)krb5_cc_close(context, ccache);
3967c478bd9Sstevel@tonic-gate       *minor_status = code;
3977c478bd9Sstevel@tonic-gate       return(GSS_S_FAILURE);
3987c478bd9Sstevel@tonic-gate    }
399ab9b2e15Sgtb    while (!(code = krb5_cc_next_cred(context, ccache, &cur, &creds))) {
4007c478bd9Sstevel@tonic-gate       if (krb5_principal_compare(context, tmp_princ, creds.server)) {
4017c478bd9Sstevel@tonic-gate 	 cred->tgt_expire = creds.times.endtime;
4027c478bd9Sstevel@tonic-gate 	 got_endtime = 1;
4037c478bd9Sstevel@tonic-gate 	 *minor_status = 0;
4047c478bd9Sstevel@tonic-gate 	 code = 0;
4057c478bd9Sstevel@tonic-gate 	 krb5_free_cred_contents(context, &creds);
4067c478bd9Sstevel@tonic-gate 	 break;
4077c478bd9Sstevel@tonic-gate       }
4087c478bd9Sstevel@tonic-gate       if (got_endtime == 0) {
4097c478bd9Sstevel@tonic-gate 	 cred->tgt_expire = creds.times.endtime;
4107c478bd9Sstevel@tonic-gate 	 got_endtime = 1;
4117c478bd9Sstevel@tonic-gate       }
4127c478bd9Sstevel@tonic-gate       krb5_free_cred_contents(context, &creds);
4137c478bd9Sstevel@tonic-gate    }
4147c478bd9Sstevel@tonic-gate    krb5_free_principal(context, tmp_princ);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate    if (code && code != KRB5_CC_END) {
4177c478bd9Sstevel@tonic-gate       /* this means some error occurred reading the ccache */
4187c478bd9Sstevel@tonic-gate       (void)krb5_cc_end_seq_get(context, ccache, &cur);
419159d09a2SMark Phalan       /* Solaris Kerberos */
420505d05c7Sgtb       (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
4217c478bd9Sstevel@tonic-gate       (void)krb5_cc_close(context, ccache);
4227c478bd9Sstevel@tonic-gate       *minor_status = code;
4237c478bd9Sstevel@tonic-gate       return(GSS_S_FAILURE);
4247c478bd9Sstevel@tonic-gate    } else if (! got_endtime) {
4257c478bd9Sstevel@tonic-gate       /* this means the ccache was entirely empty */
4267c478bd9Sstevel@tonic-gate       (void)krb5_cc_end_seq_get(context, ccache, &cur);
427159d09a2SMark Phalan       /* Solaris Kerberos */
428505d05c7Sgtb       (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
4297c478bd9Sstevel@tonic-gate       (void)krb5_cc_close(context, ccache);
4307c478bd9Sstevel@tonic-gate       *minor_status = KG_EMPTY_CCACHE;
4317c478bd9Sstevel@tonic-gate       return(GSS_S_FAILURE);
4327c478bd9Sstevel@tonic-gate    } else {
4337c478bd9Sstevel@tonic-gate       /* this means that we found an endtime to use. */
434ab9b2e15Sgtb       if ((code = krb5_cc_end_seq_get(context, ccache, &cur))) {
435159d09a2SMark Phalan 	 /* Solaris Kerberos */
436505d05c7Sgtb 	 (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
4377c478bd9Sstevel@tonic-gate 	 (void)krb5_cc_close(context, ccache);
4387c478bd9Sstevel@tonic-gate 	 *minor_status = code;
4397c478bd9Sstevel@tonic-gate 	 return(GSS_S_FAILURE);
4407c478bd9Sstevel@tonic-gate       }
4417c478bd9Sstevel@tonic-gate       flags = KRB5_TC_OPENCLOSE;	/* turns on OPENCLOSE mode */
442ab9b2e15Sgtb       if ((code = krb5_cc_set_flags(context, ccache, flags))) {
4437c478bd9Sstevel@tonic-gate 	 (void)krb5_cc_close(context, ccache);
4447c478bd9Sstevel@tonic-gate 	 *minor_status = code;
4457c478bd9Sstevel@tonic-gate 	 return(GSS_S_FAILURE);
4467c478bd9Sstevel@tonic-gate       }
4477c478bd9Sstevel@tonic-gate    }
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate    /* the credentials match and are valid */
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate    cred->ccache = ccache;
4527c478bd9Sstevel@tonic-gate    /* minor_status is set while we are iterating over the ccache */
4537c478bd9Sstevel@tonic-gate    return(GSS_S_COMPLETE);
4547c478bd9Sstevel@tonic-gate }
455*55fea89dSDan Cross 
4567c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4577c478bd9Sstevel@tonic-gate OM_uint32
krb5_gss_acquire_cred(minor_status,desired_name,time_req,desired_mechs,cred_usage,output_cred_handle,actual_mechs,time_rec)458ab9b2e15Sgtb krb5_gss_acquire_cred(minor_status, desired_name, time_req,
4597c478bd9Sstevel@tonic-gate 		      desired_mechs, cred_usage, output_cred_handle,
4607c478bd9Sstevel@tonic-gate 		      actual_mechs, time_rec)
4617c478bd9Sstevel@tonic-gate      OM_uint32 *minor_status;
4627c478bd9Sstevel@tonic-gate      gss_name_t desired_name;
4637c478bd9Sstevel@tonic-gate      OM_uint32 time_req;
4647c478bd9Sstevel@tonic-gate      gss_OID_set desired_mechs;
4657c478bd9Sstevel@tonic-gate      gss_cred_usage_t cred_usage;
4667c478bd9Sstevel@tonic-gate      gss_cred_id_t *output_cred_handle;
4677c478bd9Sstevel@tonic-gate      gss_OID_set *actual_mechs;
4687c478bd9Sstevel@tonic-gate      OM_uint32 *time_rec;
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate    krb5_context context;
4717c478bd9Sstevel@tonic-gate    size_t i;
4727c478bd9Sstevel@tonic-gate    krb5_gss_cred_id_t cred;
473ab9b2e15Sgtb    gss_OID_set ret_mechs;
4747c478bd9Sstevel@tonic-gate    int req_old, req_new;
4757c478bd9Sstevel@tonic-gate    OM_uint32 ret;
4767c478bd9Sstevel@tonic-gate    krb5_error_code code;
4777c478bd9Sstevel@tonic-gate 
478ab9b2e15Sgtb    code = gssint_initialize_library();
479ab9b2e15Sgtb    if (code) {
480ab9b2e15Sgtb        *minor_status = code;
481ab9b2e15Sgtb        return GSS_S_FAILURE;
482ab9b2e15Sgtb    }
4837c478bd9Sstevel@tonic-gate 
484ab9b2e15Sgtb    code = krb5_gss_init_context(&context);
485ab9b2e15Sgtb    if (code) {
486ab9b2e15Sgtb        *minor_status = code;
487ab9b2e15Sgtb        return GSS_S_FAILURE;
488ab9b2e15Sgtb    }
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate    /* make sure all outputs are valid */
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate    *output_cred_handle = NULL;
4937c478bd9Sstevel@tonic-gate    if (actual_mechs)
4947c478bd9Sstevel@tonic-gate       *actual_mechs = NULL;
4957c478bd9Sstevel@tonic-gate    if (time_rec)
4967c478bd9Sstevel@tonic-gate       *time_rec = 0;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate    /* validate the name */
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate    /*SUPPRESS 29*/
5017c478bd9Sstevel@tonic-gate    if ((desired_name != (gss_name_t) NULL) &&
5027c478bd9Sstevel@tonic-gate        (! kg_validate_name(desired_name))) {
503*55fea89dSDan Cross 	*minor_status = (OM_uint32) G_VALIDATE_FAILED;
5045e01956fSGlenn Barry 	krb5_free_context(context);
5055e01956fSGlenn Barry 	return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
5067c478bd9Sstevel@tonic-gate    }
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate    /* verify that the requested mechanism set is the default, or
5097c478bd9Sstevel@tonic-gate       contains krb5 */
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate    if (desired_mechs == GSS_C_NULL_OID_SET) {
5127c478bd9Sstevel@tonic-gate       req_old = 1;
5137c478bd9Sstevel@tonic-gate       req_new = 1;
5147c478bd9Sstevel@tonic-gate    } else {
5157c478bd9Sstevel@tonic-gate       req_old = 0;
5167c478bd9Sstevel@tonic-gate       req_new = 0;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate       for (i=0; i<desired_mechs->count; i++) {
5197c478bd9Sstevel@tonic-gate 	 if (g_OID_equal(gss_mech_krb5_old, &(desired_mechs->elements[i])))
5207c478bd9Sstevel@tonic-gate 	    req_old++;
5217c478bd9Sstevel@tonic-gate 	 if (g_OID_equal(gss_mech_krb5, &(desired_mechs->elements[i])))
5227c478bd9Sstevel@tonic-gate 	    req_new++;
5237c478bd9Sstevel@tonic-gate       }
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate       if (!req_old && !req_new) {
5267c478bd9Sstevel@tonic-gate 	 *minor_status = 0;
527ab9b2e15Sgtb 	 krb5_free_context(context);
5287c478bd9Sstevel@tonic-gate 	 return(GSS_S_BAD_MECH);
5297c478bd9Sstevel@tonic-gate       }
5307c478bd9Sstevel@tonic-gate    }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate    /* create the gss cred structure */
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate    if ((cred =
5357c478bd9Sstevel@tonic-gate 	(krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec))) == NULL) {
5367c478bd9Sstevel@tonic-gate       *minor_status = ENOMEM;
537ab9b2e15Sgtb       krb5_free_context(context);
5387c478bd9Sstevel@tonic-gate       return(GSS_S_FAILURE);
5397c478bd9Sstevel@tonic-gate    }
5407c478bd9Sstevel@tonic-gate    memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate    cred->usage = cred_usage;
5437c478bd9Sstevel@tonic-gate    cred->princ = NULL;
5447c478bd9Sstevel@tonic-gate    cred->prerfc_mech = req_old;
5457c478bd9Sstevel@tonic-gate    cred->rfc_mech = req_new;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate    cred->keytab = NULL;
5487c478bd9Sstevel@tonic-gate    cred->ccache = NULL;
5497c478bd9Sstevel@tonic-gate 
550ab9b2e15Sgtb    code = k5_mutex_init(&cred->lock);
551ab9b2e15Sgtb    if (code) {
552ab9b2e15Sgtb        *minor_status = code;
553ab9b2e15Sgtb        krb5_free_context(context);
554ab9b2e15Sgtb        return GSS_S_FAILURE;
555ab9b2e15Sgtb    }
556ab9b2e15Sgtb    /* Note that we don't need to lock this GSSAPI credential record
557ab9b2e15Sgtb       here, because no other thread can gain access to it until we
558ab9b2e15Sgtb       return it.  */
559ab9b2e15Sgtb 
5607c478bd9Sstevel@tonic-gate    if ((cred_usage != GSS_C_INITIATE) &&
5617c478bd9Sstevel@tonic-gate        (cred_usage != GSS_C_ACCEPT) &&
5627c478bd9Sstevel@tonic-gate        (cred_usage != GSS_C_BOTH)) {
563ab9b2e15Sgtb       k5_mutex_destroy(&cred->lock);
5647c478bd9Sstevel@tonic-gate       xfree(cred);
5657c478bd9Sstevel@tonic-gate       *minor_status = (OM_uint32) G_BAD_USAGE;
566ab9b2e15Sgtb       krb5_free_context(context);
5677c478bd9Sstevel@tonic-gate       return(GSS_S_FAILURE);
5687c478bd9Sstevel@tonic-gate    }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate    /* if requested, acquire credentials for accepting */
5717c478bd9Sstevel@tonic-gate    /* this will fill in cred->princ if the desired_name is not specified */
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate    if ((cred_usage == GSS_C_ACCEPT) ||
5747c478bd9Sstevel@tonic-gate        (cred_usage == GSS_C_BOTH))
5757c478bd9Sstevel@tonic-gate       if ((ret = acquire_accept_cred(context, minor_status, desired_name,
5767c478bd9Sstevel@tonic-gate 				     &(cred->princ), cred))
5777c478bd9Sstevel@tonic-gate 	  != GSS_S_COMPLETE) {
5787c478bd9Sstevel@tonic-gate 	 if (cred->princ)
5797c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, cred->princ);
580ab9b2e15Sgtb          k5_mutex_destroy(&cred->lock);
581ab9b2e15Sgtb          xfree(cred);
5827c478bd9Sstevel@tonic-gate 	 /* minor_status set by acquire_accept_cred() */
5835e01956fSGlenn Barry 	 save_error_info(*minor_status, context);
584ab9b2e15Sgtb 	 krb5_free_context(context);
5857c478bd9Sstevel@tonic-gate 	 return(ret);
5867c478bd9Sstevel@tonic-gate       }
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate    /* if requested, acquire credentials for initiation */
5897c478bd9Sstevel@tonic-gate    /* this will fill in cred->princ if it wasn't set above, and
5907c478bd9Sstevel@tonic-gate       the desired_name is not specified */
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate    if ((cred_usage == GSS_C_INITIATE) ||
5937c478bd9Sstevel@tonic-gate        (cred_usage == GSS_C_BOTH))
5947c478bd9Sstevel@tonic-gate       if ((ret =
5957c478bd9Sstevel@tonic-gate 	   acquire_init_cred(context, minor_status,
5967c478bd9Sstevel@tonic-gate 			     cred->princ?(gss_name_t)cred->princ:desired_name,
5977c478bd9Sstevel@tonic-gate 			     &(cred->princ), cred))
5987c478bd9Sstevel@tonic-gate 	  != GSS_S_COMPLETE) {
5997c478bd9Sstevel@tonic-gate 	 if (cred->keytab)
600ab9b2e15Sgtb 	    krb5_kt_close(context, cred->keytab);
6017c478bd9Sstevel@tonic-gate 	 if (cred->princ)
6027c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, cred->princ);
603ab9b2e15Sgtb          k5_mutex_destroy(&cred->lock);
604ab9b2e15Sgtb          xfree(cred);
6057c478bd9Sstevel@tonic-gate 	 /* minor_status set by acquire_init_cred() */
6065e01956fSGlenn Barry          save_error_info(*minor_status, context);
607ab9b2e15Sgtb 	 krb5_free_context(context);
6087c478bd9Sstevel@tonic-gate 	 return(ret);
6097c478bd9Sstevel@tonic-gate       }
6107c478bd9Sstevel@tonic-gate 
6113dba6097Smp    /* Solaris Kerberos:
612ab9b2e15Sgtb     * if the princ wasn't filled in already, fill it in now unless
6133dba6097Smp     * a cred with no associated princ is requested (will invoke default
6143dba6097Smp     * behaviour when gss_accept_init_context() is called).
615ab9b2e15Sgtb     * Note MIT 1.4 has GSS_C_NO_CREDENTIAL instead of GSS_C_NO_NAME
6163dba6097Smp     */
6173dba6097Smp    if (!cred->princ && (desired_name != GSS_C_NO_NAME))
6187c478bd9Sstevel@tonic-gate       if ((code = krb5_copy_principal(context, (krb5_principal) desired_name,
6197c478bd9Sstevel@tonic-gate 				      &(cred->princ)))) {
6207c478bd9Sstevel@tonic-gate 	 if (cred->ccache)
6217c478bd9Sstevel@tonic-gate 	    (void)krb5_cc_close(context, cred->ccache);
6227c478bd9Sstevel@tonic-gate 	 if (cred->keytab)
6237c478bd9Sstevel@tonic-gate 	    (void)krb5_kt_close(context, cred->keytab);
624ab9b2e15Sgtb          k5_mutex_destroy(&cred->lock);
625ab9b2e15Sgtb          xfree(cred);
6267c478bd9Sstevel@tonic-gate 	 *minor_status = code;
6275e01956fSGlenn Barry          save_error_info(*minor_status, context);
628ab9b2e15Sgtb 	 krb5_free_context(context);
6297c478bd9Sstevel@tonic-gate 	 return(GSS_S_FAILURE);
6307c478bd9Sstevel@tonic-gate       }
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate    /*** at this point, the cred structure has been completely created */
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate    /* compute time_rec */
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate    if (cred_usage == GSS_C_ACCEPT) {
6377c478bd9Sstevel@tonic-gate       if (time_rec)
6387c478bd9Sstevel@tonic-gate 	 *time_rec = GSS_C_INDEFINITE;
6397c478bd9Sstevel@tonic-gate    } else {
6407c478bd9Sstevel@tonic-gate       krb5_timestamp now;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate       if ((code = krb5_timeofday(context, &now))) {
6437c478bd9Sstevel@tonic-gate 	 if (cred->ccache)
6447c478bd9Sstevel@tonic-gate 	    (void)krb5_cc_close(context, cred->ccache);
6457c478bd9Sstevel@tonic-gate 	 if (cred->keytab)
6467c478bd9Sstevel@tonic-gate 	    (void)krb5_kt_close(context, cred->keytab);
6477c478bd9Sstevel@tonic-gate 	 if (cred->princ)
6487c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, cred->princ);
649ab9b2e15Sgtb          k5_mutex_destroy(&cred->lock);
650ab9b2e15Sgtb          xfree(cred);
6517c478bd9Sstevel@tonic-gate 	 *minor_status = code;
6525e01956fSGlenn Barry 	 save_error_info(*minor_status, context);
653ab9b2e15Sgtb 	 krb5_free_context(context);
6547c478bd9Sstevel@tonic-gate 	 return(GSS_S_FAILURE);
6557c478bd9Sstevel@tonic-gate       }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate       if (time_rec)
6587c478bd9Sstevel@tonic-gate 	 *time_rec = (cred->tgt_expire > now) ? (cred->tgt_expire - now) : 0;
6597c478bd9Sstevel@tonic-gate    }
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate    /* create mechs */
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate    if (actual_mechs) {
664ab9b2e15Sgtb        if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status,
6657c478bd9Sstevel@tonic-gate 							    &ret_mechs)) ||
6667c478bd9Sstevel@tonic-gate 	   (cred->prerfc_mech &&
667ab9b2e15Sgtb 	    GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
668159d09a2SMark Phalan 							  (const gss_OID) gss_mech_krb5_old,
6697c478bd9Sstevel@tonic-gate 							   &ret_mechs))) ||
6707c478bd9Sstevel@tonic-gate 	   (cred->rfc_mech &&
671ab9b2e15Sgtb 	    GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
672159d09a2SMark Phalan 							  (const gss_OID) gss_mech_krb5,
6737c478bd9Sstevel@tonic-gate 							   &ret_mechs)))) {
6747c478bd9Sstevel@tonic-gate 	   if (cred->ccache)
6757c478bd9Sstevel@tonic-gate 	       (void)krb5_cc_close(context, cred->ccache);
6767c478bd9Sstevel@tonic-gate 	   if (cred->keytab)
6777c478bd9Sstevel@tonic-gate 	       (void)krb5_kt_close(context, cred->keytab);
6787c478bd9Sstevel@tonic-gate 	   if (cred->princ)
6797c478bd9Sstevel@tonic-gate 	       krb5_free_principal(context, cred->princ);
680ab9b2e15Sgtb            k5_mutex_destroy(&cred->lock);
6817c478bd9Sstevel@tonic-gate 	   xfree(cred);
682ab9b2e15Sgtb 	   /* *minor_status set above */
683ab9b2e15Sgtb 	   krb5_free_context(context);
6847c478bd9Sstevel@tonic-gate 	   return(ret);
6857c478bd9Sstevel@tonic-gate        }
6867c478bd9Sstevel@tonic-gate    }
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate    /* intern the credential handle */
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate    if (! kg_save_cred_id((gss_cred_id_t) cred)) {
6917c478bd9Sstevel@tonic-gate       free(ret_mechs->elements);
6927c478bd9Sstevel@tonic-gate       free(ret_mechs);
6937c478bd9Sstevel@tonic-gate       if (cred->ccache)
6947c478bd9Sstevel@tonic-gate 	 (void)krb5_cc_close(context, cred->ccache);
6957c478bd9Sstevel@tonic-gate       if (cred->keytab)
6967c478bd9Sstevel@tonic-gate 	 (void)krb5_kt_close(context, cred->keytab);
6977c478bd9Sstevel@tonic-gate       if (cred->princ)
6987c478bd9Sstevel@tonic-gate 	 krb5_free_principal(context, cred->princ);
699ab9b2e15Sgtb       k5_mutex_destroy(&cred->lock);
7007c478bd9Sstevel@tonic-gate       xfree(cred);
7017c478bd9Sstevel@tonic-gate       *minor_status = (OM_uint32) G_VALIDATE_FAILED;
7025e01956fSGlenn Barry       save_error_string(*minor_status, "error saving credentials");
703ab9b2e15Sgtb       krb5_free_context(context);
7047c478bd9Sstevel@tonic-gate       return(GSS_S_FAILURE);
7057c478bd9Sstevel@tonic-gate    }
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate    /* return success */
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate    *minor_status = 0;
7107c478bd9Sstevel@tonic-gate    *output_cred_handle = (gss_cred_id_t) cred;
7117c478bd9Sstevel@tonic-gate    if (actual_mechs)
7127c478bd9Sstevel@tonic-gate       *actual_mechs = ret_mechs;
713ab9b2e15Sgtb 
714ab9b2e15Sgtb    krb5_free_context(context);
7157c478bd9Sstevel@tonic-gate    return(GSS_S_COMPLETE);
7167c478bd9Sstevel@tonic-gate }
717