Windows global stuff:
[krb5.git] / src / lib / krb5 / krb / rd_priv.c
1 /*
2  * lib/krb5/krb/rd_priv.c
3  *
4  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  M.I.T. makes no representations about the suitability of
20  * this software for any purpose.  It is provided "as is" without express
21  * or implied warranty.
22  * 
23  *
24  * krb5_rd_priv()
25  */
26
27 #include "k5-int.h"
28 #include "auth_con.h"
29
30 extern krb5_deltat krb5_clockskew;   
31 #define in_clock_skew(date) (labs((date)-currenttime) < krb5_clockskew)
32
33 /*
34
35 Parses a KRB_PRIV message from inbuf, placing the confidential user
36 data in *outbuf.
37
38 key specifies the key to be used for decryption of the message.
39  
40 remote_addr and local_addr specify the full
41 addresses (host and port) of the sender and receiver.
42
43 outbuf points to allocated storage which the caller should
44 free when finished.
45
46 i_vector is used as an initialization vector for the
47 encryption, and if non-NULL its contents are replaced with the last
48 block of the encrypted data upon exit.
49
50 Returns system errors, integrity errors.
51
52 */
53
54 static krb5_error_code
55 krb5_rd_priv_basic(context, inbuf, keyblock, local_addr, remote_addr, 
56                    i_vector, replaydata, outbuf)
57     krb5_context          context;
58     const krb5_data     * inbuf;
59     const krb5_keyblock * keyblock;
60     const krb5_address  * local_addr;
61     const krb5_address  * remote_addr;
62     krb5_pointer          i_vector;
63     krb5_replay_data    * replaydata;
64     krb5_data           * outbuf;
65 {
66     krb5_error_code       retval;
67     krb5_priv           * privmsg;
68     krb5_data             scratch;
69     krb5_encrypt_block    eblock;
70     krb5_priv_enc_part  * privmsg_enc_part;
71
72     if (!krb5_is_krb_priv(inbuf))
73         return KRB5KRB_AP_ERR_MSG_TYPE;
74
75     /* decode private message */
76     if (retval = decode_krb5_priv(inbuf, &privmsg)) 
77         return retval;
78     
79     if (!valid_etype(privmsg->enc_part.etype)) {
80         retval = KRB5_PROG_ETYPE_NOSUPP;
81         goto cleanup_privmsg;
82     }
83                            
84     /* put together an eblock for this decryption */
85     krb5_use_cstype(context, &eblock, privmsg->enc_part.etype);
86     scratch.length = privmsg->enc_part.ciphertext.length;
87     
88     if (!(scratch.data = malloc(scratch.length))) {
89         retval = ENOMEM;
90         goto cleanup_privmsg;
91     }
92
93     /* do any necessary key pre-processing */
94     if (retval = krb5_process_key(context, &eblock, keyblock)) 
95         goto cleanup_scratch;
96
97     /* call the decryption routine */
98     if (retval = krb5_decrypt(context, 
99                               (krb5_pointer) privmsg->enc_part.ciphertext.data,
100                               (krb5_pointer) scratch.data,
101                               scratch.length, &eblock, i_vector)) {
102         krb5_finish_key(context, &eblock);
103         goto cleanup_scratch;
104     }
105
106     /* if i_vector is set, put last block into the i_vector */
107     if (i_vector)
108         memcpy(i_vector,
109                privmsg->enc_part.ciphertext.data +
110                (privmsg->enc_part.ciphertext.length -
111                 eblock.crypto_entry->block_length),
112                eblock.crypto_entry->block_length);
113
114     if (retval = krb5_finish_key(context, &eblock)) 
115         goto cleanup_scratch;
116
117     /*  now decode the decrypted stuff */
118     if (retval = decode_krb5_enc_priv_part(&scratch, &privmsg_enc_part)) 
119         goto cleanup_scratch;
120
121     if (!krb5_address_compare(context,remote_addr,privmsg_enc_part->s_address)){
122         retval = KRB5KRB_AP_ERR_BADADDR;
123         goto cleanup_data;
124     }
125     
126     if (privmsg_enc_part->r_address) {
127         if (local_addr) {
128             if (!krb5_address_compare(context, local_addr,
129                                       privmsg_enc_part->r_address)) {
130                 retval = KRB5KRB_AP_ERR_BADADDR;
131                 goto cleanup_data;
132             }
133         } else {
134             krb5_address **our_addrs;
135         
136             if (retval = krb5_os_localaddr(&our_addrs)) {
137                 goto cleanup_data;
138             }
139             if (!krb5_address_search(context, privmsg_enc_part->r_address, our_addrs)) {
140                 krb5_free_addresses(context, our_addrs);
141                 retval =  KRB5KRB_AP_ERR_BADADDR;
142                 goto cleanup_data;
143             }
144             krb5_free_addresses(context, our_addrs);
145         }
146     }
147
148     replaydata->timestamp = privmsg_enc_part->timestamp;
149     replaydata->usec = privmsg_enc_part->usec;
150     replaydata->seq = privmsg_enc_part->seq_number;
151
152     /* everything is ok - return data to the user */
153     *outbuf = privmsg_enc_part->user_data;
154     retval = 0;
155
156 cleanup_data:;
157     if (retval) {
158         memset(privmsg_enc_part->user_data.data, 0, 
159                privmsg_enc_part->user_data.length); 
160         krb5_xfree(privmsg_enc_part->user_data.data);
161     }
162     krb5_xfree(privmsg_enc_part);
163
164 cleanup_scratch:;
165     memset(scratch.data, 0, scratch.length); 
166     krb5_xfree(scratch.data);
167
168 cleanup_privmsg:;
169     krb5_xfree(privmsg->enc_part.ciphertext.data); 
170     krb5_xfree(privmsg);
171
172     return retval;
173 }
174
175 krb5_error_code
176 krb5_rd_priv(context, auth_context, inbuf, outbuf, outdata)
177     krb5_context        context;
178     krb5_auth_context * auth_context;
179     const krb5_data   * inbuf;
180     krb5_data         * outbuf;
181     krb5_replay_data  * outdata;
182 {
183     krb5_error_code     retval;
184     krb5_replay_data    replaydata;
185
186     if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
187       (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
188       (outdata == NULL))
189         /* Need a better error */
190         return KRB5_RC_REQUIRED;
191
192     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
193       (auth_context->rcache == NULL))
194         return KRB5_RC_REQUIRED;
195
196     if (retval = krb5_rd_priv_basic(context, inbuf, auth_context->keyblock,
197       auth_context->local_addr, auth_context->remote_addr,
198       auth_context->i_vector, &replaydata, outbuf))
199         return retval;
200
201     if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
202         krb5_donot_replay replay;
203         krb5_timestamp currenttime;
204
205         if (retval = krb5_timeofday(context, &currenttime)) 
206             goto error;
207
208         if (!in_clock_skew(replaydata.timestamp)) {
209             retval =  KRB5KRB_AP_ERR_SKEW;
210             goto error;
211         }
212
213         if (retval = krb5_gen_replay_name(context, auth_context->remote_addr, 
214                                           "_priv", &replay.client)) 
215             goto error;
216
217         replay.server = "";             /* XXX */
218         replay.cusec = replaydata.usec;
219         replay.ctime = replaydata.timestamp;
220         if (retval = krb5_rc_store(context, auth_context->rcache, &replay)) {
221             krb5_xfree(replay.client);
222             goto error;
223         }
224         krb5_xfree(replay.client);
225     }
226
227     if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
228         if (auth_context->remote_seq_number != replaydata.seq) {
229             retval =  KRB5KRB_AP_ERR_BADORDER;
230             goto error;
231         }
232         auth_context->remote_seq_number++;
233     }
234
235     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
236       (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
237         outdata->timestamp = replaydata.timestamp;
238         outdata->usec = replaydata.usec;
239         outdata->seq = replaydata.seq;
240     }
241         
242     /* everything is ok - return data to the user */
243     return 0;
244
245 error:;
246     krb5_xfree(outbuf->data);
247     return retval;
248
249 }
250