changed `struct fd_set' to `fd_set'
[heimdal.git] / lib / krb5 / get_in_tkt.c
blob5103eef93129df3ed182f211c52cc8e63c5c1702
1 /*
2 * Copyright (c) 1997 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #include "krb5_locl.h"
41 RCSID("$Id$");
43 krb5_error_code
44 krb5_init_etype (krb5_context context,
45 unsigned *len,
46 unsigned **val,
47 const krb5_enctype *etypes)
49 int i;
50 krb5_error_code ret;
51 krb5_enctype *tmp;
53 ret = 0;
54 if (etypes)
55 tmp = (krb5_enctype*)etypes;
56 else {
57 ret = krb5_get_default_in_tkt_etypes(context,
58 &tmp);
59 if (ret)
60 return ret;
63 for (i = 0; tmp[i]; ++i)
65 *len = i;
66 *val = malloc(i * sizeof(unsigned));
67 if (*val == NULL) {
68 ret = ENOMEM;
69 goto cleanup;
71 memmove (*val,
72 tmp,
73 i * sizeof(*tmp));
74 cleanup:
75 if (etypes == NULL)
76 free (tmp);
77 return ret;
81 static krb5_error_code
82 decrypt_tkt (krb5_context context,
83 const krb5_keyblock *key,
84 krb5_const_pointer decrypt_arg,
85 krb5_kdc_rep *dec_rep)
87 krb5_error_code ret;
88 krb5_data data;
89 size_t size;
91 ret = krb5_decrypt (context,
92 dec_rep->part1.enc_part.cipher.data,
93 dec_rep->part1.enc_part.cipher.length,
94 dec_rep->part1.enc_part.etype,
95 key,
96 &data);
97 if (ret)
98 return ret;
100 ret = decode_EncASRepPart(data.data,
101 data.length,
102 &dec_rep->part2,
103 &size);
104 if (ret)
105 ret = decode_EncTGSRepPart(data.data,
106 data.length,
107 &dec_rep->part2,
108 &size);
109 krb5_data_free (&data);
110 if (ret) return ret;
111 return 0;
115 _krb5_extract_ticket(krb5_context context,
116 krb5_kdc_rep *rep,
117 krb5_creds *creds,
118 krb5_keyblock *key,
119 krb5_const_pointer keyseed,
120 krb5_addresses *addrs,
121 unsigned nonce,
122 krb5_boolean allow_server_mismatch,
123 krb5_decrypt_proc decrypt_proc,
124 krb5_const_pointer decryptarg)
126 krb5_error_code err;
127 krb5_principal tmp_principal;
128 int tmp;
129 time_t tmp_time;
130 int32_t sec_now;
132 /* compare client */
134 err = principalname2krb5_principal (&tmp_principal,
135 rep->part1.cname,
136 rep->part1.crealm);
137 if (err)
138 goto out;
139 tmp = krb5_principal_compare (context, tmp_principal, creds->client);
140 krb5_free_principal (context, tmp_principal);
141 if (!tmp) {
142 err = KRB5KRB_AP_ERR_MODIFIED;
143 goto out;
146 /* extract ticket */
148 unsigned char buf[1024];
149 size_t len;
150 encode_Ticket(buf + sizeof(buf) - 1, sizeof(buf),
151 &rep->part1.ticket, &len);
152 creds->ticket.data = malloc(len);
153 memcpy(creds->ticket.data, buf + sizeof(buf) - len, len);
154 creds->ticket.length = len;
155 creds->second_ticket.length = 0;
156 creds->second_ticket.data = NULL;
159 /* compare server */
161 err = principalname2krb5_principal (&tmp_principal,
162 rep->part1.ticket.sname,
163 rep->part1.ticket.realm);
164 if (err)
165 goto out;
166 if(allow_server_mismatch){
167 krb5_free_principal(context, creds->server);
168 creds->server = tmp_principal;
169 tmp_principal = NULL;
170 }else{
171 tmp = krb5_principal_compare (context, tmp_principal, creds->server);
172 krb5_free_principal (context, tmp_principal);
173 if (!tmp) {
174 err = KRB5KRB_AP_ERR_MODIFIED;
175 goto out;
179 /* decrypt */
181 if (decrypt_proc == NULL)
182 decrypt_proc = decrypt_tkt;
184 err = (*decrypt_proc)(context, key, decryptarg, rep);
185 if (err)
186 goto out;
188 /* compare nonces */
190 if (nonce != rep->part2.nonce) {
191 err = KRB5KRB_AP_ERR_MODIFIED;
192 goto out;
195 /* set kdc-offset */
197 krb5_timeofday (context, &sec_now);
198 if (context->kdc_sec_offset == 0
199 && krb5_config_get_bool (context->cf,
200 "libdefaults",
201 "kdc_timesync",
202 NULL)) {
203 context->kdc_sec_offset = rep->part2.authtime - sec_now;
204 krb5_timeofday (context, &sec_now);
207 /* check all times */
209 if (rep->part2.starttime) {
210 tmp_time = *rep->part2.starttime;
211 } else
212 tmp_time = rep->part2.authtime;
214 if (creds->times.starttime == 0
215 && abs(tmp_time - sec_now) > context->max_skew) {
216 err = KRB5KRB_AP_ERR_MODIFIED;
217 goto out;
220 if (creds->times.starttime != 0
221 && tmp_time != creds->times.starttime) {
222 err = KRB5KRB_AP_ERR_MODIFIED;
223 goto out;
226 creds->times.starttime = tmp_time;
228 if (rep->part2.renew_till) {
229 tmp_time = *rep->part2.renew_till;
230 } else
231 tmp_time = 0;
233 if (creds->times.renew_till != 0
234 && tmp_time > creds->times.renew_till) {
235 err = KRB5KRB_AP_ERR_MODIFIED;
236 goto out;
239 creds->times.renew_till = tmp_time;
241 creds->times.authtime = rep->part2.authtime;
243 if (creds->times.endtime != 0
244 && rep->part2.endtime > creds->times.endtime) {
245 err = KRB5KRB_AP_ERR_MODIFIED;
246 goto out;
249 creds->times.endtime = rep->part2.endtime;
251 if(rep->part2.caddr)
252 krb5_copy_addresses (context, rep->part2.caddr, &creds->addresses);
253 else if(addrs)
254 krb5_copy_addresses (context, addrs, &creds->addresses);
255 else {
256 creds->addresses.len = 0;
257 creds->addresses.val = NULL;
259 creds->flags.b = rep->part2.flags;
261 creds->authdata.length = 0;
262 creds->authdata.data = NULL;
263 creds->session.keyvalue.length = 0;
264 creds->session.keyvalue.data = NULL;
265 creds->session.keytype = rep->part2.key.keytype;
266 err = krb5_data_copy (&creds->session.keyvalue,
267 rep->part2.key.keyvalue.data,
268 rep->part2.key.keyvalue.length);
270 out:
271 memset (rep->part2.key.keyvalue.data, 0,
272 rep->part2.key.keyvalue.length);
273 return err;
277 static krb5_error_code
278 make_pa_enc_timestamp(krb5_context context, PA_DATA *pa,
279 krb5_enctype etype, krb5_keyblock *key)
281 PA_ENC_TS_ENC p;
282 u_char buf[1024];
283 size_t len;
284 EncryptedData encdata;
285 krb5_error_code ret;
286 int32_t sec, usec;
287 unsigned usec2;
289 krb5_us_timeofday (context, &sec, &usec);
290 p.patimestamp = sec;
291 usec2 = usec;
292 p.pausec = &usec2;
294 ret = encode_PA_ENC_TS_ENC(buf + sizeof(buf) - 1,
295 sizeof(buf),
297 &len);
298 if (ret)
299 return ret;
301 ret = krb5_encrypt_EncryptedData(context,
302 buf + sizeof(buf) - len,
303 len,
304 etype,
306 key,
307 &encdata);
308 if (ret)
309 return ret;
311 ret = encode_EncryptedData(buf + sizeof(buf) - 1,
312 sizeof(buf),
313 &encdata,
314 &len);
315 free_EncryptedData(&encdata);
316 if (ret)
317 return ret;
318 pa->padata_type = pa_enc_timestamp;
319 pa->padata_value.length = 0;
320 krb5_data_copy(&pa->padata_value,
321 buf + sizeof(buf) - len,
322 len);
323 return 0;
326 static krb5_error_code
327 init_as_req (krb5_context context,
328 krb5_kdc_flags opts,
329 krb5_creds *creds,
330 const krb5_addresses *addrs,
331 const krb5_enctype *etypes,
332 const krb5_preauthtype *ptypes,
333 krb5_key_proc key_proc,
334 krb5_const_pointer keyseed,
335 unsigned nonce,
336 AS_REQ *a)
338 krb5_error_code ret;
339 krb5_data salt;
340 krb5_keyblock *key;
341 krb5_enctype etype;
343 memset(a, 0, sizeof(*a));
345 a->pvno = 5;
346 a->msg_type = krb_as_req;
347 a->req_body.kdc_options = opts.b;
348 a->req_body.cname = malloc(sizeof(*a->req_body.cname));
349 if (a->req_body.cname == NULL) {
350 ret = ENOMEM;
351 goto fail;
353 a->req_body.sname = malloc(sizeof(*a->req_body.sname));
354 if (a->req_body.sname == NULL) {
355 ret = ENOMEM;
356 goto fail;
358 ret = krb5_principal2principalname (a->req_body.cname, creds->client);
359 if (ret)
360 goto fail;
361 ret = krb5_principal2principalname (a->req_body.sname, creds->server);
362 if (ret)
363 goto fail;
364 ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
365 if (ret)
366 goto fail;
368 if(creds->times.starttime) {
369 a->req_body.from = malloc(sizeof(*a->req_body.from));
370 if (a->req_body.from == NULL) {
371 ret = ENOMEM;
372 goto fail;
374 *a->req_body.from = creds->times.starttime;
376 if(creds->times.endtime){
377 ALLOC(a->req_body.till, 1);
378 *a->req_body.till = creds->times.endtime;
380 if(creds->times.renew_till){
381 a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
382 if (a->req_body.rtime == NULL) {
383 ret = ENOMEM;
384 goto fail;
386 *a->req_body.rtime = creds->times.renew_till;
388 a->req_body.nonce = nonce;
389 ret = krb5_init_etype (context,
390 &a->req_body.etype.len,
391 &a->req_body.etype.val,
392 etypes);
393 if (ret)
394 goto fail;
396 etype = a->req_body.etype.val[0]; /* XXX */
398 a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
399 if (a->req_body.addresses == NULL) {
400 ret = ENOMEM;
401 goto fail;
404 if (addrs)
405 ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
406 else
407 ret = krb5_get_all_client_addrs (a->req_body.addresses);
408 if (ret)
409 return ret;
411 a->req_body.enc_authorization_data = NULL;
412 a->req_body.additional_tickets = NULL;
414 /* not sure this is the way to use `ptypes' */
415 if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE)
416 a->padata = NULL;
417 else if (*ptypes == KRB5_PADATA_ENC_TIMESTAMP) {
418 a->padata = malloc(sizeof(*a->padata));
419 if (a->padata == NULL) {
420 ret = ENOMEM;
421 goto fail;
424 a->padata->len = 2;
425 a->padata->val = calloc(a->padata->len, sizeof(*a->padata->val));
426 if (a->padata->val == NULL) {
427 ret = ENOMEM;
428 goto fail;
431 /* make a v5 salted pa-data */
432 salt.length = 0;
433 salt.data = NULL;
434 ret = krb5_get_salt (creds->client, &salt);
436 if (ret)
437 goto fail;
440 krb5_keytype keytype;
441 ret = krb5_etype_to_keytype(context, etype, &keytype);
442 if(ret){
443 krb5_data_free(&salt);
444 goto fail;
446 ret = (*key_proc)(context, keytype, &salt, keyseed, &key);
447 krb5_data_free (&salt);
449 if (ret)
450 goto fail;
451 ret = make_pa_enc_timestamp(context, &a->padata->val[0], etype, key);
452 krb5_free_keyblock_contents (context, key);
453 free (key);
454 if (ret)
455 goto fail;
456 /* make a v4 salted pa-data */
457 salt.length = 0;
458 salt.data = NULL;
460 krb5_keytype keytype;
461 ret = krb5_etype_to_keytype(context, etype, &keytype);
462 if(ret)
463 goto fail;
464 ret = (*key_proc)(context, keytype, &salt, keyseed, &key);
466 if (ret)
467 goto fail;
468 ret = make_pa_enc_timestamp(context, &a->padata->val[1], etype, key);
469 krb5_free_keyblock_contents (context, key);
470 free (key);
471 if (ret)
472 goto fail;
473 } else {
474 ret = KRB5_PREAUTH_BAD_TYPE;
475 goto fail;
477 return 0;
478 fail:
479 free_AS_REQ(a);
480 return ret;
483 krb5_error_code
484 krb5_get_in_cred(krb5_context context,
485 krb5_flags options,
486 const krb5_addresses *addrs,
487 const krb5_enctype *etypes,
488 const krb5_preauthtype *ptypes,
489 krb5_key_proc key_proc,
490 krb5_const_pointer keyseed,
491 krb5_decrypt_proc decrypt_proc,
492 krb5_const_pointer decryptarg,
493 krb5_creds *creds,
494 krb5_kdc_rep *ret_as_reply)
496 krb5_error_code ret;
497 AS_REQ a;
498 krb5_kdc_rep rep;
499 krb5_data req, resp;
500 char buf[BUFSIZ];
501 krb5_data salt;
502 krb5_keyblock *key;
503 size_t size;
504 krb5_kdc_flags opts;
505 PA_DATA *pa;
506 krb5_enctype etype;
507 unsigned nonce;
509 opts.i = options;
511 krb5_generate_random_block (&nonce, sizeof(nonce));
512 nonce &= 0xffffffff;
514 ret = init_as_req (context,
515 opts,
516 creds,
517 addrs,
518 etypes,
519 ptypes,
520 key_proc,
521 keyseed,
522 nonce,
523 &a);
524 if (ret)
525 return ret;
527 ret = encode_AS_REQ ((unsigned char*)buf + sizeof(buf) - 1,
528 sizeof(buf),
530 &req.length);
531 free_AS_REQ(&a);
532 if (ret)
533 return ret;
535 req.data = buf + sizeof(buf) - req.length;
537 ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp);
538 if (ret)
539 return ret;
541 memset (&rep, 0, sizeof(rep));
542 if((ret = decode_AS_REP(resp.data, resp.length, &rep.part1, &size))){
543 /* let's try to parse it as a KRB-ERROR */
544 KRB_ERROR error;
545 int ret2;
547 ret2 = krb5_rd_error(context, &resp, &error);
548 if(ret2 && resp.data && ((char*)resp.data)[0] == 4)
549 ret = KRB5KRB_AP_ERR_V4_REPLY;
550 krb5_data_free(&resp);
551 if (ret2 == 0) {
552 /* XXX - send krb-error packet to caller */
553 free_KRB_ERROR (&error);
554 return error.error_code;
556 return ret;
558 krb5_data_free(&resp);
560 pa = NULL;
561 etype = rep.part1.enc_part.etype;
562 if(rep.part1.padata){
563 int index = 0;
564 pa = krb5_find_padata(rep.part1.padata->val, rep.part1.padata->len,
565 pa_pw_salt, &index);
567 if(pa) {
568 krb5_keytype keytype;
569 ret = krb5_etype_to_keytype(context, etype, &keytype);
570 ret = (*key_proc)(context, keytype, &pa->padata_value, keyseed, &key);
571 } else {
572 /* make a v5 salted pa-data */
573 krb5_keytype keytype;
574 salt.length = 0;
575 salt.data = NULL;
576 ret = krb5_get_salt (creds->client, &salt);
578 if (ret)
579 return ret;
580 ret = krb5_etype_to_keytype(context, etype, &keytype);
581 ret = (*key_proc)(context, keytype, &salt, keyseed, &key);
582 krb5_data_free (&salt);
584 if (ret)
585 return ret;
587 ret = _krb5_extract_ticket(context, &rep, creds, key, keyseed,
588 NULL, nonce, FALSE, decrypt_proc, decryptarg);
589 memset (key->keyvalue.data, 0, key->keyvalue.length);
590 krb5_free_keyblock_contents (context, key);
591 free (key);
593 if (ret == 0 && ret_as_reply)
594 *ret_as_reply = rep;
595 else
596 krb5_free_kdc_rep (context, &rep);
597 return ret;
600 krb5_error_code
601 krb5_get_in_tkt(krb5_context context,
602 krb5_flags options,
603 const krb5_addresses *addrs,
604 const krb5_enctype *etypes,
605 const krb5_preauthtype *ptypes,
606 krb5_key_proc key_proc,
607 krb5_const_pointer keyseed,
608 krb5_decrypt_proc decrypt_proc,
609 krb5_const_pointer decryptarg,
610 krb5_creds *creds,
611 krb5_ccache ccache,
612 krb5_kdc_rep *ret_as_reply)
614 krb5_error_code ret;
615 krb5_kdc_flags opts;
616 opts.i = 0;
617 opts.b = int2KDCOptions(options);
619 ret = krb5_get_in_cred (context,
620 opts.i,
621 addrs,
622 etypes,
623 ptypes,
624 key_proc,
625 keyseed,
626 decrypt_proc,
627 decryptarg,
628 creds,
629 ret_as_reply);
630 if(ret)
631 return ret;
632 ret = krb5_cc_store_cred (context, ccache, creds);
633 krb5_free_creds_contents (context, creds);
634 return ret;