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