1 /* 2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * lib/krb5/krb/get_in_tkt.c 6 * 7 * Copyright 1995 by the Massachusetts Institute of Technology. 8 * All Rights Reserved. 9 * 10 * Export of this software from the United States of America may 11 * require a specific license from the United States Government. 12 * It is the responsibility of any person or organization contemplating 13 * export to obtain such a license before exporting. 14 * 15 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 16 * distribute this software and its documentation for any purpose and 17 * without fee is hereby granted, provided that the above copyright 18 * notice appear in all copies and that both that copyright notice and 19 * this permission notice appear in supporting documentation, and that 20 * the name of M.I.T. not be used in advertising or publicity pertaining 21 * to distribution of the software without specific, written prior 22 * permission. Furthermore if you modify this software you must label 23 * your software as modified software and not distribute it in such a 24 * fashion that it might be confused with the original M.I.T. software. 25 * M.I.T. makes no representations about the suitability of 26 * this software for any purpose. It is provided "as is" without express 27 * or implied warranty. 28 */ 29 30 #include "k5-int.h" 31 #ifdef HAVE_MEMORY_H 32 #include <memory.h> 33 #endif 34 #include <locale.h> 35 36 /* helper function: convert flags to necessary KDC options */ 37 #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK) 38 39 /* Get a TGT for use at the remote host */ 40 krb5_error_code KRB5_CALLCONV 41 krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, char *rhost, krb5_principal client, krb5_principal server, krb5_ccache cc, int forwardable, krb5_data *outbuf) 42 43 44 45 46 47 48 /* Should forwarded TGT also be forwardable? */ 49 50 { 51 krb5_replay_data replaydata; 52 krb5_data * scratch = 0; 53 krb5_address **addrs = NULL; 54 krb5_error_code retval; 55 krb5_creds creds, tgt; 56 krb5_creds *pcreds; 57 krb5_flags kdcoptions; 58 int close_cc = 0; 59 int free_rhost = 0; 60 krb5_enctype enctype = 0; 61 krb5_keyblock *session_key; 62 krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes; 63 64 memset((char *)&creds, 0, sizeof(creds)); 65 memset((char *)&tgt, 0, sizeof(creds)); 66 67 if (cc == 0) { 68 if ((retval = krb5int_cc_default(context, &cc))) 69 goto errout; 70 close_cc = 1; 71 } 72 retval = krb5_auth_con_getkey (context, auth_context, &session_key); 73 if (retval) 74 goto errout; 75 if (session_key) { 76 enctype = session_key->enctype; 77 krb5_free_keyblock (context, session_key); 78 session_key = NULL; 79 } else if (server) { /* must server be non-NULL when rhost is given? */ 80 /* Try getting credentials to see what the remote side supports. 81 Not bulletproof, just a heuristic. */ 82 krb5_creds in, *out = 0; 83 memset (&in, 0, sizeof(in)); 84 85 retval = krb5_copy_principal (context, server, &in.server); 86 if (retval) 87 goto punt; 88 retval = krb5_copy_principal (context, client, &in.client); 89 if (retval) 90 goto punt; 91 retval = krb5_get_credentials (context, 0, cc, &in, &out); 92 if (retval) 93 goto punt; 94 /* Got the credentials. Okay, now record the enctype and 95 throw them away. */ 96 enctype = out->keyblock.enctype; 97 krb5_free_creds (context, out); 98 punt: 99 krb5_free_cred_contents (context, &in); 100 } 101 102 if ((retval = krb5_copy_principal(context, client, &creds.client))) 103 goto errout; 104 105 if ((retval = krb5_build_principal_ext(context, &creds.server, 106 client->realm.length, 107 client->realm.data, 108 KRB5_TGS_NAME_SIZE, 109 KRB5_TGS_NAME, 110 client->realm.length, 111 client->realm.data, 112 0))) 113 goto errout; 114 115 /* fetch tgt directly from cache */ 116 context->use_conf_ktypes = 1; 117 retval = krb5_cc_retrieve_cred (context, cc, KRB5_TC_SUPPORTED_KTYPES, 118 &creds, &tgt); 119 context->use_conf_ktypes = old_use_conf_ktypes; 120 if (retval) 121 goto errout; 122 123 /* tgt->client must be equal to creds.client */ 124 if (!krb5_principal_compare(context, tgt.client, creds.client)) { 125 /* Solaris Kerberos */ 126 char *r_name = NULL; 127 char *t_name = NULL; 128 krb5_error_code r_err, t_err; 129 t_err = krb5_unparse_name(context, tgt.client, &t_name); 130 r_err = krb5_unparse_name(context, creds.client, &r_name); 131 krb5_set_error_message(context, KRB5_PRINC_NOMATCH, 132 dgettext(TEXT_DOMAIN, 133 "Requested principal and ticket don't match: Requested principal is '%s' and TGT principal is '%s'"), 134 r_err ? "unknown" : r_name, 135 t_err ? "unknown" : t_name); 136 if (r_name) 137 krb5_free_unparsed_name(context, r_name); 138 if (t_name) 139 krb5_free_unparsed_name(context, t_name); 140 retval = KRB5_PRINC_NOMATCH; 141 goto errout; 142 } 143 144 if (!tgt.ticket.length) { 145 retval = KRB5_NO_TKT_SUPPLIED; 146 goto errout; 147 } 148 149 if (tgt.addresses && *tgt.addresses) { 150 if (rhost == NULL) { 151 if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) { 152 retval = KRB5_FWD_BAD_PRINCIPAL; 153 goto errout; 154 } 155 156 if (krb5_princ_size(context, server) < 2){ 157 retval = KRB5_CC_BADNAME; 158 goto errout; 159 } 160 161 rhost = malloc(server->data[1].length+1); 162 if (!rhost) { 163 retval = ENOMEM; 164 goto errout; 165 } 166 free_rhost = 1; 167 /* Solaris Kerberos */ 168 (void) memcpy(rhost, server->data[1].data, server->data[1].length); 169 rhost[server->data[1].length] = '\0'; 170 } 171 172 retval = krb5_os_hostaddr(context, rhost, &addrs); 173 if (retval) 174 goto errout; 175 } 176 177 creds.keyblock.enctype = enctype; 178 creds.times = tgt.times; 179 creds.times.starttime = 0; 180 kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED; 181 182 if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */ 183 kdcoptions &= ~(KDC_OPT_FORWARDABLE); 184 185 if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, 186 addrs, &creds, &pcreds))) { 187 if (enctype) { 188 creds.keyblock.enctype = 0; 189 if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, 190 addrs, &creds, &pcreds))) 191 goto errout; 192 } 193 else goto errout; 194 } 195 retval = krb5_mk_1cred(context, auth_context, pcreds, 196 &scratch, &replaydata); 197 krb5_free_creds(context, pcreds); 198 199 /* 200 * Solaris Kerberos: changed this logic from the MIT 1.2.1 version to be 201 * more robust. 202 */ 203 if (scratch) { 204 if (retval) 205 krb5_free_data(context, scratch); 206 else { 207 *outbuf = *scratch; 208 krb5_xfree(scratch); 209 } 210 } 211 212 errout: 213 if (addrs) 214 krb5_free_addresses(context, addrs); 215 /* Solaris Kerberos */ 216 if (close_cc) 217 (void) krb5_cc_close(context, cc); 218 if (free_rhost) 219 free(rhost); 220 krb5_free_cred_contents(context, &creds); 221 krb5_free_cred_contents(context, &tgt); 222 return retval; 223 } 224