1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 7 /* 8 * lib/krb5/krb/gic_keytab.c 9 * 10 * Copyright (C) 2002, 2003 by the Massachusetts Institute of Technology. 11 * All rights reserved. 12 * 13 * Export of this software from the United States of America may 14 * require a specific license from the United States Government. 15 * It is the responsibility of any person or organization contemplating 16 * export to obtain such a license before exporting. 17 * 18 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 19 * distribute this software and its documentation for any purpose and 20 * without fee is hereby granted, provided that the above copyright 21 * notice appear in all copies and that both that copyright notice and 22 * this permission notice appear in supporting documentation, and that 23 * the name of M.I.T. not be used in advertising or publicity pertaining 24 * to distribution of the software without specific, written prior 25 * permission. Furthermore if you modify this software you must label 26 * your software as modified software and not distribute it in such a 27 * fashion that it might be confused with the original M.I.T. software. 28 * M.I.T. makes no representations about the suitability of 29 * this software for any purpose. It is provided "as is" without express 30 * or implied warranty. 31 */ 32 33 #include "k5-int.h" 34 35 /*ARGSUSED*/ 36 static krb5_error_code 37 krb5_get_as_key_keytab( 38 krb5_context context, 39 krb5_principal client, 40 krb5_enctype etype, 41 krb5_prompter_fct prompter, 42 void *prompter_data, 43 krb5_data *salt, 44 krb5_data *params, 45 krb5_keyblock *as_key, 46 void *gak_data) 47 { 48 krb5_keytab keytab = (krb5_keytab) gak_data; 49 krb5_error_code ret; 50 krb5_keytab_entry kt_ent; 51 krb5_keyblock *kt_key; 52 53 /* if there's already a key of the correct etype, we're done. 54 if the etype is wrong, free the existing key, and make 55 a new one. */ 56 57 if (as_key->length) { 58 if (as_key->enctype == etype) 59 return(0); 60 61 krb5_free_keyblock_contents(context, as_key); 62 as_key->length = 0; 63 } 64 65 if (!krb5_c_valid_enctype(etype)) 66 return(KRB5_PROG_ETYPE_NOSUPP); 67 68 /* Solaris Kerberos */ 69 if ((ret = krb5_kt_get_entry(context, keytab, client, 70 0, /* don't have vno available */ 71 etype, &kt_ent)) != NULL) 72 return(ret); 73 74 ret = krb5_copy_keyblock(context, &kt_ent.key, &kt_key); 75 76 /* again, krb5's memory management is lame... */ 77 78 *as_key = *kt_key; 79 krb5_xfree(kt_key); 80 81 (void) krb5_kt_free_entry(context, &kt_ent); 82 83 return(ret); 84 } 85 86 krb5_error_code KRB5_CALLCONV 87 krb5_get_init_creds_keytab(krb5_context context, 88 krb5_creds *creds, 89 krb5_principal client, 90 krb5_keytab arg_keytab, 91 krb5_deltat start_time, 92 char *in_tkt_service, 93 krb5_get_init_creds_opt *options) 94 { 95 krb5_error_code ret, ret2; 96 int use_master; 97 krb5_keytab keytab; 98 krb5_gic_opt_ext *opte = NULL; 99 100 if (arg_keytab == NULL) { 101 if ((ret = krb5_kt_default(context, &keytab))) 102 return ret; 103 } else { 104 keytab = arg_keytab; 105 } 106 107 ret = krb5int_gic_opt_to_opte(context, options, &opte, 1, 108 "krb5_get_init_creds_keytab"); 109 if (ret) 110 return ret; 111 112 use_master = 0; 113 114 /* first try: get the requested tkt from any kdc */ 115 116 ret = krb5_get_init_creds(context, creds, client, NULL, NULL, 117 start_time, in_tkt_service, opte, 118 krb5_get_as_key_keytab, (void *) keytab, 119 &use_master,NULL); 120 121 /* check for success */ 122 123 if (ret == 0) 124 goto cleanup; 125 126 /* If all the kdc's are unavailable fail */ 127 128 if ((ret == KRB5_KDC_UNREACH) || (ret == KRB5_REALM_CANT_RESOLVE)) 129 goto cleanup; 130 131 /* if the reply did not come from the master kdc, try again with 132 the master kdc */ 133 134 if (!use_master) { 135 use_master = 1; 136 137 ret2 = krb5_get_init_creds(context, creds, client, NULL, NULL, 138 start_time, in_tkt_service, opte, 139 krb5_get_as_key_keytab, (void *) keytab, 140 &use_master, NULL); 141 142 if (ret2 == 0) { 143 ret = 0; 144 goto cleanup; 145 } 146 147 /* if the master is unreachable, return the error from the 148 slave we were able to contact */ 149 150 if ((ret2 == KRB5_KDC_UNREACH) || 151 (ret2 == KRB5_REALM_CANT_RESOLVE) || 152 (ret2 == KRB5_REALM_UNKNOWN)) 153 goto cleanup; 154 155 ret = ret2; 156 } 157 158 /* at this point, we have a response from the master. Since we don't 159 do any prompting or changing for keytabs, that's it. */ 160 161 cleanup: 162 if (opte && krb5_gic_opt_is_shadowed(opte)) 163 krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte); 164 if (arg_keytab == NULL) 165 (void) krb5_kt_close(context, keytab); /* Solaris Kerberos */ 166 167 return(ret); 168 } 169 krb5_error_code KRB5_CALLCONV 170 krb5_get_in_tkt_with_keytab(krb5_context context, krb5_flags options, 171 krb5_address *const *addrs, krb5_enctype *ktypes, 172 krb5_preauthtype *pre_auth_types, 173 krb5_keytab arg_keytab, krb5_ccache ccache, 174 krb5_creds *creds, krb5_kdc_rep **ret_as_reply) 175 { 176 krb5_error_code retval; 177 krb5_gic_opt_ext *opte; 178 char * server = NULL; 179 krb5_keytab keytab; 180 krb5_principal client_princ, server_princ; 181 int use_master = 0; 182 183 retval = krb5int_populate_gic_opt(context, &opte, 184 options, addrs, ktypes, 185 pre_auth_types, creds); 186 if (retval) 187 return retval; 188 189 if (arg_keytab == NULL) { 190 retval = krb5_kt_default(context, &keytab); 191 if (retval) 192 return retval; 193 } 194 else keytab = arg_keytab; 195 196 retval = krb5_unparse_name( context, creds->server, &server); 197 if (retval) 198 goto cleanup; 199 server_princ = creds->server; 200 client_princ = creds->client; 201 retval = krb5_get_init_creds (context, 202 creds, creds->client, 203 krb5_prompter_posix, NULL, 204 0, server, opte, 205 krb5_get_as_key_keytab, (void *)keytab, 206 &use_master, ret_as_reply); 207 krb5_free_unparsed_name( context, server); 208 krb5_get_init_creds_opt_free(context, (krb5_get_init_creds_opt *)opte); 209 if (retval) { 210 goto cleanup; 211 } 212 if (creds->server) 213 krb5_free_principal( context, creds->server); 214 if (creds->client) 215 krb5_free_principal( context, creds->client); 216 creds->client = client_princ; 217 creds->server = server_princ; 218 219 /* store it in the ccache! */ 220 if (ccache) 221 if ((retval = krb5_cc_store_cred(context, ccache, creds))) 222 goto cleanup; 223 cleanup: if (arg_keytab == NULL) 224 krb5_kt_close(context, keytab); 225 return retval; 226 } 227 228