10Sstevel@tonic-gate /*
2*13132SGlenn.Barry@oracle.com * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
30Sstevel@tonic-gate */
40Sstevel@tonic-gate /*
50Sstevel@tonic-gate * Copyright 2000 by the Massachusetts Institute of Technology.
60Sstevel@tonic-gate * All Rights Reserved.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * Export of this software from the United States of America may
90Sstevel@tonic-gate * require a specific license from the United States Government.
100Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating
110Sstevel@tonic-gate * export to obtain such a license before exporting.
125053Sgtb *
130Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
140Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
150Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
160Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
170Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
180Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining
190Sstevel@tonic-gate * to distribution of the software without specific, written prior
200Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label
210Sstevel@tonic-gate * your software as modified software and not distribute it in such a
220Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
230Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of
240Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
250Sstevel@tonic-gate * or implied warranty.
265053Sgtb *
270Sstevel@tonic-gate */
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * Copyright 1993 by OpenVision Technologies, Inc.
305053Sgtb *
310Sstevel@tonic-gate * Permission to use, copy, modify, distribute, and sell this software
320Sstevel@tonic-gate * and its documentation for any purpose is hereby granted without fee,
330Sstevel@tonic-gate * provided that the above copyright notice appears in all copies and
340Sstevel@tonic-gate * that both that copyright notice and this permission notice appear in
350Sstevel@tonic-gate * supporting documentation, and that the name of OpenVision not be used
360Sstevel@tonic-gate * in advertising or publicity pertaining to distribution of the software
370Sstevel@tonic-gate * without specific, written prior permission. OpenVision makes no
380Sstevel@tonic-gate * representations about the suitability of this software for any
390Sstevel@tonic-gate * purpose. It is provided "as is" without express or implied warranty.
405053Sgtb *
410Sstevel@tonic-gate * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
420Sstevel@tonic-gate * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
430Sstevel@tonic-gate * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
440Sstevel@tonic-gate * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
450Sstevel@tonic-gate * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
460Sstevel@tonic-gate * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
470Sstevel@tonic-gate * PERFORMANCE OF THIS SOFTWARE.
480Sstevel@tonic-gate */
490Sstevel@tonic-gate
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate * Copyright (C) 1998 by the FundsXpress, INC.
525053Sgtb *
530Sstevel@tonic-gate * All rights reserved.
545053Sgtb *
550Sstevel@tonic-gate * Export of this software from the United States of America may require
560Sstevel@tonic-gate * a specific license from the United States Government. It is the
570Sstevel@tonic-gate * responsibility of any person or organization contemplating export to
580Sstevel@tonic-gate * obtain such a license before exporting.
595053Sgtb *
600Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
610Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
620Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
630Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
640Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
650Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining
660Sstevel@tonic-gate * to distribution of the software without specific, written prior
670Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of
680Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
690Sstevel@tonic-gate * or implied warranty.
705053Sgtb *
710Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
720Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
730Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
740Sstevel@tonic-gate */
750Sstevel@tonic-gate
765053Sgtb #include "k5-int.h"
775053Sgtb #include "gss_libinit.h"
785053Sgtb #include "gssapiP_krb5.h"
795053Sgtb #include "mglueP.h"
800Sstevel@tonic-gate #ifdef HAVE_STRING_H
810Sstevel@tonic-gate #include <string.h>
820Sstevel@tonic-gate #else
830Sstevel@tonic-gate #include <strings.h>
840Sstevel@tonic-gate #endif
85*13132SGlenn.Barry@oracle.com #include <syslog.h>
86*13132SGlenn.Barry@oracle.com #include <locale.h> /* Solaris Kerberos */
87*13132SGlenn.Barry@oracle.com #include "file/ktfile.h" /* Solaris Kerberos */
880Sstevel@tonic-gate
895053Sgtb #if defined(USE_LOGIN_LIBRARY)
905053Sgtb #include <Kerberos/KerberosLoginPrivate.h>
915053Sgtb #elif defined(USE_LEASH)
927934SMark.Phalan@Sun.COM #ifdef _WIN64
937934SMark.Phalan@Sun.COM #define LEASH_DLL "leashw64.dll"
947934SMark.Phalan@Sun.COM #else
957934SMark.Phalan@Sun.COM #define LEASH_DLL "leashw32.dll"
967934SMark.Phalan@Sun.COM #endif
975053Sgtb static void (*pLeash_AcquireInitialTicketsIfNeeded)(krb5_context,krb5_principal,char*,int) = NULL;
985053Sgtb static HANDLE hLeashDLL = INVALID_HANDLE_VALUE;
995053Sgtb #endif
1005053Sgtb
1015053Sgtb k5_mutex_t gssint_krb5_keytab_lock = K5_MUTEX_PARTIAL_INITIALIZER;
1025053Sgtb static char *krb5_gss_keytab = NULL;
1035053Sgtb
1045053Sgtb /* Heimdal calls this gsskrb5_register_acceptor_identity. */
1055053Sgtb OM_uint32 KRB5_CALLCONV
krb5_gss_register_acceptor_identity(const char * keytab)1065053Sgtb krb5_gss_register_acceptor_identity(const char *keytab)
1075053Sgtb {
1085053Sgtb size_t len;
1095053Sgtb char *new, *old;
1105053Sgtb int err;
1115053Sgtb
1125053Sgtb err = gssint_initialize_library();
1135053Sgtb if (err != 0)
1145053Sgtb return GSS_S_FAILURE;
1155053Sgtb
1165053Sgtb if (keytab == NULL)
1175053Sgtb return GSS_S_FAILURE;
1185053Sgtb
1195053Sgtb len = strlen(keytab);
1205053Sgtb new = malloc(len + 1);
1215053Sgtb if (new == NULL)
1225053Sgtb return GSS_S_FAILURE;
1235053Sgtb strcpy(new, keytab);
1245053Sgtb
1255053Sgtb err = k5_mutex_lock(&gssint_krb5_keytab_lock);
1265053Sgtb if (err) {
1275053Sgtb free(new);
1285053Sgtb return GSS_S_FAILURE;
1295053Sgtb }
1305053Sgtb old = krb5_gss_keytab;
1315053Sgtb krb5_gss_keytab = new;
1325053Sgtb k5_mutex_unlock(&gssint_krb5_keytab_lock);
1335053Sgtb if (old != NULL)
1345053Sgtb free(old);
1355053Sgtb return GSS_S_COMPLETE;
1365053Sgtb }
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate /* get credentials corresponding to a key in the krb5 keytab.
1390Sstevel@tonic-gate If the default name is requested, return the name in output_princ.
1400Sstevel@tonic-gate If output_princ is non-NULL, the caller will use or free it, regardless
1410Sstevel@tonic-gate of the return value.
1420Sstevel@tonic-gate If successful, set the keytab-specific fields in cred
1430Sstevel@tonic-gate */
1440Sstevel@tonic-gate
1455053Sgtb static OM_uint32
acquire_accept_cred(context,minor_status,desired_name,output_princ,cred)1460Sstevel@tonic-gate acquire_accept_cred(context, minor_status, desired_name, output_princ, cred)
1470Sstevel@tonic-gate krb5_context context;
1480Sstevel@tonic-gate OM_uint32 *minor_status;
1490Sstevel@tonic-gate gss_name_t desired_name;
1500Sstevel@tonic-gate krb5_principal *output_princ;
1510Sstevel@tonic-gate krb5_gss_cred_id_rec *cred;
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate krb5_error_code code;
1540Sstevel@tonic-gate krb5_principal princ;
1550Sstevel@tonic-gate krb5_keytab kt;
1560Sstevel@tonic-gate krb5_keytab_entry entry;
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate *output_princ = NULL;
1590Sstevel@tonic-gate cred->keytab = NULL;
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate /* open the default keytab */
1620Sstevel@tonic-gate
1635053Sgtb code = gssint_initialize_library();
1645053Sgtb if (code != 0) {
1655053Sgtb *minor_status = code;
1665053Sgtb return GSS_S_FAILURE;
1675053Sgtb }
1685053Sgtb code = k5_mutex_lock(&gssint_krb5_keytab_lock);
1695053Sgtb if (code) {
1705053Sgtb *minor_status = code;
1715053Sgtb return GSS_S_FAILURE;
1725053Sgtb }
1735053Sgtb if (krb5_gss_keytab != NULL) {
1745053Sgtb code = krb5_kt_resolve(context, krb5_gss_keytab, &kt);
1755053Sgtb k5_mutex_unlock(&gssint_krb5_keytab_lock);
1765053Sgtb } else {
1775053Sgtb k5_mutex_unlock(&gssint_krb5_keytab_lock);
1785053Sgtb code = krb5_kt_default(context, &kt);
1795053Sgtb }
1805053Sgtb
1815053Sgtb if (code) {
1820Sstevel@tonic-gate *minor_status = code;
1835053Sgtb /* Solaris Kerb NOTE: GSS_S_CRED_UNAVAIL is not RFC 2743 compliant */
1840Sstevel@tonic-gate return(GSS_S_NO_CRED);
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate
187*13132SGlenn.Barry@oracle.com if (desired_name != GSS_C_NO_NAME) {
188*13132SGlenn.Barry@oracle.com princ = (krb5_principal) desired_name;
189*13132SGlenn.Barry@oracle.com if ((code = krb5_kt_get_entry(context, kt, princ, 0, 0, &entry))) {
190*13132SGlenn.Barry@oracle.com if (code == KRB5_KT_NOTFOUND) {
191*13132SGlenn.Barry@oracle.com char *s_name;
192*13132SGlenn.Barry@oracle.com if (krb5_unparse_name(context, princ, &s_name) == 0) {
193*13132SGlenn.Barry@oracle.com krb5_set_error_message(context, KG_KEYTAB_NOMATCH,
194*13132SGlenn.Barry@oracle.com dgettext(TEXT_DOMAIN,
195*13132SGlenn.Barry@oracle.com "No principal in keytab ('%s') matches desired name %s"),
196*13132SGlenn.Barry@oracle.com KTFILENAME(kt),
197*13132SGlenn.Barry@oracle.com s_name);
198*13132SGlenn.Barry@oracle.com krb5_free_unparsed_name(context, s_name);
199*13132SGlenn.Barry@oracle.com }
200*13132SGlenn.Barry@oracle.com *minor_status = KG_KEYTAB_NOMATCH;
201*13132SGlenn.Barry@oracle.com } else
202*13132SGlenn.Barry@oracle.com *minor_status = code;
2035053Sgtb /* Solaris Kerb NOTE: GSS_S_CRED_UNAVAIL is not RFC 2743 compliant */
204*13132SGlenn.Barry@oracle.com (void) krb5_kt_close(context, kt);
205*13132SGlenn.Barry@oracle.com return(GSS_S_NO_CRED);
206*13132SGlenn.Barry@oracle.com }
207*13132SGlenn.Barry@oracle.com krb5_kt_free_entry(context, &entry);
2080Sstevel@tonic-gate
2093376Smp153739 /* Open the replay cache for this principal. */
2103376Smp153739 if ((code = krb5_get_server_rcache(context,
2113376Smp153739 krb5_princ_component(context, princ, 0),
2123376Smp153739 &cred->rcache))) {
2130Sstevel@tonic-gate *minor_status = code;
2140Sstevel@tonic-gate return(GSS_S_FAILURE);
2150Sstevel@tonic-gate }
2163376Smp153739
217*13132SGlenn.Barry@oracle.com }
2180Sstevel@tonic-gate
2195053Sgtb /* hooray. we made it */
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate cred->keytab = kt;
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate return(GSS_S_COMPLETE);
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate /* get credentials corresponding to the default credential cache.
2270Sstevel@tonic-gate If the default name is requested, return the name in output_princ.
2280Sstevel@tonic-gate If output_princ is non-NULL, the caller will use or free it, regardless
2290Sstevel@tonic-gate of the return value.
2300Sstevel@tonic-gate If successful, set the ccache-specific fields in cred.
2310Sstevel@tonic-gate */
2320Sstevel@tonic-gate
2335053Sgtb static OM_uint32
acquire_init_cred(context,minor_status,desired_name,output_princ,cred)2340Sstevel@tonic-gate acquire_init_cred(context, minor_status, desired_name, output_princ, cred)
2350Sstevel@tonic-gate krb5_context context;
2360Sstevel@tonic-gate OM_uint32 *minor_status;
2370Sstevel@tonic-gate gss_name_t desired_name;
2380Sstevel@tonic-gate krb5_principal *output_princ;
2390Sstevel@tonic-gate krb5_gss_cred_id_rec *cred;
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate krb5_error_code code;
2420Sstevel@tonic-gate krb5_ccache ccache;
2430Sstevel@tonic-gate krb5_principal princ, tmp_princ;
2440Sstevel@tonic-gate krb5_flags flags;
2450Sstevel@tonic-gate krb5_cc_cursor cur;
2460Sstevel@tonic-gate krb5_creds creds;
2470Sstevel@tonic-gate int got_endtime;
2487934SMark.Phalan@Sun.COM int caller_provided_ccache_name = 0;
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate cred->ccache = NULL;
2510Sstevel@tonic-gate
252781Sgtb /* load the GSS ccache name into the kg_context */
2535053Sgtb
254781Sgtb if (GSS_ERROR(kg_sync_ccache_name(context, minor_status)))
255781Sgtb return(GSS_S_FAILURE);
2560Sstevel@tonic-gate
2577934SMark.Phalan@Sun.COM /* check to see if the caller provided a ccache name if so
2587934SMark.Phalan@Sun.COM * we will just use that and not search the cache collection */
2597934SMark.Phalan@Sun.COM if (GSS_ERROR(kg_caller_provided_ccache_name (minor_status, &caller_provided_ccache_name))) {
2607934SMark.Phalan@Sun.COM return(GSS_S_FAILURE);
2617934SMark.Phalan@Sun.COM }
2627934SMark.Phalan@Sun.COM
2635053Sgtb #if defined(USE_LOGIN_LIBRARY) || defined(USE_LEASH)
2647934SMark.Phalan@Sun.COM if (desired_name && !caller_provided_ccache_name) {
2655053Sgtb #if defined(USE_LOGIN_LIBRARY)
2667934SMark.Phalan@Sun.COM KLStatus err = klNoErr;
2675053Sgtb char *ccache_name = NULL;
2685053Sgtb KLPrincipal kl_desired_princ = NULL;
2697934SMark.Phalan@Sun.COM
2707934SMark.Phalan@Sun.COM err = __KLCreatePrincipalFromKerberos5Principal ((krb5_principal) desired_name,
2717934SMark.Phalan@Sun.COM &kl_desired_princ);
2725053Sgtb
2737934SMark.Phalan@Sun.COM if (!err) {
2747934SMark.Phalan@Sun.COM err = KLAcquireInitialTickets (kl_desired_princ, NULL, NULL, &ccache_name);
2757934SMark.Phalan@Sun.COM }
2767934SMark.Phalan@Sun.COM
2777934SMark.Phalan@Sun.COM if (!err) {
2787934SMark.Phalan@Sun.COM err = krb5_cc_resolve (context, ccache_name, &ccache);
2795053Sgtb }
2805053Sgtb
2817934SMark.Phalan@Sun.COM if (err) {
2827934SMark.Phalan@Sun.COM *minor_status = err;
2837934SMark.Phalan@Sun.COM return(GSS_S_CRED_UNAVAIL);
2845053Sgtb }
2855053Sgtb
2865053Sgtb if (kl_desired_princ != NULL) { KLDisposePrincipal (kl_desired_princ); }
2875053Sgtb if (ccache_name != NULL) { KLDisposeString (ccache_name); }
2887934SMark.Phalan@Sun.COM
2895053Sgtb #elif defined(USE_LEASH)
2905053Sgtb if ( hLeashDLL == INVALID_HANDLE_VALUE ) {
2917934SMark.Phalan@Sun.COM hLeashDLL = LoadLibrary(LEASH_DLL);
2925053Sgtb if ( hLeashDLL != INVALID_HANDLE_VALUE ) {
2935053Sgtb (FARPROC) pLeash_AcquireInitialTicketsIfNeeded =
2945053Sgtb GetProcAddress(hLeashDLL, "not_an_API_Leash_AcquireInitialTicketsIfNeeded");
2955053Sgtb }
2965053Sgtb }
2975053Sgtb
2985053Sgtb if ( pLeash_AcquireInitialTicketsIfNeeded ) {
2995053Sgtb char ccname[256]="";
3005053Sgtb pLeash_AcquireInitialTicketsIfNeeded(context, (krb5_principal) desired_name, ccname, sizeof(ccname));
3015053Sgtb if (!ccname[0]) {
3025053Sgtb *minor_status = KRB5_CC_NOTFOUND;
3035053Sgtb return(GSS_S_NO_CRED);
3045053Sgtb }
3055053Sgtb
3065053Sgtb if ((code = krb5_cc_resolve (context, ccname, &ccache))) {
3075053Sgtb *minor_status = code;
3085053Sgtb return(GSS_S_NO_CRED);
3095053Sgtb }
3105053Sgtb } else {
3115053Sgtb /* leash dll not available, open the default credential cache */
3125053Sgtb
3135053Sgtb if ((code = krb5int_cc_default(context, &ccache))) {
3145053Sgtb *minor_status = code;
3155053Sgtb return(GSS_S_NO_CRED);
3165053Sgtb }
3175053Sgtb }
3185053Sgtb #endif /* USE_LEASH */
3195053Sgtb } else
3205053Sgtb #endif /* USE_LOGIN_LIBRARY || USE_LEASH */
3215053Sgtb {
3225053Sgtb /* open the default credential cache */
3235053Sgtb
3245053Sgtb if ((code = krb5int_cc_default(context, &ccache))) {
3255053Sgtb *minor_status = code;
3265053Sgtb return(GSS_S_NO_CRED);
3275053Sgtb }
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate /* turn off OPENCLOSE mode while extensive frobbing is going on */
331781Sgtb /*
332781Sgtb * SUNW14resync
333781Sgtb * Added calls to krb5_cc_set_flags(... KRB5_TC_OPENCLOSE)
334781Sgtb * on the error returns cuz the 1.4 krb5_cc_close does not always close
335781Sgtb * the file like it used to and caused STC test gss.27 to fail.
336781Sgtb */
3370Sstevel@tonic-gate flags = 0; /* turns off OPENCLOSE mode */
3385053Sgtb if ((code = krb5_cc_set_flags(context, ccache, flags))) {
339781Sgtb (void)krb5_cc_close(context, ccache);
3400Sstevel@tonic-gate *minor_status = code;
3410Sstevel@tonic-gate return(GSS_S_NO_CRED);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate /* get out the principal name and see if it matches */
3450Sstevel@tonic-gate
3465053Sgtb if ((code = krb5_cc_get_principal(context, ccache, &princ))) {
3477934SMark.Phalan@Sun.COM /* Solaris Kerberos */
348781Sgtb (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
3490Sstevel@tonic-gate (void)krb5_cc_close(context, ccache);
3500Sstevel@tonic-gate *minor_status = code;
3510Sstevel@tonic-gate return(GSS_S_FAILURE);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate if (desired_name != (gss_name_t) NULL) {
3550Sstevel@tonic-gate if (! krb5_principal_compare(context, princ, (krb5_principal) desired_name)) {
3560Sstevel@tonic-gate (void)krb5_free_principal(context, princ);
3577934SMark.Phalan@Sun.COM /* Solaris Kerberos */
3585053Sgtb (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
3590Sstevel@tonic-gate (void)krb5_cc_close(context, ccache);
3600Sstevel@tonic-gate *minor_status = KG_CCACHE_NOMATCH;
3610Sstevel@tonic-gate return(GSS_S_NO_CRED);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate (void)krb5_free_principal(context, princ);
3640Sstevel@tonic-gate princ = (krb5_principal) desired_name;
3650Sstevel@tonic-gate } else {
3660Sstevel@tonic-gate *output_princ = princ;
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate /* iterate over the ccache, find the tgt */
3700Sstevel@tonic-gate
3715053Sgtb if ((code = krb5_cc_start_seq_get(context, ccache, &cur))) {
3727934SMark.Phalan@Sun.COM /* Solaris Kerberos */
373781Sgtb (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
3740Sstevel@tonic-gate (void)krb5_cc_close(context, ccache);
3750Sstevel@tonic-gate *minor_status = code;
3760Sstevel@tonic-gate return(GSS_S_FAILURE);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate /* this is hairy. If there's a tgt for the principal's local realm
3800Sstevel@tonic-gate in here, that's what we want for the expire time. But if
3810Sstevel@tonic-gate there's not, then we want to use the first key. */
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate got_endtime = 0;
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate code = krb5_build_principal_ext(context, &tmp_princ,
3860Sstevel@tonic-gate krb5_princ_realm(context, princ)->length,
3870Sstevel@tonic-gate krb5_princ_realm(context, princ)->data,
3880Sstevel@tonic-gate 6, "krbtgt",
3890Sstevel@tonic-gate krb5_princ_realm(context, princ)->length,
3900Sstevel@tonic-gate krb5_princ_realm(context, princ)->data,
3910Sstevel@tonic-gate 0);
3920Sstevel@tonic-gate if (code) {
3937934SMark.Phalan@Sun.COM /* Solaris Kerberos */
394781Sgtb (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
3950Sstevel@tonic-gate (void)krb5_cc_close(context, ccache);
3960Sstevel@tonic-gate *minor_status = code;
3970Sstevel@tonic-gate return(GSS_S_FAILURE);
3980Sstevel@tonic-gate }
3995053Sgtb while (!(code = krb5_cc_next_cred(context, ccache, &cur, &creds))) {
4000Sstevel@tonic-gate if (krb5_principal_compare(context, tmp_princ, creds.server)) {
4010Sstevel@tonic-gate cred->tgt_expire = creds.times.endtime;
4020Sstevel@tonic-gate got_endtime = 1;
4030Sstevel@tonic-gate *minor_status = 0;
4040Sstevel@tonic-gate code = 0;
4050Sstevel@tonic-gate krb5_free_cred_contents(context, &creds);
4060Sstevel@tonic-gate break;
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate if (got_endtime == 0) {
4090Sstevel@tonic-gate cred->tgt_expire = creds.times.endtime;
4100Sstevel@tonic-gate got_endtime = 1;
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate krb5_free_cred_contents(context, &creds);
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate krb5_free_principal(context, tmp_princ);
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate if (code && code != KRB5_CC_END) {
4170Sstevel@tonic-gate /* this means some error occurred reading the ccache */
4180Sstevel@tonic-gate (void)krb5_cc_end_seq_get(context, ccache, &cur);
4197934SMark.Phalan@Sun.COM /* Solaris Kerberos */
420781Sgtb (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
4210Sstevel@tonic-gate (void)krb5_cc_close(context, ccache);
4220Sstevel@tonic-gate *minor_status = code;
4230Sstevel@tonic-gate return(GSS_S_FAILURE);
4240Sstevel@tonic-gate } else if (! got_endtime) {
4250Sstevel@tonic-gate /* this means the ccache was entirely empty */
4260Sstevel@tonic-gate (void)krb5_cc_end_seq_get(context, ccache, &cur);
4277934SMark.Phalan@Sun.COM /* Solaris Kerberos */
428781Sgtb (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
4290Sstevel@tonic-gate (void)krb5_cc_close(context, ccache);
4300Sstevel@tonic-gate *minor_status = KG_EMPTY_CCACHE;
4310Sstevel@tonic-gate return(GSS_S_FAILURE);
4320Sstevel@tonic-gate } else {
4330Sstevel@tonic-gate /* this means that we found an endtime to use. */
4345053Sgtb if ((code = krb5_cc_end_seq_get(context, ccache, &cur))) {
4357934SMark.Phalan@Sun.COM /* Solaris Kerberos */
436781Sgtb (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
4370Sstevel@tonic-gate (void)krb5_cc_close(context, ccache);
4380Sstevel@tonic-gate *minor_status = code;
4390Sstevel@tonic-gate return(GSS_S_FAILURE);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */
4425053Sgtb if ((code = krb5_cc_set_flags(context, ccache, flags))) {
4430Sstevel@tonic-gate (void)krb5_cc_close(context, ccache);
4440Sstevel@tonic-gate *minor_status = code;
4450Sstevel@tonic-gate return(GSS_S_FAILURE);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate /* the credentials match and are valid */
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate cred->ccache = ccache;
4520Sstevel@tonic-gate /* minor_status is set while we are iterating over the ccache */
4530Sstevel@tonic-gate return(GSS_S_COMPLETE);
4540Sstevel@tonic-gate }
4555053Sgtb
4565053Sgtb /*ARGSUSED*/
4570Sstevel@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)4585053Sgtb krb5_gss_acquire_cred(minor_status, desired_name, time_req,
4590Sstevel@tonic-gate desired_mechs, cred_usage, output_cred_handle,
4600Sstevel@tonic-gate actual_mechs, time_rec)
4610Sstevel@tonic-gate OM_uint32 *minor_status;
4620Sstevel@tonic-gate gss_name_t desired_name;
4630Sstevel@tonic-gate OM_uint32 time_req;
4640Sstevel@tonic-gate gss_OID_set desired_mechs;
4650Sstevel@tonic-gate gss_cred_usage_t cred_usage;
4660Sstevel@tonic-gate gss_cred_id_t *output_cred_handle;
4670Sstevel@tonic-gate gss_OID_set *actual_mechs;
4680Sstevel@tonic-gate OM_uint32 *time_rec;
4690Sstevel@tonic-gate {
4700Sstevel@tonic-gate krb5_context context;
4710Sstevel@tonic-gate size_t i;
4720Sstevel@tonic-gate krb5_gss_cred_id_t cred;
4735053Sgtb gss_OID_set ret_mechs;
4740Sstevel@tonic-gate int req_old, req_new;
4750Sstevel@tonic-gate OM_uint32 ret;
4760Sstevel@tonic-gate krb5_error_code code;
4770Sstevel@tonic-gate
4785053Sgtb code = gssint_initialize_library();
4795053Sgtb if (code) {
4805053Sgtb *minor_status = code;
4815053Sgtb return GSS_S_FAILURE;
4825053Sgtb }
4830Sstevel@tonic-gate
4845053Sgtb code = krb5_gss_init_context(&context);
4855053Sgtb if (code) {
4865053Sgtb *minor_status = code;
4875053Sgtb return GSS_S_FAILURE;
4885053Sgtb }
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate /* make sure all outputs are valid */
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate *output_cred_handle = NULL;
4930Sstevel@tonic-gate if (actual_mechs)
4940Sstevel@tonic-gate *actual_mechs = NULL;
4950Sstevel@tonic-gate if (time_rec)
4960Sstevel@tonic-gate *time_rec = 0;
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate /* validate the name */
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate /*SUPPRESS 29*/
5010Sstevel@tonic-gate if ((desired_name != (gss_name_t) NULL) &&
5020Sstevel@tonic-gate (! kg_validate_name(desired_name))) {
503*13132SGlenn.Barry@oracle.com *minor_status = (OM_uint32) G_VALIDATE_FAILED;
504*13132SGlenn.Barry@oracle.com krb5_free_context(context);
505*13132SGlenn.Barry@oracle.com return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
5060Sstevel@tonic-gate }
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate /* verify that the requested mechanism set is the default, or
5090Sstevel@tonic-gate contains krb5 */
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate if (desired_mechs == GSS_C_NULL_OID_SET) {
5120Sstevel@tonic-gate req_old = 1;
5130Sstevel@tonic-gate req_new = 1;
5140Sstevel@tonic-gate } else {
5150Sstevel@tonic-gate req_old = 0;
5160Sstevel@tonic-gate req_new = 0;
5170Sstevel@tonic-gate
5180Sstevel@tonic-gate for (i=0; i<desired_mechs->count; i++) {
5190Sstevel@tonic-gate if (g_OID_equal(gss_mech_krb5_old, &(desired_mechs->elements[i])))
5200Sstevel@tonic-gate req_old++;
5210Sstevel@tonic-gate if (g_OID_equal(gss_mech_krb5, &(desired_mechs->elements[i])))
5220Sstevel@tonic-gate req_new++;
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate if (!req_old && !req_new) {
5260Sstevel@tonic-gate *minor_status = 0;
5275053Sgtb krb5_free_context(context);
5280Sstevel@tonic-gate return(GSS_S_BAD_MECH);
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate /* create the gss cred structure */
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate if ((cred =
5350Sstevel@tonic-gate (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec))) == NULL) {
5360Sstevel@tonic-gate *minor_status = ENOMEM;
5375053Sgtb krb5_free_context(context);
5380Sstevel@tonic-gate return(GSS_S_FAILURE);
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate cred->usage = cred_usage;
5430Sstevel@tonic-gate cred->princ = NULL;
5440Sstevel@tonic-gate cred->prerfc_mech = req_old;
5450Sstevel@tonic-gate cred->rfc_mech = req_new;
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate cred->keytab = NULL;
5480Sstevel@tonic-gate cred->ccache = NULL;
5490Sstevel@tonic-gate
5505053Sgtb code = k5_mutex_init(&cred->lock);
5515053Sgtb if (code) {
5525053Sgtb *minor_status = code;
5535053Sgtb krb5_free_context(context);
5545053Sgtb return GSS_S_FAILURE;
5555053Sgtb }
5565053Sgtb /* Note that we don't need to lock this GSSAPI credential record
5575053Sgtb here, because no other thread can gain access to it until we
5585053Sgtb return it. */
5595053Sgtb
5600Sstevel@tonic-gate if ((cred_usage != GSS_C_INITIATE) &&
5610Sstevel@tonic-gate (cred_usage != GSS_C_ACCEPT) &&
5620Sstevel@tonic-gate (cred_usage != GSS_C_BOTH)) {
5635053Sgtb k5_mutex_destroy(&cred->lock);
5640Sstevel@tonic-gate xfree(cred);
5650Sstevel@tonic-gate *minor_status = (OM_uint32) G_BAD_USAGE;
5665053Sgtb krb5_free_context(context);
5670Sstevel@tonic-gate return(GSS_S_FAILURE);
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate /* if requested, acquire credentials for accepting */
5710Sstevel@tonic-gate /* this will fill in cred->princ if the desired_name is not specified */
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate if ((cred_usage == GSS_C_ACCEPT) ||
5740Sstevel@tonic-gate (cred_usage == GSS_C_BOTH))
5750Sstevel@tonic-gate if ((ret = acquire_accept_cred(context, minor_status, desired_name,
5760Sstevel@tonic-gate &(cred->princ), cred))
5770Sstevel@tonic-gate != GSS_S_COMPLETE) {
5780Sstevel@tonic-gate if (cred->princ)
5790Sstevel@tonic-gate krb5_free_principal(context, cred->princ);
5805053Sgtb k5_mutex_destroy(&cred->lock);
5815053Sgtb xfree(cred);
5820Sstevel@tonic-gate /* minor_status set by acquire_accept_cred() */
583*13132SGlenn.Barry@oracle.com save_error_info(*minor_status, context);
5845053Sgtb krb5_free_context(context);
5850Sstevel@tonic-gate return(ret);
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate /* if requested, acquire credentials for initiation */
5890Sstevel@tonic-gate /* this will fill in cred->princ if it wasn't set above, and
5900Sstevel@tonic-gate the desired_name is not specified */
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate if ((cred_usage == GSS_C_INITIATE) ||
5930Sstevel@tonic-gate (cred_usage == GSS_C_BOTH))
5940Sstevel@tonic-gate if ((ret =
5950Sstevel@tonic-gate acquire_init_cred(context, minor_status,
5960Sstevel@tonic-gate cred->princ?(gss_name_t)cred->princ:desired_name,
5970Sstevel@tonic-gate &(cred->princ), cred))
5980Sstevel@tonic-gate != GSS_S_COMPLETE) {
5990Sstevel@tonic-gate if (cred->keytab)
6005053Sgtb krb5_kt_close(context, cred->keytab);
6010Sstevel@tonic-gate if (cred->princ)
6020Sstevel@tonic-gate krb5_free_principal(context, cred->princ);
6035053Sgtb k5_mutex_destroy(&cred->lock);
6045053Sgtb xfree(cred);
6050Sstevel@tonic-gate /* minor_status set by acquire_init_cred() */
606*13132SGlenn.Barry@oracle.com save_error_info(*minor_status, context);
6075053Sgtb krb5_free_context(context);
6080Sstevel@tonic-gate return(ret);
6090Sstevel@tonic-gate }
6100Sstevel@tonic-gate
6113376Smp153739 /* Solaris Kerberos:
6125053Sgtb * if the princ wasn't filled in already, fill it in now unless
6133376Smp153739 * a cred with no associated princ is requested (will invoke default
6143376Smp153739 * behaviour when gss_accept_init_context() is called).
6155053Sgtb * Note MIT 1.4 has GSS_C_NO_CREDENTIAL instead of GSS_C_NO_NAME
6163376Smp153739 */
6173376Smp153739 if (!cred->princ && (desired_name != GSS_C_NO_NAME))
6180Sstevel@tonic-gate if ((code = krb5_copy_principal(context, (krb5_principal) desired_name,
6190Sstevel@tonic-gate &(cred->princ)))) {
6200Sstevel@tonic-gate if (cred->ccache)
6210Sstevel@tonic-gate (void)krb5_cc_close(context, cred->ccache);
6220Sstevel@tonic-gate if (cred->keytab)
6230Sstevel@tonic-gate (void)krb5_kt_close(context, cred->keytab);
6245053Sgtb k5_mutex_destroy(&cred->lock);
6255053Sgtb xfree(cred);
6260Sstevel@tonic-gate *minor_status = code;
627*13132SGlenn.Barry@oracle.com save_error_info(*minor_status, context);
6285053Sgtb krb5_free_context(context);
6290Sstevel@tonic-gate return(GSS_S_FAILURE);
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate /*** at this point, the cred structure has been completely created */
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate /* compute time_rec */
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate if (cred_usage == GSS_C_ACCEPT) {
6370Sstevel@tonic-gate if (time_rec)
6380Sstevel@tonic-gate *time_rec = GSS_C_INDEFINITE;
6390Sstevel@tonic-gate } else {
6400Sstevel@tonic-gate krb5_timestamp now;
6410Sstevel@tonic-gate
6420Sstevel@tonic-gate if ((code = krb5_timeofday(context, &now))) {
6430Sstevel@tonic-gate if (cred->ccache)
6440Sstevel@tonic-gate (void)krb5_cc_close(context, cred->ccache);
6450Sstevel@tonic-gate if (cred->keytab)
6460Sstevel@tonic-gate (void)krb5_kt_close(context, cred->keytab);
6470Sstevel@tonic-gate if (cred->princ)
6480Sstevel@tonic-gate krb5_free_principal(context, cred->princ);
6495053Sgtb k5_mutex_destroy(&cred->lock);
6505053Sgtb xfree(cred);
6510Sstevel@tonic-gate *minor_status = code;
652*13132SGlenn.Barry@oracle.com save_error_info(*minor_status, context);
6535053Sgtb krb5_free_context(context);
6540Sstevel@tonic-gate return(GSS_S_FAILURE);
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate if (time_rec)
6580Sstevel@tonic-gate *time_rec = (cred->tgt_expire > now) ? (cred->tgt_expire - now) : 0;
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate /* create mechs */
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate if (actual_mechs) {
6645053Sgtb if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status,
6650Sstevel@tonic-gate &ret_mechs)) ||
6660Sstevel@tonic-gate (cred->prerfc_mech &&
6675053Sgtb GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
6687934SMark.Phalan@Sun.COM (const gss_OID) gss_mech_krb5_old,
6690Sstevel@tonic-gate &ret_mechs))) ||
6700Sstevel@tonic-gate (cred->rfc_mech &&
6715053Sgtb GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
6727934SMark.Phalan@Sun.COM (const gss_OID) gss_mech_krb5,
6730Sstevel@tonic-gate &ret_mechs)))) {
6740Sstevel@tonic-gate if (cred->ccache)
6750Sstevel@tonic-gate (void)krb5_cc_close(context, cred->ccache);
6760Sstevel@tonic-gate if (cred->keytab)
6770Sstevel@tonic-gate (void)krb5_kt_close(context, cred->keytab);
6780Sstevel@tonic-gate if (cred->princ)
6790Sstevel@tonic-gate krb5_free_principal(context, cred->princ);
6805053Sgtb k5_mutex_destroy(&cred->lock);
6810Sstevel@tonic-gate xfree(cred);
6825053Sgtb /* *minor_status set above */
6835053Sgtb krb5_free_context(context);
6840Sstevel@tonic-gate return(ret);
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate }
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate /* intern the credential handle */
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate if (! kg_save_cred_id((gss_cred_id_t) cred)) {
6910Sstevel@tonic-gate free(ret_mechs->elements);
6920Sstevel@tonic-gate free(ret_mechs);
6930Sstevel@tonic-gate if (cred->ccache)
6940Sstevel@tonic-gate (void)krb5_cc_close(context, cred->ccache);
6950Sstevel@tonic-gate if (cred->keytab)
6960Sstevel@tonic-gate (void)krb5_kt_close(context, cred->keytab);
6970Sstevel@tonic-gate if (cred->princ)
6980Sstevel@tonic-gate krb5_free_principal(context, cred->princ);
6995053Sgtb k5_mutex_destroy(&cred->lock);
7000Sstevel@tonic-gate xfree(cred);
7010Sstevel@tonic-gate *minor_status = (OM_uint32) G_VALIDATE_FAILED;
702*13132SGlenn.Barry@oracle.com save_error_string(*minor_status, "error saving credentials");
7035053Sgtb krb5_free_context(context);
7040Sstevel@tonic-gate return(GSS_S_FAILURE);
7050Sstevel@tonic-gate }
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate /* return success */
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate *minor_status = 0;
7100Sstevel@tonic-gate *output_cred_handle = (gss_cred_id_t) cred;
7110Sstevel@tonic-gate if (actual_mechs)
7120Sstevel@tonic-gate *actual_mechs = ret_mechs;
7135053Sgtb
7145053Sgtb krb5_free_context(context);
7150Sstevel@tonic-gate return(GSS_S_COMPLETE);
7160Sstevel@tonic-gate }
717