xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_priv.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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, &currenttime)))
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