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/get_in_tkt.c 9 * 10 * Copyright 1995 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 #ifdef HAVE_MEMORY_H 35 #include <memory.h> 36 #endif 37 38 /* helper function: convert flags to necessary KDC options */ 39 #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK) 40 41 /* Get a TGT for use at the remote host */ 42 krb5_error_code KRB5_CALLCONV 43 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) 44 45 46 47 48 49 50 /* Should forwarded TGT also be forwardable? */ 51 52 { 53 krb5_replay_data replaydata; 54 krb5_data * scratch = 0; 55 krb5_address **addrs = NULL; 56 krb5_error_code retval; 57 krb5_creds creds, tgt; 58 krb5_creds *pcreds; 59 krb5_flags kdcoptions; 60 int close_cc = 0; 61 int free_rhost = 0; 62 krb5_enctype enctype = 0; 63 krb5_keyblock *session_key; 64 krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes; 65 66 memset((char *)&creds, 0, sizeof(creds)); 67 memset((char *)&tgt, 0, sizeof(creds)); 68 69 if (cc == 0) { 70 if ((retval = krb5int_cc_default(context, &cc))) 71 goto errout; 72 close_cc = 1; 73 } 74 retval = krb5_auth_con_getkey (context, auth_context, &session_key); 75 if (retval) 76 goto errout; 77 if (session_key) { 78 enctype = session_key->enctype; 79 krb5_free_keyblock (context, session_key); 80 session_key = NULL; 81 } else if (server) { /* must server be non-NULL when rhost is given? */ 82 /* Try getting credentials to see what the remote side supports. 83 Not bulletproof, just a heuristic. */ 84 krb5_creds in, *out = 0; 85 memset (&in, 0, sizeof(in)); 86 87 retval = krb5_copy_principal (context, server, &in.server); 88 if (retval) 89 goto punt; 90 retval = krb5_copy_principal (context, client, &in.client); 91 if (retval) 92 goto punt; 93 retval = krb5_get_credentials (context, 0, cc, &in, &out); 94 if (retval) 95 goto punt; 96 /* Got the credentials. Okay, now record the enctype and 97 throw them away. */ 98 enctype = out->keyblock.enctype; 99 krb5_free_creds (context, out); 100 punt: 101 krb5_free_cred_contents (context, &in); 102 } 103 104 if ((retval = krb5_copy_principal(context, client, &creds.client))) 105 goto errout; 106 107 if ((retval = krb5_build_principal_ext(context, &creds.server, 108 client->realm.length, 109 client->realm.data, 110 KRB5_TGS_NAME_SIZE, 111 KRB5_TGS_NAME, 112 client->realm.length, 113 client->realm.data, 114 0))) 115 goto errout; 116 117 /* fetch tgt directly from cache */ 118 context->use_conf_ktypes = 1; 119 retval = krb5_cc_retrieve_cred (context, cc, KRB5_TC_SUPPORTED_KTYPES, 120 &creds, &tgt); 121 context->use_conf_ktypes = old_use_conf_ktypes; 122 if (retval) 123 goto errout; 124 125 /* tgt->client must be equal to creds.client */ 126 if (!krb5_principal_compare(context, tgt.client, creds.client)) { 127 retval = KRB5_PRINC_NOMATCH; 128 goto errout; 129 } 130 131 if (!tgt.ticket.length) { 132 retval = KRB5_NO_TKT_SUPPLIED; 133 goto errout; 134 } 135 136 if (tgt.addresses && *tgt.addresses) { 137 if (rhost == NULL) { 138 if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) { 139 retval = KRB5_FWD_BAD_PRINCIPAL; 140 goto errout; 141 } 142 143 if (krb5_princ_size(context, server) < 2){ 144 retval = KRB5_CC_BADNAME; 145 goto errout; 146 } 147 148 rhost = malloc(server->data[1].length+1); 149 if (!rhost) { 150 retval = ENOMEM; 151 goto errout; 152 } 153 free_rhost = 1; 154 /* Solaris Kerberos */ 155 (void) memcpy(rhost, server->data[1].data, server->data[1].length); 156 rhost[server->data[1].length] = '\0'; 157 } 158 159 retval = krb5_os_hostaddr(context, rhost, &addrs); 160 if (retval) 161 goto errout; 162 } 163 164 creds.keyblock.enctype = enctype; 165 creds.times = tgt.times; 166 creds.times.starttime = 0; 167 kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED; 168 169 if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */ 170 kdcoptions &= ~(KDC_OPT_FORWARDABLE); 171 172 if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, 173 addrs, &creds, &pcreds))) { 174 if (enctype) { 175 creds.keyblock.enctype = 0; 176 if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, 177 addrs, &creds, &pcreds))) 178 goto errout; 179 } 180 else goto errout; 181 } 182 retval = krb5_mk_1cred(context, auth_context, pcreds, 183 &scratch, &replaydata); 184 krb5_free_creds(context, pcreds); 185 186 /* 187 * Solaris Kerberos: changed this logic from the MIT 1.2.1 version to be 188 * more robust. 189 */ 190 if (scratch) { 191 if (retval) 192 krb5_free_data(context, scratch); 193 else { 194 *outbuf = *scratch; 195 krb5_xfree(scratch); 196 } 197 } 198 199 errout: 200 if (addrs) 201 krb5_free_addresses(context, addrs); 202 /* Solaris Kerberos */ 203 if (close_cc) 204 (void) krb5_cc_close(context, cc); 205 if (free_rhost) 206 free(rhost); 207 krb5_free_cred_contents(context, &creds); 208 krb5_free_cred_contents(context, &tgt); 209 return retval; 210 } 211