extract_ticket -> _krb5_extract_ticket
[heimdal.git] / lib / krb5 / get_in_tkt.c
blobdf6a7a5dd619097794f0ac9d813ac4c5b804ba0a
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_decrypt_proc decrypt_proc,
123 krb5_const_pointer decryptarg)
125 krb5_error_code err;
126 krb5_principal tmp_principal;
127 int tmp;
128 time_t tmp_time;
129 int32_t sec_now;
131 /* compare client */
133 err = principalname2krb5_principal (&tmp_principal,
134 rep->part1.cname,
135 rep->part1.crealm);
136 if (err)
137 goto out;
138 tmp = krb5_principal_compare (context, tmp_principal, creds->client);
139 krb5_free_principal (context, tmp_principal);
140 if (!tmp) {
141 err = KRB5KRB_AP_ERR_MODIFIED;
142 goto out;
145 /* extract ticket */
147 char buf[1024];
148 size_t len;
149 encode_Ticket(buf + sizeof(buf) - 1, sizeof(buf),
150 &rep->part1.ticket, &len);
151 creds->ticket.data = malloc(len);
152 memcpy(creds->ticket.data, buf + sizeof(buf) - len, len);
153 creds->ticket.length = len;
154 creds->second_ticket.length = 0;
155 creds->second_ticket.data = NULL;
158 /* compare server */
160 err = principalname2krb5_principal (&tmp_principal,
161 rep->part1.ticket.sname,
162 rep->part1.ticket.realm);
163 if (err)
164 goto out;
165 tmp = krb5_principal_compare (context, tmp_principal, creds->server);
166 krb5_free_principal (context, tmp_principal);
167 if (!tmp) {
168 err = KRB5KRB_AP_ERR_MODIFIED;
169 goto out;
172 /* decrypt */
174 if (decrypt_proc == NULL)
175 decrypt_proc = decrypt_tkt;
177 err = (*decrypt_proc)(context, key, decryptarg, rep);
178 if (err)
179 goto out;
181 /* compare nonces */
183 if (nonce != rep->part2.nonce) {
184 err = KRB5KRB_AP_ERR_MODIFIED;
185 goto out;
188 /* set kdc-offset */
190 krb5_timeofday (context, &sec_now);
191 if (context->kdc_sec_offset == 0
192 && krb5_config_get_bool (context->cf,
193 "libdefaults",
194 "kdc_timesync",
195 NULL)) {
196 context->kdc_sec_offset = rep->part2.authtime - sec_now;
197 krb5_timeofday (context, &sec_now);
200 /* check all times */
202 if (rep->part2.starttime) {
203 tmp_time = *rep->part2.starttime;
204 } else
205 tmp_time = rep->part2.authtime;
207 if (creds->times.starttime == 0
208 && abs(tmp_time - sec_now) > context->max_skew) {
209 err = KRB5KRB_AP_ERR_MODIFIED;
210 goto out;
213 if (creds->times.starttime != 0
214 && tmp_time != creds->times.starttime) {
215 err = KRB5KRB_AP_ERR_MODIFIED;
216 goto out;
219 creds->times.starttime = tmp_time;
221 if (rep->part2.renew_till) {
222 tmp_time = *rep->part2.renew_till;
223 } else
224 tmp_time = 0;
226 if (creds->times.renew_till != 0
227 && tmp_time > creds->times.renew_till) {
228 err = KRB5KRB_AP_ERR_MODIFIED;
229 goto out;
232 creds->times.renew_till = tmp_time;
234 creds->times.authtime = rep->part2.authtime;
236 if (creds->times.endtime != 0
237 && rep->part2.endtime > creds->times.endtime) {
238 err = KRB5KRB_AP_ERR_MODIFIED;
239 goto out;
242 creds->times.endtime = rep->part2.endtime;
244 if(rep->part2.caddr)
245 krb5_copy_addresses (context, rep->part2.caddr, &creds->addresses);
246 else if(addrs)
247 krb5_copy_addresses (context, addrs, &creds->addresses);
248 else {
249 creds->addresses.len = 0;
250 creds->addresses.val = NULL;
252 creds->flags.b = rep->part2.flags;
254 creds->authdata.length = 0;
255 creds->authdata.data = NULL;
256 creds->session.keyvalue.length = 0;
257 creds->session.keyvalue.data = NULL;
258 creds->session.keytype = rep->part2.key.keytype;
259 err = krb5_data_copy (&creds->session.keyvalue,
260 rep->part2.key.keyvalue.data,
261 rep->part2.key.keyvalue.length);
263 out:
264 memset (rep->part2.key.keyvalue.data, 0,
265 rep->part2.key.keyvalue.length);
266 return err;
270 static krb5_error_code
271 make_pa_enc_timestamp(krb5_context context, PA_DATA *pa, krb5_keyblock *key)
273 PA_ENC_TS_ENC p;
274 u_char buf[1024];
275 size_t len;
276 EncryptedData encdata;
277 krb5_error_code ret;
278 int32_t sec, usec;
279 unsigned usec2;
281 krb5_us_timeofday (context, &sec, &usec);
282 p.patimestamp = sec;
283 usec2 = usec;
284 p.pausec = &usec2;
286 ret = encode_PA_ENC_TS_ENC(buf + sizeof(buf) - 1,
287 sizeof(buf),
289 &len);
290 if (ret)
291 return ret;
294 * According to the spec this is the only encryption method
295 * that must be supported so it's the safest choice. On the
296 * other hand, old KDCs might not support it.
299 ret = krb5_encrypt_EncryptedData(context,
300 buf + sizeof(buf) - len,
301 len,
302 ETYPE_DES_CBC_MD5,
304 key,
305 &encdata);
306 if (ret)
307 return ret;
309 ret = encode_EncryptedData(buf + sizeof(buf) - 1,
310 sizeof(buf),
311 &encdata,
312 &len);
313 free_EncryptedData(&encdata);
314 if (ret)
315 return ret;
316 pa->padata_type = pa_enc_timestamp;
317 pa->padata_value.length = 0;
318 krb5_data_copy(&pa->padata_value,
319 buf + sizeof(buf) - len,
320 len);
321 return 0;
324 static krb5_error_code
325 init_as_req (krb5_context context,
326 krb5_kdc_flags opts,
327 krb5_creds *creds,
328 const krb5_addresses *addrs,
329 const krb5_enctype *etypes,
330 const krb5_preauthtype *ptypes,
331 krb5_key_proc key_proc,
332 krb5_const_pointer keyseed,
333 unsigned nonce,
334 AS_REQ *a)
336 krb5_error_code ret;
337 krb5_data salt;
338 krb5_keyblock *key;
339 krb5_enctype etype;
341 memset(a, 0, sizeof(*a));
343 a->pvno = 5;
344 a->msg_type = krb_as_req;
345 a->req_body.kdc_options = opts.b;
346 a->req_body.cname = malloc(sizeof(*a->req_body.cname));
347 if (a->req_body.cname == NULL) {
348 ret = ENOMEM;
349 goto fail;
351 a->req_body.sname = malloc(sizeof(*a->req_body.sname));
352 if (a->req_body.sname == NULL) {
353 ret = ENOMEM;
354 goto fail;
356 ret = krb5_principal2principalname (a->req_body.cname, creds->client);
357 if (ret)
358 goto fail;
359 ret = krb5_principal2principalname (a->req_body.sname, creds->server);
360 if (ret)
361 goto fail;
362 ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
363 if (ret)
364 goto fail;
366 if(creds->times.starttime) {
367 a->req_body.from = malloc(sizeof(*a->req_body.from));
368 if (a->req_body.from == NULL) {
369 ret = ENOMEM;
370 goto fail;
372 *a->req_body.from = creds->times.starttime;
374 if(creds->times.endtime){
375 ALLOC(a->req_body.till, 1);
376 *a->req_body.till = creds->times.endtime;
378 if(creds->times.renew_till){
379 a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
380 if (a->req_body.rtime == NULL) {
381 ret = ENOMEM;
382 goto fail;
384 *a->req_body.rtime = creds->times.renew_till;
386 a->req_body.nonce = nonce;
387 ret = krb5_init_etype (context,
388 &a->req_body.etype.len,
389 &a->req_body.etype.val,
390 etypes);
391 if (ret)
392 goto fail;
394 etype = a->req_body.etype.val[0]; /* XXX */
396 a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
397 if (a->req_body.addresses == NULL) {
398 ret = ENOMEM;
399 goto fail;
402 if (addrs)
403 ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
404 else
405 ret = krb5_get_all_client_addrs (a->req_body.addresses);
406 if (ret)
407 return ret;
409 a->req_body.enc_authorization_data = NULL;
410 a->req_body.additional_tickets = NULL;
412 /* not sure this is the way to use `ptypes' */
413 if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE)
414 a->padata = NULL;
415 else if (*ptypes == KRB5_PADATA_ENC_TIMESTAMP) {
416 a->padata = malloc(sizeof(*a->padata));
417 if (a->padata == NULL) {
418 ret = ENOMEM;
419 goto fail;
422 a->padata->len = 2;
423 a->padata->val = calloc(a->padata->len, sizeof(*a->padata->val));
424 if (a->padata->val == NULL) {
425 ret = ENOMEM;
426 goto fail;
429 /* make a v5 salted pa-data */
430 salt.length = 0;
431 salt.data = NULL;
432 ret = krb5_get_salt (creds->client, &salt);
434 if (ret)
435 goto fail;
437 ret = (*key_proc)(context, etype, &salt,
438 keyseed, &key);
439 krb5_data_free (&salt);
440 if (ret)
441 goto fail;
442 ret = make_pa_enc_timestamp(context, &a->padata->val[0], key);
443 krb5_free_keyblock (context, key);
444 free (key);
445 if (ret)
446 goto fail;
447 /* make a v4 salted pa-data */
448 salt.length = 0;
449 salt.data = NULL;
450 ret = (*key_proc)(context, etype, &salt,
451 keyseed, &key);
452 if (ret)
453 goto fail;
454 ret = make_pa_enc_timestamp(context, &a->padata->val[1], key);
455 krb5_free_keyblock (context, key);
456 free (key);
457 if (ret)
458 goto fail;
459 } else {
460 ret = KRB5_PREAUTH_BAD_TYPE;
461 goto fail;
463 return 0;
464 fail:
465 free_AS_REQ(a);
466 return ret;
469 krb5_error_code
470 krb5_get_in_cred(krb5_context context,
471 krb5_flags options,
472 const krb5_addresses *addrs,
473 const krb5_enctype *etypes,
474 const krb5_preauthtype *ptypes,
475 krb5_key_proc key_proc,
476 krb5_const_pointer keyseed,
477 krb5_decrypt_proc decrypt_proc,
478 krb5_const_pointer decryptarg,
479 krb5_creds *creds,
480 krb5_kdc_rep *ret_as_reply)
482 krb5_error_code ret;
483 AS_REQ a;
484 krb5_kdc_rep rep;
485 krb5_data req, resp;
486 char buf[BUFSIZ];
487 krb5_data salt;
488 krb5_keyblock *key;
489 size_t size;
490 krb5_kdc_flags opts;
491 PA_DATA *pa;
492 krb5_enctype etype;
493 unsigned nonce;
495 opts.i = options;
497 krb5_generate_random_block (&nonce, sizeof(nonce));
498 nonce &= 0xffffffff;
500 ret = init_as_req (context,
501 opts,
502 creds,
503 addrs,
504 etypes,
505 ptypes,
506 key_proc,
507 keyseed,
508 nonce,
509 &a);
510 if (ret)
511 return ret;
513 etype = a.req_body.etype.val[0]; /* XXX */
515 ret = encode_AS_REQ ((unsigned char*)buf + sizeof(buf) - 1,
516 sizeof(buf),
518 &req.length);
519 free_AS_REQ(&a);
520 if (ret)
521 return ret;
523 req.data = buf + sizeof(buf) - req.length;
525 ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp);
526 if (ret)
527 return ret;
529 memset (&rep, 0, sizeof(rep));
530 if((ret = decode_AS_REP(resp.data, resp.length, &rep.part1, &size))){
531 /* let's try to parse it as a KRB-ERROR */
532 KRB_ERROR error;
533 int ret2;
535 ret2 = krb5_rd_error(context, &resp, &error);
536 if(ret2 && ((char*)resp.data)[0] == 4)
537 ret = KRB5KRB_AP_ERR_V4_REPLY;
538 krb5_data_free(&resp);
539 if (ret2 == 0) {
540 /* XXX - send krb-error packet to caller */
541 free_KRB_ERROR (&error);
542 return error.error_code;
544 return ret;
546 krb5_data_free(&resp);
548 pa = NULL;
549 if(rep.part1.padata){
550 int index = 0;
551 pa = krb5_find_padata(rep.part1.padata->val, rep.part1.padata->len,
552 pa_pw_salt, &index);
554 if(pa) {
555 ret = (*key_proc)(context, etype,
556 &pa->padata_value, keyseed, &key);
557 } else {
558 /* make a v5 salted pa-data */
559 salt.length = 0;
560 salt.data = NULL;
561 ret = krb5_get_salt (creds->client, &salt);
563 if (ret)
564 return ret;
565 ret = (*key_proc)(context, etype, &salt,
566 keyseed, &key);
567 krb5_data_free (&salt);
569 if (ret)
570 return ret;
572 ret = _krb5_extract_ticket(context, &rep, creds, key, keyseed,
573 NULL, nonce, decrypt_proc, decryptarg);
574 memset (key->keyvalue.data, 0, key->keyvalue.length);
575 krb5_free_keyblock (context, key);
576 free (key);
578 if (ret == 0 && ret_as_reply)
579 *ret_as_reply = rep;
580 else
581 krb5_free_kdc_rep (context, &rep);
582 return ret;
585 krb5_error_code
586 krb5_get_in_tkt(krb5_context context,
587 krb5_flags options,
588 const krb5_addresses *addrs,
589 const krb5_enctype *etypes,
590 const krb5_preauthtype *ptypes,
591 krb5_key_proc key_proc,
592 krb5_const_pointer keyseed,
593 krb5_decrypt_proc decrypt_proc,
594 krb5_const_pointer decryptarg,
595 krb5_creds *creds,
596 krb5_ccache ccache,
597 krb5_kdc_rep *ret_as_reply)
599 krb5_error_code ret;
601 ret = krb5_get_in_cred (context,
602 options,
603 addrs,
604 etypes,
605 ptypes,
606 key_proc,
607 keyseed,
608 decrypt_proc,
609 decryptarg,
610 creds,
611 ret_as_reply);
612 if(ret)
613 return ret;
614 ret = krb5_cc_store_cred (context, ccache, creds);
615 krb5_free_creds_contents (context, creds);
616 return ret;