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/get_in_tkt.c 10 * 11 * Copyright 1995 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 #define NEED_SOCKETS 35 #include <k5-int.h> 36 #include <memory.h> 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( 44 krb5_context context, 45 krb5_auth_context auth_context, 46 char *rhost, 47 krb5_principal client, 48 krb5_principal server, 49 krb5_ccache cc, 50 int forwardable, /* Should forwarded TGT also be forwardable? */ 51 krb5_data *outbuf) 52 { 53 krb5_replay_data replaydata; 54 krb5_data * scratch = 0; 55 krb5_address **addrs = 0; 56 krb5_error_code retval; 57 krb5_creds creds, tgt; 58 krb5_creds *pcreds = 0; 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 (void) memcpy(rhost, server->data[1].data, server->data[1].length); 155 rhost[server->data[1].length] = '\0'; 156 } 157 158 retval = krb5_os_hostaddr(context, rhost, &addrs); 159 if (retval) 160 goto errout; 161 } 162 163 creds.keyblock.enctype = enctype; 164 creds.times = tgt.times; 165 creds.times.starttime = 0; 166 kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED; 167 168 if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */ 169 kdcoptions &= ~(KDC_OPT_FORWARDABLE); 170 171 if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, 172 addrs, &creds, &pcreds))) { 173 if (enctype) { 174 creds.keyblock.enctype = 0; 175 if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, 176 addrs, &creds, &pcreds))) 177 goto errout; 178 } else goto errout; 179 } 180 181 retval = krb5_mk_1cred(context, auth_context, pcreds, 182 &scratch, &replaydata); 183 krb5_free_creds(context, pcreds); 184 185 /* Solaris Kerberos: changed this logic from the MIT 1.2.1 version to be 186 * more robust. 187 */ 188 if (scratch) { 189 if (retval) 190 krb5_free_data(context, scratch); 191 else { 192 *outbuf = *scratch; 193 krb5_xfree(scratch); 194 } 195 } 196 197 errout: 198 if (addrs) 199 krb5_free_addresses(context, addrs); 200 if (close_cc) 201 (void) krb5_cc_close(context, cc); 202 if (free_rhost) 203 free(rhost); 204 krb5_free_cred_contents(context, &creds); 205 krb5_free_cred_contents(context, &tgt); 206 return retval; 207 } 208