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/rd_priv.c 9 * 10 * Copyright 1990,1991 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 * krb5_rd_priv() 34 */ 35 36 #include "k5-int.h" 37 #include "cleanup.h" 38 #include "auth_con.h" 39 40 #define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew) 41 42 /* 43 44 Parses a KRB_PRIV message from inbuf, placing the confidential user 45 data in *outbuf. 46 47 key specifies the key to be used for decryption of the message. 48 49 remote_addr and local_addr specify the full 50 addresses (host and port) of the sender and receiver. 51 52 outbuf points to allocated storage which the caller should 53 free when finished. 54 55 i_vector is used as an initialization vector for the 56 encryption, and if non-NULL its contents are replaced with the last 57 block of the encrypted data upon exit. 58 59 Returns system errors, integrity errors. 60 61 */ 62 63 static krb5_error_code 64 krb5_rd_priv_basic(krb5_context context, const krb5_data *inbuf, const krb5_keyblock *keyblock, const krb5_address *local_addr, const krb5_address *remote_addr, krb5_pointer i_vector, krb5_replay_data *replaydata, krb5_data *outbuf) 65 { 66 krb5_error_code retval; 67 krb5_priv * privmsg; 68 krb5_data scratch; 69 krb5_priv_enc_part * privmsg_enc_part; 70 size_t blocksize; 71 krb5_data ivdata; 72 73 if (!krb5_is_krb_priv(inbuf)) 74 return KRB5KRB_AP_ERR_MSG_TYPE; 75 76 /* decode private message */ 77 if ((retval = decode_krb5_priv(inbuf, &privmsg))) 78 return retval; 79 80 if (i_vector) { 81 if ((retval = krb5_c_block_size(context, keyblock->enctype, 82 &blocksize))) 83 goto cleanup_privmsg; 84 85 ivdata.length = blocksize; 86 ivdata.data = i_vector; 87 } 88 89 scratch.length = privmsg->enc_part.ciphertext.length; 90 if (!(scratch.data = malloc(scratch.length))) { 91 retval = ENOMEM; 92 goto cleanup_privmsg; 93 } 94 95 if ((retval = krb5_c_decrypt(context, keyblock, 96 KRB5_KEYUSAGE_KRB_PRIV_ENCPART, 97 i_vector?&ivdata:0, 98 &privmsg->enc_part, &scratch))) 99 goto cleanup_scratch; 100 101 /* now decode the decrypted stuff */ 102 if ((retval = decode_krb5_enc_priv_part(&scratch, &privmsg_enc_part))) 103 goto cleanup_scratch; 104 105 if (!krb5_address_compare(context,remote_addr,privmsg_enc_part->s_address)){ 106 retval = KRB5KRB_AP_ERR_BADADDR; 107 goto cleanup_data; 108 } 109 110 if (privmsg_enc_part->r_address) { 111 if (local_addr) { 112 if (!krb5_address_compare(context, local_addr, 113 privmsg_enc_part->r_address)) { 114 retval = KRB5KRB_AP_ERR_BADADDR; 115 goto cleanup_data; 116 } 117 } else { 118 krb5_address **our_addrs; 119 120 if ((retval = krb5_os_localaddr(context, &our_addrs))) { 121 goto cleanup_data; 122 } 123 if (!krb5_address_search(context, privmsg_enc_part->r_address, 124 our_addrs)) { 125 krb5_free_addresses(context, our_addrs); 126 retval = KRB5KRB_AP_ERR_BADADDR; 127 goto cleanup_data; 128 } 129 krb5_free_addresses(context, our_addrs); 130 } 131 } 132 133 replaydata->timestamp = privmsg_enc_part->timestamp; 134 replaydata->usec = privmsg_enc_part->usec; 135 replaydata->seq = privmsg_enc_part->seq_number; 136 137 /* everything is ok - return data to the user */ 138 *outbuf = privmsg_enc_part->user_data; 139 retval = 0; 140 141 cleanup_data:; 142 if (retval == 0) 143 privmsg_enc_part->user_data.data = 0; 144 krb5_free_priv_enc_part(context, privmsg_enc_part); 145 146 cleanup_scratch:; 147 /* Solaris Kerberos */ 148 (void) memset(scratch.data, 0, scratch.length); 149 krb5_xfree(scratch.data); 150 151 cleanup_privmsg:; 152 krb5_xfree(privmsg->enc_part.ciphertext.data); 153 krb5_xfree(privmsg); 154 155 return retval; 156 } 157 158 krb5_error_code KRB5_CALLCONV 159 krb5_rd_priv(krb5_context context, krb5_auth_context auth_context, const krb5_data *inbuf, krb5_data *outbuf, krb5_replay_data *outdata) 160 { 161 krb5_error_code retval; 162 krb5_keyblock * keyblock; 163 krb5_replay_data replaydata; 164 165 /* Get keyblock */ 166 if ((keyblock = auth_context->recv_subkey) == NULL) 167 keyblock = auth_context->keyblock; 168 169 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || 170 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && 171 (outdata == NULL)) 172 /* Need a better error */ 173 return KRB5_RC_REQUIRED; 174 175 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && 176 (auth_context->rcache == NULL)) 177 return KRB5_RC_REQUIRED; 178 179 { 180 krb5_address * premote_fulladdr = NULL; 181 krb5_address * plocal_fulladdr = NULL; 182 krb5_address remote_fulladdr; 183 krb5_address local_fulladdr; 184 CLEANUP_INIT(2); 185 186 if (auth_context->local_addr) { 187 if (auth_context->local_port) { 188 if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr, 189 auth_context->local_port, 190 &local_fulladdr))){ 191 CLEANUP_PUSH(local_fulladdr.contents, free); 192 plocal_fulladdr = &local_fulladdr; 193 } else { 194 return retval; 195 } 196 } else { 197 plocal_fulladdr = auth_context->local_addr; 198 } 199 } 200 201 if (auth_context->remote_addr) { 202 if (auth_context->remote_port) { 203 if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr, 204 auth_context->remote_port, 205 &remote_fulladdr))){ 206 CLEANUP_PUSH(remote_fulladdr.contents, free); 207 premote_fulladdr = &remote_fulladdr; 208 } else { 209 CLEANUP_DONE(); 210 return retval; 211 } 212 } else { 213 premote_fulladdr = auth_context->remote_addr; 214 } 215 } 216 217 if ((retval = krb5_rd_priv_basic(context, inbuf, keyblock, 218 plocal_fulladdr, 219 premote_fulladdr, 220 auth_context->i_vector, 221 &replaydata, outbuf))) { 222 CLEANUP_DONE(); 223 return retval; 224 } 225 226 CLEANUP_DONE(); 227 } 228 229 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { 230 krb5_donot_replay replay; 231 krb5_timestamp currenttime; 232 233 if ((retval = krb5_timeofday(context, ¤ttime))) 234 goto error; 235 236 if (!in_clock_skew(replaydata.timestamp)) { 237 retval = KRB5KRB_AP_ERR_SKEW; 238 goto error; 239 } 240 241 if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr, 242 "_priv", &replay.client))) 243 goto error; 244 245 replay.server = ""; /* XXX */ 246 replay.cusec = replaydata.usec; 247 replay.ctime = replaydata.timestamp; 248 if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) { 249 krb5_xfree(replay.client); 250 goto error; 251 } 252 krb5_xfree(replay.client); 253 } 254 255 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { 256 if (!krb5int_auth_con_chkseqnum(context, auth_context, 257 replaydata.seq)) { 258 retval = KRB5KRB_AP_ERR_BADORDER; 259 goto error; 260 } 261 auth_context->remote_seq_number++; 262 } 263 264 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || 265 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { 266 outdata->timestamp = replaydata.timestamp; 267 outdata->usec = replaydata.usec; 268 outdata->seq = replaydata.seq; 269 } 270 271 /* everything is ok - return data to the user */ 272 return 0; 273 274 error:; 275 krb5_xfree(outbuf->data); 276 return retval; 277 278 } 279 280