* krbconfig.c: Removed the krb5_clockskew variable
[krb5.git] / src / lib / krb5 / krb / rd_cred.c
1 #include <k5-int.h>
2 #include "cleanup.h"
3 #include "auth_con.h"
4
5 #include <stddef.h>           /* NULL */
6 #include <stdlib.h>           /* malloc */
7 #include <errno.h>            /* ENOMEM */
8
9 /*-------------------- decrypt_credencdata --------------------*/
10
11 /*
12  * decrypt the enc_part of a krb5_cred
13  */
14 static krb5_error_code 
15 decrypt_credencdata(context, pcred, pkeyblock, pcredenc)
16     krb5_context          context;
17     krb5_cred           * pcred;
18     krb5_keyblock       * pkeyblock;
19     krb5_cred_enc_part  * pcredenc;
20 {
21     krb5_cred_enc_part  * ppart;
22     krb5_encrypt_block    eblock;
23     krb5_error_code       retval;
24     krb5_data             scratch;
25
26     if (!valid_enctype(pcred->enc_part.enctype))
27         return KRB5_PROG_ETYPE_NOSUPP;
28
29     /* put together an eblock for this decryption */
30     krb5_use_enctype(context, &eblock, pcred->enc_part.enctype);
31     scratch.length = pcred->enc_part.ciphertext.length;
32     
33     if (!(scratch.data = (char *)malloc(scratch.length))) 
34         return ENOMEM;
35
36     /* do any necessary key pre-processing */
37     if ((retval = krb5_process_key(context, &eblock, pkeyblock)))
38         goto cleanup;
39     
40     /* call the decryption routine */
41     if ((retval = krb5_decrypt(context, 
42                                (krb5_pointer) pcred->enc_part.ciphertext.data,
43                                (krb5_pointer) scratch.data,
44                                scratch.length, &eblock, 0))) {
45         (void)krb5_finish_key(context, &eblock);
46         goto cleanup;
47     }
48
49     if ((retval = krb5_finish_key(context, &eblock)))
50         goto cleanup;
51
52     /*  now decode the decrypted stuff */
53     if ((retval = decode_krb5_enc_cred_part(&scratch, &ppart)))
54         goto cleanup_encpart;
55
56     *pcredenc = *ppart;
57     retval = 0;
58
59 cleanup_encpart:
60     memset(ppart, 0, sizeof(*ppart));
61     krb5_xfree(ppart);
62
63 cleanup:
64     memset(scratch.data, 0, scratch.length);
65     krb5_xfree(scratch.data);
66
67     return retval;
68 }
69 /*----------------------- krb5_rd_cred_basic -----------------------*/
70
71 static krb5_error_code 
72 krb5_rd_cred_basic(context, pcreddata, pkeyblock, local_addr, remote_addr,
73                    replaydata, pppcreds)
74     krb5_context          context;
75     krb5_data           * pcreddata;
76     krb5_keyblock       * pkeyblock;
77     krb5_address        * local_addr;
78     krb5_address        * remote_addr;
79     krb5_replay_data    * replaydata;
80     krb5_creds        *** pppcreds;
81 {
82     krb5_error_code       retval;
83     krb5_cred           * pcred;
84     krb5_int32            ncreds;
85     krb5_int32            i = 0;
86     krb5_cred_enc_part    encpart;
87
88     /* decode cred message */
89     if ((retval = decode_krb5_cred(pcreddata, &pcred)))
90         return retval;
91
92     if ((retval = decrypt_credencdata(context, pcred, pkeyblock, &encpart)))
93         goto cleanup_cred;
94
95     if (!krb5_address_compare(context, remote_addr, encpart.s_address)) {
96         retval = KRB5KRB_AP_ERR_BADADDR;
97         goto cleanup_cred;
98     }
99
100     if (encpart.r_address) {
101         if (local_addr) {
102             if (!krb5_address_compare(context, local_addr, encpart.r_address)) {
103                 retval = KRB5KRB_AP_ERR_BADADDR;
104                 goto cleanup_cred;
105             }
106         } else {
107             krb5_address **our_addrs;
108
109             if ((retval = krb5_os_localaddr(context, &our_addrs))) {
110                 goto cleanup_cred;
111             }
112             if (!krb5_address_search(context, encpart.r_address, our_addrs)) {
113                 krb5_free_addresses(context, our_addrs);
114                 retval =  KRB5KRB_AP_ERR_BADADDR;
115                 goto cleanup_cred;
116             }
117             krb5_free_addresses(context, our_addrs);
118         }
119     }
120
121     replaydata->timestamp = encpart.timestamp;
122     replaydata->usec = encpart.usec;
123     replaydata->seq = encpart.nonce;
124
125    /*
126     * Allocate the list of creds.  The memory is allocated so that
127     * krb5_free_tgt_creds can be used to free the list.
128     */
129     for (ncreds = 0; pcred->tickets[ncreds]; ncreds++);
130         
131     if ((*pppcreds = 
132         (krb5_creds **)malloc((size_t)(sizeof(krb5_creds *) * ncreds + 1))) == NULL) {
133         retval = ENOMEM;
134         goto cleanup_cred;
135     }
136
137     /*
138      * For each credential, create a strcture in the list of
139      * credentials and copy the information.
140      */
141     while (i < ncreds) {
142         krb5_cred_info  * pinfo;
143         krb5_creds      * pcur;
144         krb5_data       * pdata;
145
146         if ((pcur = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) {
147             retval = ENOMEM;
148             goto cleanup;
149         }
150
151         (*pppcreds)[i] = pcur;
152         pinfo = encpart.ticket_info[i++];
153         memset(pcur, 0, sizeof(krb5_creds));
154
155         if ((retval = krb5_copy_principal(context, pinfo->client,
156                                           &pcur->client)))
157             goto cleanup;
158
159         if ((retval = krb5_copy_principal(context, pinfo->server,
160                                           &pcur->server)))
161             goto cleanup;
162
163         if ((retval = krb5_copy_keyblock_contents(context, pinfo->session,
164                                                   &pcur->keyblock)))
165             goto cleanup;
166
167         if ((retval = krb5_copy_addresses(context, pinfo->caddrs, 
168                                           &pcur->addresses)))
169             goto cleanup;
170
171         if ((retval = encode_krb5_ticket(pcred->tickets[i - 1], &pdata)))
172             goto cleanup;
173
174         pcur->ticket = *pdata;
175         krb5_xfree(pdata);
176
177
178         pcur->is_skey = FALSE;
179         pcur->magic = KV5M_CREDS;
180         pcur->times = pinfo->times;
181         pcur->ticket_flags = pinfo->flags;
182         pcur->authdata = NULL;   /* not used */
183         memset(&pcur->second_ticket, 0, sizeof(pcur->second_ticket));
184     }
185
186     /*
187      * NULL terminate the list
188      */
189     (*pppcreds)[i] = NULL;
190
191 cleanup:
192     if (retval)
193         while (i >= 0)
194             free((*pppcreds)[i--]);
195
196 cleanup_cred:
197     krb5_free_cred(context, pcred);
198
199     return retval;
200 }
201
202 /*----------------------- krb5_rd_cred -----------------------*/
203
204 #define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew)
205
206 /*
207  * This functions takes as input an KRB_CRED message, validates it, and
208  * outputs the nonce and an array of the forwarded credentials.
209  */
210 krb5_error_code
211 krb5_rd_cred(context, auth_context, pcreddata, pppcreds, outdata)
212     krb5_context          context;
213     krb5_auth_context     auth_context;
214     krb5_data           * pcreddata;       
215     krb5_creds        *** pppcreds;
216     krb5_replay_data    * outdata;
217 {
218     krb5_error_code       retval;
219     krb5_keyblock       * keyblock;
220     krb5_replay_data      replaydata;
221
222     /* Get keyblock */
223     if ((keyblock = auth_context->local_subkey) == NULL)
224         if ((keyblock = auth_context->remote_subkey) == NULL)
225             keyblock = auth_context->keyblock;
226
227     if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
228       (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
229       (outdata == NULL))
230         /* Need a better error */
231         return KRB5_RC_REQUIRED;
232
233     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
234       (auth_context->rcache == NULL))
235         return KRB5_RC_REQUIRED;
236
237 {
238     krb5_address * premote_fulladdr = NULL;
239     krb5_address * plocal_fulladdr = NULL;
240     krb5_address remote_fulladdr;
241     krb5_address local_fulladdr;
242     CLEANUP_INIT(2);
243
244     if (auth_context->local_addr) {
245         if (auth_context->local_port) {
246             if (!(retval = krb5_make_fulladdr(context,auth_context->local_addr,
247                                               auth_context->local_port, 
248                                               &local_fulladdr))){
249                 CLEANUP_PUSH(local_fulladdr.contents, free);
250                 plocal_fulladdr = &local_fulladdr;
251             } else {
252                 return retval;
253             }
254         } else {
255             plocal_fulladdr = auth_context->local_addr;
256         }
257     }
258
259     if (auth_context->remote_addr) {
260         if (auth_context->remote_port) {
261             if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr,
262                                               auth_context->remote_port, 
263                                               &remote_fulladdr))){
264                 CLEANUP_PUSH(remote_fulladdr.contents, free);
265                 premote_fulladdr = &remote_fulladdr;
266             } else {
267                 return retval;
268             }
269         } else {
270             premote_fulladdr = auth_context->remote_addr;
271         }
272     }
273
274     if ((retval = krb5_rd_cred_basic(context, pcreddata, keyblock,
275                                      plocal_fulladdr, premote_fulladdr,
276                                      &replaydata, pppcreds))) {
277         CLEANUP_DONE();
278         return retval;
279     }
280
281     CLEANUP_DONE();
282 }
283
284
285     if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
286         krb5_donot_replay replay;
287         krb5_timestamp currenttime;
288
289         if ((retval = krb5_timeofday(context, &currenttime)))
290             goto error;
291
292         if (!in_clock_skew(replaydata.timestamp)) {
293             retval =  KRB5KRB_AP_ERR_SKEW;
294             goto error;
295         }
296
297         if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr,
298                                            "_forw", &replay.client)))
299             goto error;
300
301         replay.server = "";             /* XXX */
302         replay.cusec = replaydata.usec;
303         replay.ctime = replaydata.timestamp;
304         if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
305             krb5_xfree(replay.client);
306             goto error;
307         }
308         krb5_xfree(replay.client);
309     }
310
311     if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
312         if (auth_context->remote_seq_number != replaydata.seq) {
313             retval =  KRB5KRB_AP_ERR_BADORDER;
314             goto error;
315         }
316         auth_context->remote_seq_number++;
317     }
318
319     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
320       (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
321         outdata->timestamp = replaydata.timestamp;
322         outdata->usec = replaydata.usec;
323         outdata->seq = replaydata.seq;
324     }
325
326 error:;
327     if (retval)
328         krb5_xfree(*pppcreds);
329     return retval;
330 }
331
332