/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- krb5_init_etype
- check_server_referral
- check_client_referral
- decrypt_tkt
- _krb5_extract_ticket
- make_pa_enc_timestamp
- add_padata
- init_as_req
- set_ptypes
- krb5_get_in_cred
- krb5_get_in_tkt
1 /*
2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
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.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include "krb5_locl.h"
35
36 RCSID("$Id$");
37
38 krb5_error_code KRB5_LIB_FUNCTION
39 krb5_init_etype (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
40 unsigned *len,
41 krb5_enctype **val,
42 const krb5_enctype *etypes)
43 {
44 unsigned int i;
45 krb5_error_code ret;
46 krb5_enctype *tmp = NULL;
47
48 ret = 0;
49 if (etypes == NULL) {
50 ret = krb5_get_default_in_tkt_etypes(context,
51 &tmp);
52 if (ret)
53 return ret;
54 etypes = tmp;
55 }
56
57 for (i = 0; etypes[i]; ++i)
58 ;
59 *len = i;
60 *val = malloc(i * sizeof(**val));
61 if (i != 0 && *val == NULL) {
62 ret = ENOMEM;
63 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
64 goto cleanup;
65 }
66 memmove (*val,
67 etypes,
68 i * sizeof(*tmp));
69 cleanup:
70 if (tmp != NULL)
71 free (tmp);
72 return ret;
73 }
74
75 static krb5_error_code
76 check_server_referral(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
77 krb5_kdc_rep *rep,
78 unsigned flags,
79 krb5_const_principal requested,
80 krb5_const_principal returned,
81 const krb5_keyblock const * key)
82 {
83 krb5_error_code ret;
84 PA_ServerReferralData ref;
85 krb5_crypto session;
86 EncryptedData ed;
87 size_t len;
88 krb5_data data;
89 PA_DATA *pa;
90 int i = 0, cmp;
91
92 if (rep->kdc_rep.padata == NULL)
93 goto noreferral;
94
95 pa = krb5_find_padata(rep->kdc_rep.padata->val,
96 rep->kdc_rep.padata->len,
97 KRB5_PADATA_SERVER_REFERRAL, &i);
98 if (pa == NULL)
99 goto noreferral;
100
101 memset(&ed, 0, sizeof(ed));
102 memset(&ref, 0, sizeof(ref));
103
104 ret = decode_EncryptedData(pa->padata_value.data,
105 pa->padata_value.length,
106 &ed, &len);
107 if (ret)
108 return ret;
109 if (len != pa->padata_value.length) {
110 free_EncryptedData(&ed);
111 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
112 N_("Referral EncryptedData wrong for realm %s",
113 "realm"), requested->realm);
114 return KRB5KRB_AP_ERR_MODIFIED;
115 }
116
117 ret = krb5_crypto_init(context, key, 0, &session);
118 if (ret) {
119 free_EncryptedData(&ed);
120 return ret;
121 }
122
123 ret = krb5_decrypt_EncryptedData(context, session,
124 KRB5_KU_PA_SERVER_REFERRAL,
125 &ed, &data);
126 free_EncryptedData(&ed);
127 krb5_crypto_destroy(context, session);
128 if (ret)
129 return ret;
130
131 ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len);
132 if (ret) {
133 krb5_data_free(&data);
134 return ret;
135 }
136 krb5_data_free(&data);
137
138 if (strcmp(requested->realm, returned->realm) != 0) {
139 free_PA_ServerReferralData(&ref);
140 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
141 N_("server ref realm mismatch, "
142 "requested realm %s got back %s", ""),
143 requested->realm, returned->realm);
144 return KRB5KRB_AP_ERR_MODIFIED;
145 }
146
147 if (returned->name.name_string.len == 2 &&
148 strcmp(returned->name.name_string.val[0], KRB5_TGS_NAME) == 0)
149 {
150 const char *realm = returned->name.name_string.val[1];
151
152 if (ref.referred_realm == NULL
153 || strcmp(*ref.referred_realm, realm) != 0)
154 {
155 free_PA_ServerReferralData(&ref);
156 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
157 N_("tgt returned with wrong ref", ""));
158 return KRB5KRB_AP_ERR_MODIFIED;
159 }
160 } else if (krb5_principal_compare(context, returned, requested) == 0) {
161 free_PA_ServerReferralData(&ref);
162 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
163 N_("req princ no same as returned", ""));
164 return KRB5KRB_AP_ERR_MODIFIED;
165 }
166
167 if (ref.requested_principal_name) {
168 cmp = _krb5_principal_compare_PrincipalName(context,
169 requested,
170 ref.requested_principal_name);
171 if (!cmp) {
172 free_PA_ServerReferralData(&ref);
173 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
174 N_("referred principal not same "
175 "as requested", ""));
176 return KRB5KRB_AP_ERR_MODIFIED;
177 }
178 } else if (flags & EXTRACT_TICKET_AS_REQ) {
179 free_PA_ServerReferralData(&ref);
180 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
181 N_("Requested principal missing on AS-REQ", ""));
182 return KRB5KRB_AP_ERR_MODIFIED;
183 }
184
185 free_PA_ServerReferralData(&ref);
186
187 return ret;
188 noreferral:
189 if (krb5_principal_compare(context, requested, returned) == FALSE) {
190 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
191 N_("Not same server principal returned "
192 "as requested", ""));
193 return KRB5KRB_AP_ERR_MODIFIED;
194 }
195 return 0;
196 }
197
198
199 /*
200 * Verify referral data
201 */
202
203
204 static krb5_error_code
205 check_client_referral(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
206 krb5_kdc_rep *rep,
207 krb5_const_principal requested,
208 krb5_const_principal mapped,
209 krb5_keyblock const * key)
210 {
211 krb5_error_code ret;
212 PA_ClientCanonicalized canon;
213 krb5_crypto crypto;
214 krb5_data data;
215 PA_DATA *pa;
216 size_t len;
217 int i = 0;
218
219 if (rep->kdc_rep.padata == NULL)
220 goto noreferral;
221
222 pa = krb5_find_padata(rep->kdc_rep.padata->val,
223 rep->kdc_rep.padata->len,
224 KRB5_PADATA_CLIENT_CANONICALIZED, &i);
225 if (pa == NULL)
226 goto noreferral;
227
228 ret = decode_PA_ClientCanonicalized(pa->padata_value.data,
229 pa->padata_value.length,
230 &canon, &len);
231 if (ret) {
232 krb5_set_error_message(context, ret,
233 N_("Failed to decode ClientCanonicalized "
234 "from realm %s", ""), requested->realm);
235 return ret;
236 }
237
238 ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length,
239 &canon.names, &len, ret);
240 if (ret) {
241 free_PA_ClientCanonicalized(&canon);
242 return ret;
243 }
244 if (data.length != len)
245 krb5_abortx(context, "internal asn.1 error");
246
247 ret = krb5_crypto_init(context, key, 0, &crypto);
248 if (ret) {
249 free(data.data);
250 free_PA_ClientCanonicalized(&canon);
251 return ret;
252 }
253
254 ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES,
255 data.data, data.length,
256 &canon.canon_checksum);
257 krb5_crypto_destroy(context, crypto);
258 free(data.data);
259 if (ret) {
260 krb5_set_error_message(context, ret,
261 N_("Failed to verify client canonicalized "
262 "data from realm %s", ""),
263 requested->realm);
264 free_PA_ClientCanonicalized(&canon);
265 return ret;
266 }
267
268 if (!_krb5_principal_compare_PrincipalName(context,
269 requested,
270 &canon.names.requested_name))
271 {
272 free_PA_ClientCanonicalized(&canon);
273 krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
274 N_("Requested name doesn't match"
275 " in client referral", ""));
276 return KRB5_PRINC_NOMATCH;
277 }
278 if (!_krb5_principal_compare_PrincipalName(context,
279 mapped,
280 &canon.names.mapped_name))
281 {
282 free_PA_ClientCanonicalized(&canon);
283 krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
284 N_("Mapped name doesn't match"
285 " in client referral", ""));
286 return KRB5_PRINC_NOMATCH;
287 }
288
289 return 0;
290
291 noreferral:
292 if (krb5_principal_compare(context, requested, mapped) == FALSE) {
293 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
294 N_("Not same client principal returned "
295 "as requested", ""));
296 return KRB5KRB_AP_ERR_MODIFIED;
297 }
298 return 0;
299 }
300
301
302
303 static krb5_error_code
304 decrypt_tkt (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
305 krb5_keyblock *key,
306 krb5_key_usage usage,
307 krb5_const_pointer decrypt_arg,
308 krb5_kdc_rep *dec_rep)
309 {
310 krb5_error_code ret;
311 krb5_data data;
312 size_t size;
313 krb5_crypto crypto;
314
315 ret = krb5_crypto_init(context, key, 0, &crypto);
316 if (ret)
317 return ret;
318
319 ret = krb5_decrypt_EncryptedData (context,
320 crypto,
321 usage,
322 &dec_rep->kdc_rep.enc_part,
323 &data);
324 krb5_crypto_destroy(context, crypto);
325
326 if (ret)
327 return ret;
328
329 ret = krb5_decode_EncASRepPart(context,
330 data.data,
331 data.length,
332 &dec_rep->enc_part,
333 &size);
334 if (ret)
335 ret = krb5_decode_EncTGSRepPart(context,
336 data.data,
337 data.length,
338 &dec_rep->enc_part,
339 &size);
340 krb5_data_free (&data);
341 if (ret)
342 return ret;
343 return 0;
344 }
345
346 int
347 _krb5_extract_ticket(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
348 krb5_kdc_rep *rep,
349 krb5_creds *creds,
350 krb5_keyblock *key,
351 krb5_const_pointer keyseed,
352 krb5_key_usage key_usage,
353 krb5_addresses *addrs,
354 unsigned nonce,
355 unsigned flags,
356 krb5_decrypt_proc decrypt_proc,
357 krb5_const_pointer decryptarg)
358 {
359 krb5_error_code ret;
360 krb5_principal tmp_principal;
361 size_t len;
362 time_t tmp_time;
363 krb5_timestamp sec_now;
364
365 /* decrypt */
366
367 if (decrypt_proc == NULL)
368 decrypt_proc = decrypt_tkt;
369
370 ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
371 if (ret)
372 goto out;
373
374 /* save session key */
375
376 creds->session.keyvalue.length = 0;
377 creds->session.keyvalue.data = NULL;
378 creds->session.keytype = rep->enc_part.key.keytype;
379 ret = krb5_data_copy (&creds->session.keyvalue,
380 rep->enc_part.key.keyvalue.data,
381 rep->enc_part.key.keyvalue.length);
382 if (ret) {
383 krb5_clear_error_message(context);
384 goto out;
385 }
386
387 /*
388 * HACK:
389 * this is really a ugly hack, to support using the Netbios Domain Name
390 * as realm against windows KDC's, they always return the full realm
391 * based on the DNS Name.
392 */
393 flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
394 flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
395
396 /* compare client and save */
397 ret = _krb5_principalname2krb5_principal (context,
398 &tmp_principal,
399 rep->kdc_rep.cname,
400 rep->kdc_rep.crealm);
401 if (ret)
402 goto out;
403
404 /* check client referral and save principal */
405 /* anonymous here ? */
406 if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) {
407 ret = check_client_referral(context, rep,
408 creds->client,
409 tmp_principal,
410 &creds->session);
411 if (ret) {
412 krb5_free_principal (context, tmp_principal);
413 goto out;
414 }
415 }
416 krb5_free_principal (context, creds->client);
417 creds->client = tmp_principal;
418
419 /* check server referral and save principal */
420 ret = _krb5_principalname2krb5_principal (context,
421 &tmp_principal,
422 rep->kdc_rep.ticket.sname,
423 rep->kdc_rep.ticket.realm);
424 if (ret)
425 goto out;
426 if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){
427 ret = check_server_referral(context,
428 rep,
429 flags,
430 creds->server,
431 tmp_principal,
432 &creds->session);
433 if (ret) {
434 krb5_free_principal (context, tmp_principal);
435 goto out;
436 }
437 }
438 krb5_free_principal(context, creds->server);
439 creds->server = tmp_principal;
440
441 /* verify names */
442 if(flags & EXTRACT_TICKET_MATCH_REALM){
443 const char *srealm = krb5_principal_get_realm(context, creds->server);
444 const char *crealm = krb5_principal_get_realm(context, creds->client);
445
446 if (strcmp(rep->enc_part.srealm, srealm) != 0 ||
447 strcmp(rep->enc_part.srealm, crealm) != 0)
448 {
449 ret = KRB5KRB_AP_ERR_MODIFIED;
450 krb5_clear_error_message(context);
451 goto out;
452 }
453 }
454
455 /* compare nonces */
456
457 if (nonce != rep->enc_part.nonce) {
458 ret = KRB5KRB_AP_ERR_MODIFIED;
459 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
460 goto out;
461 }
462
463 /* set kdc-offset */
464
465 krb5_timeofday (context, &sec_now);
466 if (rep->enc_part.flags.initial
467 && context->kdc_sec_offset == 0
468 && krb5_config_get_bool (context, NULL,
469 "libdefaults",
470 "kdc_timesync",
471 NULL)) {
472 context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
473 krb5_timeofday (context, &sec_now);
474 }
475
476 /* check all times */
477
478 if (rep->enc_part.starttime) {
479 tmp_time = *rep->enc_part.starttime;
480 } else
481 tmp_time = rep->enc_part.authtime;
482
483 if (creds->times.starttime == 0
484 && abs(tmp_time - sec_now) > context->max_skew) {
485 ret = KRB5KRB_AP_ERR_SKEW;
486 krb5_set_error_message (context, ret,
487 N_("time skew (%d) larger than max (%d)", ""),
488 abs(tmp_time - sec_now),
489 (int)context->max_skew);
490 goto out;
491 }
492
493 if (creds->times.starttime != 0
494 && tmp_time != creds->times.starttime) {
495 krb5_clear_error_message (context);
496 ret = KRB5KRB_AP_ERR_MODIFIED;
497 goto out;
498 }
499
500 creds->times.starttime = tmp_time;
501
502 if (rep->enc_part.renew_till) {
503 tmp_time = *rep->enc_part.renew_till;
504 } else
505 tmp_time = 0;
506
507 if (creds->times.renew_till != 0
508 && tmp_time > creds->times.renew_till) {
509 krb5_clear_error_message (context);
510 ret = KRB5KRB_AP_ERR_MODIFIED;
511 goto out;
512 }
513
514 creds->times.renew_till = tmp_time;
515
516 creds->times.authtime = rep->enc_part.authtime;
517
518 if (creds->times.endtime != 0
519 && rep->enc_part.endtime > creds->times.endtime) {
520 krb5_clear_error_message (context);
521 ret = KRB5KRB_AP_ERR_MODIFIED;
522 goto out;
523 }
524
525 creds->times.endtime = rep->enc_part.endtime;
526
527 if(rep->enc_part.caddr)
528 krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
529 else if(addrs)
530 krb5_copy_addresses (context, addrs, &creds->addresses);
531 else {
532 creds->addresses.len = 0;
533 creds->addresses.val = NULL;
534 }
535 creds->flags.b = rep->enc_part.flags;
536
537 creds->authdata.len = 0;
538 creds->authdata.val = NULL;
539
540 /* extract ticket */
541 ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
542 &rep->kdc_rep.ticket, &len, ret);
543 if(ret)
544 goto out;
545 if (creds->ticket.length != len)
546 krb5_abortx(context, "internal error in ASN.1 encoder");
547 creds->second_ticket.length = 0;
548 creds->second_ticket.data = NULL;
549
550
551 out:
552 memset (rep->enc_part.key.keyvalue.data, 0,
553 rep->enc_part.key.keyvalue.length);
554 return ret;
555 }
556
557
558 static krb5_error_code
559 make_pa_enc_timestamp(krb5_context context, PA_DATA *pa,
/* [<][>][^][v][top][bottom][index][help] */
560 krb5_enctype etype, krb5_keyblock *key)
561 {
562 PA_ENC_TS_ENC p;
563 unsigned char *buf;
564 size_t buf_size;
565 size_t len;
566 EncryptedData encdata;
567 krb5_error_code ret;
568 int32_t usec;
569 int usec2;
570 krb5_crypto crypto;
571
572 krb5_us_timeofday (context, &p.patimestamp, &usec);
573 usec2 = usec;
574 p.pausec = &usec2;
575
576 ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
577 if (ret)
578 return ret;
579 if(buf_size != len)
580 krb5_abortx(context, "internal error in ASN.1 encoder");
581 ret = krb5_crypto_init(context, key, 0, &crypto);
582 if (ret) {
583 free(buf);
584 return ret;
585 }
586 ret = krb5_encrypt_EncryptedData(context,
587 crypto,
588 KRB5_KU_PA_ENC_TIMESTAMP,
589 buf,
590 len,
591 0,
592 &encdata);
593 free(buf);
594 krb5_crypto_destroy(context, crypto);
595 if (ret)
596 return ret;
597
598 ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
599 free_EncryptedData(&encdata);
600 if (ret)
601 return ret;
602 if(buf_size != len)
603 krb5_abortx(context, "internal error in ASN.1 encoder");
604 pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP;
605 pa->padata_value.length = len;
606 pa->padata_value.data = buf;
607 return 0;
608 }
609
610 static krb5_error_code
611 add_padata(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
612 METHOD_DATA *md,
613 krb5_principal client,
614 krb5_key_proc key_proc,
615 krb5_const_pointer keyseed,
616 krb5_enctype *enctypes,
617 unsigned netypes,
618 krb5_salt *salt)
619 {
620 krb5_error_code ret;
621 PA_DATA *pa2;
622 krb5_salt salt2;
623 krb5_enctype *ep;
624 int i;
625
626 if(salt == NULL) {
627 /* default to standard salt */
628 ret = krb5_get_pw_salt (context, client, &salt2);
629 salt = &salt2;
630 }
631 if (!enctypes) {
632 enctypes = context->etypes;
633 netypes = 0;
634 for (ep = enctypes; *ep != ETYPE_NULL; ep++)
635 netypes++;
636 }
637 pa2 = realloc (md->val, (md->len + netypes) * sizeof(*md->val));
638 if (pa2 == NULL) {
639 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
640 return ENOMEM;
641 }
642 md->val = pa2;
643
644 for (i = 0; i < netypes; ++i) {
645 krb5_keyblock *key;
646
647 ret = (*key_proc)(context, enctypes[i], *salt, keyseed, &key);
648 if (ret)
649 continue;
650 ret = make_pa_enc_timestamp (context, &md->val[md->len],
651 enctypes[i], key);
652 krb5_free_keyblock (context, key);
653 if (ret)
654 return ret;
655 ++md->len;
656 }
657 if(salt == &salt2)
658 krb5_free_salt(context, salt2);
659 return 0;
660 }
661
662 static krb5_error_code
663 init_as_req (krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
664 KDCOptions opts,
665 krb5_creds *creds,
666 const krb5_addresses *addrs,
667 const krb5_enctype *etypes,
668 const krb5_preauthtype *ptypes,
669 const krb5_preauthdata *preauth,
670 krb5_key_proc key_proc,
671 krb5_const_pointer keyseed,
672 unsigned nonce,
673 AS_REQ *a)
674 {
675 krb5_error_code ret;
676 krb5_salt salt;
677
678 memset(a, 0, sizeof(*a));
679
680 a->pvno = 5;
681 a->msg_type = krb_as_req;
682 a->req_body.kdc_options = opts;
683 a->req_body.cname = malloc(sizeof(*a->req_body.cname));
684 if (a->req_body.cname == NULL) {
685 ret = ENOMEM;
686 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
687 goto fail;
688 }
689 a->req_body.sname = malloc(sizeof(*a->req_body.sname));
690 if (a->req_body.sname == NULL) {
691 ret = ENOMEM;
692 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
693 goto fail;
694 }
695 ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
696 if (ret)
697 goto fail;
698 ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
699 if (ret)
700 goto fail;
701 ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
702 if (ret)
703 goto fail;
704
705 if(creds->times.starttime) {
706 a->req_body.from = malloc(sizeof(*a->req_body.from));
707 if (a->req_body.from == NULL) {
708 ret = ENOMEM;
709 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
710 goto fail;
711 }
712 *a->req_body.from = creds->times.starttime;
713 }
714 if(creds->times.endtime){
715 ALLOC(a->req_body.till, 1);
716 *a->req_body.till = creds->times.endtime;
717 }
718 if(creds->times.renew_till){
719 a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
720 if (a->req_body.rtime == NULL) {
721 ret = ENOMEM;
722 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
723 goto fail;
724 }
725 *a->req_body.rtime = creds->times.renew_till;
726 }
727 a->req_body.nonce = nonce;
728 ret = krb5_init_etype (context,
729 &a->req_body.etype.len,
730 &a->req_body.etype.val,
731 etypes);
732 if (ret)
733 goto fail;
734
735 /*
736 * This means no addresses
737 */
738
739 if (addrs && addrs->len == 0) {
740 a->req_body.addresses = NULL;
741 } else {
742 a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
743 if (a->req_body.addresses == NULL) {
744 ret = ENOMEM;
745 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
746 goto fail;
747 }
748
749 if (addrs)
750 ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
751 else {
752 ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
753 if(ret == 0 && a->req_body.addresses->len == 0) {
754 free(a->req_body.addresses);
755 a->req_body.addresses = NULL;
756 }
757 }
758 if (ret)
759 return ret;
760 }
761
762 a->req_body.enc_authorization_data = NULL;
763 a->req_body.additional_tickets = NULL;
764
765 if(preauth != NULL) {
766 int i;
767 ALLOC(a->padata, 1);
768 if(a->padata == NULL) {
769 ret = ENOMEM;
770 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
771 goto fail;
772 }
773 a->padata->val = NULL;
774 a->padata->len = 0;
775 for(i = 0; i < preauth->len; i++) {
776 if(preauth->val[i].type == KRB5_PADATA_ENC_TIMESTAMP){
777 int j;
778
779 for(j = 0; j < preauth->val[i].info.len; j++) {
780 krb5_salt *sp = &salt;
781 if(preauth->val[i].info.val[j].salttype)
782 salt.salttype = *preauth->val[i].info.val[j].salttype;
783 else
784 salt.salttype = KRB5_PW_SALT;
785 if(preauth->val[i].info.val[j].salt)
786 salt.saltvalue = *preauth->val[i].info.val[j].salt;
787 else
788 if(salt.salttype == KRB5_PW_SALT)
789 sp = NULL;
790 else
791 krb5_data_zero(&salt.saltvalue);
792 ret = add_padata(context, a->padata, creds->client,
793 key_proc, keyseed,
794 &preauth->val[i].info.val[j].etype, 1,
795 sp);
796 if (ret == 0)
797 break;
798 }
799 }
800 }
801 } else
802 /* not sure this is the way to use `ptypes' */
803 if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE)
804 a->padata = NULL;
805 else if (*ptypes == KRB5_PADATA_ENC_TIMESTAMP) {
806 ALLOC(a->padata, 1);
807 if (a->padata == NULL) {
808 ret = ENOMEM;
809 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
810 goto fail;
811 }
812 a->padata->len = 0;
813 a->padata->val = NULL;
814
815 /* make a v5 salted pa-data */
816 add_padata(context, a->padata, creds->client,
817 key_proc, keyseed, a->req_body.etype.val,
818 a->req_body.etype.len, NULL);
819
820 /* make a v4 salted pa-data */
821 salt.salttype = KRB5_PW_SALT;
822 krb5_data_zero(&salt.saltvalue);
823 add_padata(context, a->padata, creds->client,
824 key_proc, keyseed, a->req_body.etype.val,
825 a->req_body.etype.len, &salt);
826 } else {
827 ret = KRB5_PREAUTH_BAD_TYPE;
828 krb5_set_error_message (context, ret,
829 N_("pre-auth type %d not supported", ""),
830 *ptypes);
831 goto fail;
832 }
833 return 0;
834 fail:
835 free_AS_REQ(a);
836 return ret;
837 }
838
839 static int
840 set_ptypes(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
841 KRB_ERROR *error,
842 const krb5_preauthtype **ptypes,
843 krb5_preauthdata **preauth)
844 {
845 static krb5_preauthdata preauth2;
846 static krb5_preauthtype ptypes2[] = { KRB5_PADATA_ENC_TIMESTAMP, KRB5_PADATA_NONE };
847
848 if(error->e_data) {
849 METHOD_DATA md;
850 int i;
851 decode_METHOD_DATA(error->e_data->data,
852 error->e_data->length,
853 &md,
854 NULL);
855 for(i = 0; i < md.len; i++){
856 switch(md.val[i].padata_type){
857 case KRB5_PADATA_ENC_TIMESTAMP:
858 *ptypes = ptypes2;
859 break;
860 case KRB5_PADATA_ETYPE_INFO:
861 *preauth = &preauth2;
862 ALLOC_SEQ(*preauth, 1);
863 (*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP;
864 krb5_decode_ETYPE_INFO(context,
865 md.val[i].padata_value.data,
866 md.val[i].padata_value.length,
867 &(*preauth)->val[0].info,
868 NULL);
869 break;
870 default:
871 break;
872 }
873 }
874 free_METHOD_DATA(&md);
875 } else {
876 *ptypes = ptypes2;
877 }
878 return(1);
879 }
880
881 krb5_error_code KRB5_LIB_FUNCTION
882 krb5_get_in_cred(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
883 krb5_flags options,
884 const krb5_addresses *addrs,
885 const krb5_enctype *etypes,
886 const krb5_preauthtype *ptypes,
887 const krb5_preauthdata *preauth,
888 krb5_key_proc key_proc,
889 krb5_const_pointer keyseed,
890 krb5_decrypt_proc decrypt_proc,
891 krb5_const_pointer decryptarg,
892 krb5_creds *creds,
893 krb5_kdc_rep *ret_as_reply)
894 {
895 krb5_error_code ret;
896 AS_REQ a;
897 krb5_kdc_rep rep;
898 krb5_data req, resp;
899 size_t len;
900 krb5_salt salt;
901 krb5_keyblock *key;
902 size_t size;
903 KDCOptions opts;
904 PA_DATA *pa;
905 krb5_enctype etype;
906 krb5_preauthdata *my_preauth = NULL;
907 unsigned nonce;
908 int done;
909
910 opts = int2KDCOptions(options);
911
912 krb5_generate_random_block (&nonce, sizeof(nonce));
913 nonce &= 0xffffffff;
914
915 do {
916 done = 1;
917 ret = init_as_req (context,
918 opts,
919 creds,
920 addrs,
921 etypes,
922 ptypes,
923 preauth,
924 key_proc,
925 keyseed,
926 nonce,
927 &a);
928 if (my_preauth) {
929 free_ETYPE_INFO(&my_preauth->val[0].info);
930 free (my_preauth->val);
931 my_preauth = NULL;
932 }
933 if (ret)
934 return ret;
935
936 ASN1_MALLOC_ENCODE(AS_REQ, req.data, req.length, &a, &len, ret);
937 free_AS_REQ(&a);
938 if (ret)
939 return ret;
940 if(len != req.length)
941 krb5_abortx(context, "internal error in ASN.1 encoder");
942
943 ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp);
944 krb5_data_free(&req);
945 if (ret)
946 return ret;
947
948 memset (&rep, 0, sizeof(rep));
949 ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
950 if(ret) {
951 /* let's try to parse it as a KRB-ERROR */
952 KRB_ERROR error;
953 int ret2;
954
955 ret2 = krb5_rd_error(context, &resp, &error);
956 if(ret2 && resp.data && ((char*)resp.data)[0] == 4)
957 ret = KRB5KRB_AP_ERR_V4_REPLY;
958 krb5_data_free(&resp);
959 if (ret2 == 0) {
960 ret = krb5_error_from_rd_error(context, &error, creds);
961 /* if no preauth was set and KDC requires it, give it
962 one more try */
963 if (!ptypes && !preauth
964 && ret == KRB5KDC_ERR_PREAUTH_REQUIRED
965 #if 0
966 || ret == KRB5KDC_ERR_BADOPTION
967 #endif
968 && set_ptypes(context, &error, &ptypes, &my_preauth)) {
969 done = 0;
970 preauth = my_preauth;
971 krb5_free_error_contents(context, &error);
972 krb5_clear_error_message(context);
973 continue;
974 }
975 if(ret_as_reply)
976 ret_as_reply->error = error;
977 else
978 free_KRB_ERROR (&error);
979 return ret;
980 }
981 return ret;
982 }
983 krb5_data_free(&resp);
984 } while(!done);
985
986 pa = NULL;
987 etype = rep.kdc_rep.enc_part.etype;
988 if(rep.kdc_rep.padata){
989 int i = 0;
990 pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len,
991 KRB5_PADATA_PW_SALT, &i);
992 if(pa == NULL) {
993 i = 0;
994 pa = krb5_find_padata(rep.kdc_rep.padata->val,
995 rep.kdc_rep.padata->len,
996 KRB5_PADATA_AFS3_SALT, &i);
997 }
998 }
999 if(pa) {
1000 salt.salttype = pa->padata_type;
1001 salt.saltvalue = pa->padata_value;
1002
1003 ret = (*key_proc)(context, etype, salt, keyseed, &key);
1004 } else {
1005 /* make a v5 salted pa-data */
1006 ret = krb5_get_pw_salt (context, creds->client, &salt);
1007
1008 if (ret)
1009 goto out;
1010 ret = (*key_proc)(context, etype, salt, keyseed, &key);
1011 krb5_free_salt(context, salt);
1012 }
1013 if (ret)
1014 goto out;
1015
1016 {
1017 unsigned flags = 0;
1018 if (opts.request_anonymous)
1019 flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
1020
1021 ret = _krb5_extract_ticket(context,
1022 &rep,
1023 creds,
1024 key,
1025 keyseed,
1026 KRB5_KU_AS_REP_ENC_PART,
1027 NULL,
1028 nonce,
1029 flags,
1030 decrypt_proc,
1031 decryptarg);
1032 }
1033 memset (key->keyvalue.data, 0, key->keyvalue.length);
1034 krb5_free_keyblock_contents (context, key);
1035 free (key);
1036
1037 out:
1038 if (ret == 0 && ret_as_reply)
1039 *ret_as_reply = rep;
1040 else
1041 krb5_free_kdc_rep (context, &rep);
1042 return ret;
1043 }
1044
1045 krb5_error_code KRB5_LIB_FUNCTION
1046 krb5_get_in_tkt(krb5_context context,
/* [<][>][^][v][top][bottom][index][help] */
1047 krb5_flags options,
1048 const krb5_addresses *addrs,
1049 const krb5_enctype *etypes,
1050 const krb5_preauthtype *ptypes,
1051 krb5_key_proc key_proc,
1052 krb5_const_pointer keyseed,
1053 krb5_decrypt_proc decrypt_proc,
1054 krb5_const_pointer decryptarg,
1055 krb5_creds *creds,
1056 krb5_ccache ccache,
1057 krb5_kdc_rep *ret_as_reply)
1058 {
1059 krb5_error_code ret;
1060
1061 ret = krb5_get_in_cred (context,
1062 options,
1063 addrs,
1064 etypes,
1065 ptypes,
1066 NULL,
1067 key_proc,
1068 keyseed,
1069 decrypt_proc,
1070 decryptarg,
1071 creds,
1072 ret_as_reply);
1073 if(ret)
1074 return ret;
1075 if (ccache)
1076 ret = krb5_cc_store_cred (context, ccache, creds);
1077 return ret;
1078 }