17c478bd9Sstevel@tonic-gate /*
2db02be57S  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
6505d05c7Sgtb 
7505d05c7Sgtb /*
8505d05c7Sgtb  * lib/krb5/krb/gic_keytab.c
9505d05c7Sgtb  *
10505d05c7Sgtb  * Copyright (C) 2002, 2003 by the Massachusetts Institute of Technology.
11505d05c7Sgtb  * All rights reserved.
12505d05c7Sgtb  *
13505d05c7Sgtb  * Export of this software from the United States of America may
14505d05c7Sgtb  *   require a specific license from the United States Government.
15505d05c7Sgtb  *   It is the responsibility of any person or organization contemplating
16505d05c7Sgtb  *   export to obtain such a license before exporting.
17505d05c7Sgtb  *
18505d05c7Sgtb  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19505d05c7Sgtb  * distribute this software and its documentation for any purpose and
20505d05c7Sgtb  * without fee is hereby granted, provided that the above copyright
21505d05c7Sgtb  * notice appear in all copies and that both that copyright notice and
22505d05c7Sgtb  * this permission notice appear in supporting documentation, and that
23505d05c7Sgtb  * the name of M.I.T. not be used in advertising or publicity pertaining
24505d05c7Sgtb  * to distribution of the software without specific, written prior
25505d05c7Sgtb  * permission.  Furthermore if you modify this software you must label
26505d05c7Sgtb  * your software as modified software and not distribute it in such a
27505d05c7Sgtb  * fashion that it might be confused with the original M.I.T. software.
28505d05c7Sgtb  * M.I.T. makes no representations about the suitability of
29505d05c7Sgtb  * this software for any purpose.  It is provided "as is" without express
30505d05c7Sgtb  * or implied warranty.
31505d05c7Sgtb  */
32505d05c7Sgtb 
33db02be57S /* Solaris Kerberos */
34db02be57S #include <libintl.h>
35db02be57S #include <locale.h>
36db02be57S 
37159d09a2SMark Phalan #include "k5-int.h"
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*ARGSUSED*/
407c478bd9Sstevel@tonic-gate static krb5_error_code
krb5_get_as_key_keytab(krb5_context context,krb5_principal client,krb5_enctype etype,krb5_prompter_fct prompter,void * prompter_data,krb5_data * salt,krb5_data * params,krb5_keyblock * as_key,void * gak_data)417c478bd9Sstevel@tonic-gate krb5_get_as_key_keytab(
427c478bd9Sstevel@tonic-gate     krb5_context context,
437c478bd9Sstevel@tonic-gate     krb5_principal client,
447c478bd9Sstevel@tonic-gate     krb5_enctype etype,
457c478bd9Sstevel@tonic-gate     krb5_prompter_fct prompter,
467c478bd9Sstevel@tonic-gate     void *prompter_data,
477c478bd9Sstevel@tonic-gate     krb5_data *salt,
487c478bd9Sstevel@tonic-gate     krb5_data *params,
497c478bd9Sstevel@tonic-gate     krb5_keyblock *as_key,
507c478bd9Sstevel@tonic-gate     void *gak_data)
517c478bd9Sstevel@tonic-gate {
527c478bd9Sstevel@tonic-gate     krb5_keytab keytab = (krb5_keytab) gak_data;
537c478bd9Sstevel@tonic-gate     krb5_error_code ret;
547c478bd9Sstevel@tonic-gate     krb5_keytab_entry kt_ent;
557c478bd9Sstevel@tonic-gate     krb5_keyblock *kt_key;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate     /* if there's already a key of the correct etype, we're done.
587c478bd9Sstevel@tonic-gate        if the etype is wrong, free the existing key, and make
597c478bd9Sstevel@tonic-gate        a new one. */
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate     if (as_key->length) {
627c478bd9Sstevel@tonic-gate 	if (as_key->enctype == etype)
637c478bd9Sstevel@tonic-gate 	    return(0);
647c478bd9Sstevel@tonic-gate 
65505d05c7Sgtb 	krb5_free_keyblock_contents(context, as_key);
667c478bd9Sstevel@tonic-gate 	as_key->length = 0;
677c478bd9Sstevel@tonic-gate     }
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate     if (!krb5_c_valid_enctype(etype))
707c478bd9Sstevel@tonic-gate 	return(KRB5_PROG_ETYPE_NOSUPP);
717c478bd9Sstevel@tonic-gate 
72159d09a2SMark Phalan     /* Solaris Kerberos */
737c478bd9Sstevel@tonic-gate     if ((ret = krb5_kt_get_entry(context, keytab, client,
747c478bd9Sstevel@tonic-gate 				 0, /* don't have vno available */
75*940daf74SToomas Soome 				 etype, &kt_ent)) != 0)
767c478bd9Sstevel@tonic-gate 	return(ret);
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate     ret = krb5_copy_keyblock(context, &kt_ent.key, &kt_key);
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate     /* again, krb5's memory management is lame... */
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate     *as_key = *kt_key;
837c478bd9Sstevel@tonic-gate     krb5_xfree(kt_key);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate     (void) krb5_kt_free_entry(context, &kt_ent);
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate     return(ret);
887c478bd9Sstevel@tonic-gate }
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_get_init_creds_keytab(krb5_context context,krb5_creds * creds,krb5_principal client,krb5_keytab arg_keytab,krb5_deltat start_time,char * in_tkt_service,krb5_get_init_creds_opt * options)91159d09a2SMark Phalan krb5_get_init_creds_keytab(krb5_context context,
927c478bd9Sstevel@tonic-gate 			   krb5_creds *creds,
937c478bd9Sstevel@tonic-gate 			   krb5_principal client,
947c478bd9Sstevel@tonic-gate 			   krb5_keytab arg_keytab,
957c478bd9Sstevel@tonic-gate 			   krb5_deltat start_time,
967c478bd9Sstevel@tonic-gate 			   char *in_tkt_service,
977c478bd9Sstevel@tonic-gate 			   krb5_get_init_creds_opt *options)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate    krb5_error_code ret, ret2;
1007c478bd9Sstevel@tonic-gate    int use_master;
1017c478bd9Sstevel@tonic-gate    krb5_keytab keytab;
102159d09a2SMark Phalan    krb5_gic_opt_ext *opte = NULL;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate    if (arg_keytab == NULL) {
105505d05c7Sgtb        if ((ret = krb5_kt_default(context, &keytab)))
1067c478bd9Sstevel@tonic-gate 	    return ret;
1077c478bd9Sstevel@tonic-gate    } else {
1087c478bd9Sstevel@tonic-gate        keytab = arg_keytab;
1097c478bd9Sstevel@tonic-gate    }
1107c478bd9Sstevel@tonic-gate 
111159d09a2SMark Phalan    ret = krb5int_gic_opt_to_opte(context, options, &opte, 1,
112159d09a2SMark Phalan 				 "krb5_get_init_creds_keytab");
113159d09a2SMark Phalan    if (ret)
114159d09a2SMark Phalan       return ret;
115159d09a2SMark Phalan 
116db02be57S    /*
117db02be57S     * Solaris Kerberos:
118db02be57S     * If "client" was constructed from krb5_sname_to_princ() it may
119db02be57S     * have a referral realm. This happens when there is no applicable
120db02be57S     * domain-to-realm mapping in the Kerberos configuration file.
121db02be57S     * If that is the case then the realm of the first principal found
122db02be57S     * in the keytab which matches the client can be used for the client's
123db02be57S     * realm.
124db02be57S     */
125db02be57S    if (krb5_is_referral_realm(&client->realm)) {
126db02be57S 	krb5_data realm;
127db02be57S 	ret = krb5_kt_find_realm(context, keytab, client, &realm);
128db02be57S 	if (ret == 0) {
129db02be57S 		krb5_free_data_contents(context, &client->realm);
130db02be57S 		client->realm.length = realm.length;
131db02be57S 		client->realm.data = realm.data;
132db02be57S 	} else {
133db02be57S 		/* Try to set a useful error message */
134db02be57S 		char *princ = NULL;
135db02be57S 		krb5_unparse_name(context, client, &princ);
136db02be57S 
137db02be57S 		krb5_set_error_message(context, ret,
138db02be57S 		    gettext("Failed to find realm for %s in keytab"),
139db02be57S 		    princ ? princ : "<unknown>");
140db02be57S 		if (princ)
141db02be57S 			krb5_free_unparsed_name(context, princ);
142db02be57S 	}
143db02be57S    }
144db02be57S 
145db02be57S    if (ret != 0)
146db02be57S 	goto cleanup;
147db02be57S 
148db02be57S 
1497c478bd9Sstevel@tonic-gate    use_master = 0;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate    /* first try: get the requested tkt from any kdc */
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate    ret = krb5_get_init_creds(context, creds, client, NULL, NULL,
154159d09a2SMark Phalan 			     start_time, in_tkt_service, opte,
1557c478bd9Sstevel@tonic-gate 			     krb5_get_as_key_keytab, (void *) keytab,
156505d05c7Sgtb 			     &use_master,NULL);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate    /* check for success */
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate    if (ret == 0)
1617c478bd9Sstevel@tonic-gate       goto cleanup;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate    /* If all the kdc's are unavailable fail */
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate    if ((ret == KRB5_KDC_UNREACH) || (ret == KRB5_REALM_CANT_RESOLVE))
1667c478bd9Sstevel@tonic-gate       goto cleanup;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate    /* if the reply did not come from the master kdc, try again with
1697c478bd9Sstevel@tonic-gate       the master kdc */
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate    if (!use_master) {
1727c478bd9Sstevel@tonic-gate       use_master = 1;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate       ret2 = krb5_get_init_creds(context, creds, client, NULL, NULL,
175159d09a2SMark Phalan 				 start_time, in_tkt_service, opte,
1767c478bd9Sstevel@tonic-gate 				 krb5_get_as_key_keytab, (void *) keytab,
177505d05c7Sgtb 				 &use_master, NULL);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate       if (ret2 == 0) {
1807c478bd9Sstevel@tonic-gate 	 ret = 0;
1817c478bd9Sstevel@tonic-gate 	 goto cleanup;
1827c478bd9Sstevel@tonic-gate       }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate       /* if the master is unreachable, return the error from the
1857c478bd9Sstevel@tonic-gate 	 slave we were able to contact */
1867c478bd9Sstevel@tonic-gate 
187159d09a2SMark Phalan       if ((ret2 == KRB5_KDC_UNREACH) ||
188159d09a2SMark Phalan 	  (ret2 == KRB5_REALM_CANT_RESOLVE) ||
189159d09a2SMark Phalan 	  (ret2 == KRB5_REALM_UNKNOWN))
1907c478bd9Sstevel@tonic-gate 	 goto cleanup;
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate       ret = ret2;
1937c478bd9Sstevel@tonic-gate    }
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate    /* at this point, we have a response from the master.  Since we don't
1967c478bd9Sstevel@tonic-gate       do any prompting or changing for keytabs, that's it. */
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate cleanup:
199159d09a2SMark Phalan    if (opte && krb5_gic_opt_is_shadowed(opte))
200159d09a2SMark Phalan        krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
2017c478bd9Sstevel@tonic-gate    if (arg_keytab == NULL)
202159d09a2SMark Phalan        (void) krb5_kt_close(context, keytab); /* Solaris Kerberos */
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate    return(ret);
2057c478bd9Sstevel@tonic-gate }
206505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_get_in_tkt_with_keytab(krb5_context context,krb5_flags options,krb5_address * const * addrs,krb5_enctype * ktypes,krb5_preauthtype * pre_auth_types,krb5_keytab arg_keytab,krb5_ccache ccache,krb5_creds * creds,krb5_kdc_rep ** ret_as_reply)207505d05c7Sgtb krb5_get_in_tkt_with_keytab(krb5_context context, krb5_flags options,
208505d05c7Sgtb 			      krb5_address *const *addrs, krb5_enctype *ktypes,
209505d05c7Sgtb 			      krb5_preauthtype *pre_auth_types,
210505d05c7Sgtb 			      krb5_keytab arg_keytab, krb5_ccache ccache,
211505d05c7Sgtb 			      krb5_creds *creds, krb5_kdc_rep **ret_as_reply)
212505d05c7Sgtb {
213505d05c7Sgtb     krb5_error_code retval;
214159d09a2SMark Phalan     krb5_gic_opt_ext *opte;
215505d05c7Sgtb     char * server = NULL;
216505d05c7Sgtb     krb5_keytab keytab;
217505d05c7Sgtb     krb5_principal client_princ, server_princ;
218505d05c7Sgtb     int use_master = 0;
219505d05c7Sgtb 
220159d09a2SMark Phalan     retval = krb5int_populate_gic_opt(context, &opte,
221505d05c7Sgtb 				      options, addrs, ktypes,
222505d05c7Sgtb 				      pre_auth_types, creds);
223159d09a2SMark Phalan     if (retval)
224159d09a2SMark Phalan 	return retval;
225159d09a2SMark Phalan 
226505d05c7Sgtb     if (arg_keytab == NULL) {
227505d05c7Sgtb 	retval = krb5_kt_default(context, &keytab);
228505d05c7Sgtb 	if (retval)
229505d05c7Sgtb 	    return retval;
230505d05c7Sgtb     }
231505d05c7Sgtb     else keytab = arg_keytab;
232505d05c7Sgtb 
233505d05c7Sgtb     retval = krb5_unparse_name( context, creds->server, &server);
234505d05c7Sgtb     if (retval)
235505d05c7Sgtb 	goto cleanup;
236505d05c7Sgtb     server_princ = creds->server;
237505d05c7Sgtb     client_princ = creds->client;
238505d05c7Sgtb     retval = krb5_get_init_creds (context,
239505d05c7Sgtb 				  creds, creds->client,
240505d05c7Sgtb 				  krb5_prompter_posix,  NULL,
241159d09a2SMark Phalan 				  0, server, opte,
242505d05c7Sgtb 				  krb5_get_as_key_keytab, (void *)keytab,
243505d05c7Sgtb 				  &use_master, ret_as_reply);
244505d05c7Sgtb     krb5_free_unparsed_name( context, server);
245159d09a2SMark Phalan     krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte);
246505d05c7Sgtb     if (retval) {
247505d05c7Sgtb 	goto cleanup;
248505d05c7Sgtb     }
249505d05c7Sgtb 	if (creds->server)
250505d05c7Sgtb 	    krb5_free_principal( context, creds->server);
251505d05c7Sgtb 	if (creds->client)
252505d05c7Sgtb 	    krb5_free_principal( context, creds->client);
253505d05c7Sgtb 	creds->client = client_princ;
254505d05c7Sgtb 	creds->server = server_princ;
255505d05c7Sgtb 
256505d05c7Sgtb     /* store it in the ccache! */
257505d05c7Sgtb     if (ccache)
258505d05c7Sgtb 	if ((retval = krb5_cc_store_cred(context, ccache, creds)))
259505d05c7Sgtb 	    goto cleanup;
260505d05c7Sgtb  cleanup:    if (arg_keytab == NULL)
261505d05c7Sgtb      krb5_kt_close(context, keytab);
262505d05c7Sgtb     return retval;
263505d05c7Sgtb }
264159d09a2SMark Phalan 
265