2 * Copyright 1995 by the Massachusetts Institute of Technology. All
5 * Export of this software from the United States of America may
6 * require a specific license from the United States Government.
7 * It is the responsibility of any person or organization contemplating
8 * export to obtain such a license before exporting.
10 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
11 * distribute this software and its documentation for any purpose and
12 * without fee is hereby granted, provided that the above copyright
13 * notice appear in all copies and that both that copyright notice and
14 * this permission notice appear in supporting documentation, and that
15 * the name of M.I.T. not be used in advertising or publicity pertaining
16 * to distribution of the software without specific, written prior
17 * permission. Furthermore if you modify this software you must label
18 * your software as modified software and not distribute it in such a
19 * fashion that it might be confused with the original M.I.T. software.
20 * M.I.T. makes no representations about the suitability of
21 * this software for any purpose. It is provided "as is" without express
22 * or implied warranty.
27 * This file contains routines for establishing, verifying, and any other
28 * necessary functions, for utilizing the pre-authentication field of the
29 * kerberos kdc request, with various hardware/software verification devices.
34 typedef krb5_error_code (*pa_function)(krb5_context,
35 krb5_kdc_req *request,
36 krb5_pa_data *in_padata,
37 krb5_pa_data **out_padata,
40 krb5_keyblock *as_key,
41 krb5_prompter_fct prompter_fct,
43 krb5_gic_get_as_key_fct gak_fct,
46 typedef struct _pa_types_t {
47 krb5_preauthtype type;
52 #define PA_REAL 0x0001
53 #define PA_INFO 0x0002
56 krb5_error_code pa_salt(krb5_context context,
57 krb5_kdc_req *request,
58 krb5_pa_data *in_padata,
59 krb5_pa_data **out_padata,
62 krb5_keyblock *as_key,
63 krb5_prompter_fct prompter, void *prompter_data,
64 krb5_gic_get_as_key_fct gak_fct, void *gak_data)
68 /* screw the abstraction. If there was a *reasonable* copy_data,
69 I'd use it. But I'm inside the library, which is the twilight
70 zone of source code, so I can do anything. */
72 tmp.length = in_padata->length;
74 if ((tmp.data = malloc(tmp.length)) == NULL)
76 memcpy(tmp.data, in_padata->contents, tmp.length);
83 /* assume that no other salt was allocated */
85 if (in_padata->pa_type == KRB5_PADATA_AFS3_SALT)
86 salt->length = SALT_TYPE_AFS_LENGTH;
92 krb5_error_code pa_enc_timestamp(krb5_context context,
93 krb5_kdc_req *request,
94 krb5_pa_data *in_padata,
95 krb5_pa_data **out_padata,
98 krb5_keyblock *as_key,
99 krb5_prompter_fct prompter,
101 krb5_gic_get_as_key_fct gak_fct,
105 krb5_pa_enc_ts pa_enc;
107 krb5_enc_data enc_data;
110 if (as_key->length == 0) {
112 fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__,
114 if (salt->length > 0)
115 fprintf (stderr, " '%*s'", salt->length, salt->data);
116 fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n",
117 *etype, request->ktype[0]);
119 if ((ret = ((*gak_fct)(context, request->client,
120 *etype ? *etype : request->ktype[0],
121 prompter, prompter_data,
122 salt, as_key, gak_data))))
126 /* now get the time of day, and encrypt it accordingly */
128 if ((ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec)))
131 if ((ret = encode_krb5_pa_enc_ts(&pa_enc, &tmp)))
135 fprintf (stderr, "key type %d bytes %02x %02x ...\n",
137 as_key->contents[0], as_key->contents[1]);
139 ret = krb5_encrypt_helper(context, as_key,
140 KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
143 fprintf (stderr, "enc data { type=%d kvno=%d data=%02x %02x ... }\n",
144 enc_data.enctype, enc_data.kvno,
145 0xff & enc_data.ciphertext.data[0],
146 0xff & enc_data.ciphertext.data[1]);
149 krb5_free_data(context, tmp);
152 krb5_xfree(enc_data.ciphertext.data);
156 ret = encode_krb5_enc_data(&enc_data, &tmp);
158 krb5_xfree(enc_data.ciphertext.data);
163 if ((pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
164 krb5_free_data(context, tmp);
168 pa->magic = KV5M_PA_DATA;
169 pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
170 pa->length = tmp->length;
171 pa->contents = (krb5_octet *) tmp->data;
181 char *sam_challenge_banner(krb5_int32 sam_type)
186 case PA_SAM_TYPE_ENIGMA: /* Enigma Logic */
187 label = "Challenge for Enigma Logic mechanism";
189 case PA_SAM_TYPE_DIGI_PATH: /* Digital Pathways */
190 case PA_SAM_TYPE_DIGI_PATH_HEX: /* Digital Pathways */
191 label = "Challenge for Digital Pathways mechanism";
193 case PA_SAM_TYPE_ACTIVCARD_DEC: /* Digital Pathways */
194 case PA_SAM_TYPE_ACTIVCARD_HEX: /* Digital Pathways */
195 label = "Challenge for Activcard mechanism";
197 case PA_SAM_TYPE_SKEY_K0: /* S/key where KDC has key 0 */
198 label = "Challenge for Enhanced S/Key mechanism";
200 case PA_SAM_TYPE_SKEY: /* Traditional S/Key */
201 label = "Challenge for Traditional S/Key mechanism";
203 case PA_SAM_TYPE_SECURID: /* Security Dynamics */
204 label = "Challenge for Security Dynamics mechanism";
206 case PA_SAM_TYPE_SECURID_PREDICT: /* predictive Security Dynamics */
207 label = "Challenge for Security Dynamics mechanism";
210 label = "Challenge from authentication server";
217 /* this macro expands to the int,ptr necessary for "%.*s" in an sprintf */
219 #define SAMDATA(kdata, str, maxsize) \
220 (int)((kdata.length)? \
221 ((((kdata.length)<=(maxsize))?(kdata.length):strlen(str))): \
224 ((((kdata.length)<=(maxsize))?(kdata.data):(str))):(str)
226 /* XXX Danger! This code is not in sync with the kerberos-password-02
227 draft. This draft cannot be implemented as written. This code is
228 compatible with earlier versions of mit krb5 and cygnus kerbnet. */
231 krb5_error_code pa_sam(krb5_context context,
232 krb5_kdc_req *request,
233 krb5_pa_data *in_padata,
234 krb5_pa_data **out_padata,
237 krb5_keyblock *as_key,
238 krb5_prompter_fct prompter,
240 krb5_gic_get_as_key_fct gak_fct,
245 char name[100], banner[100];
246 char prompt[100], response[100];
247 krb5_data response_data;
249 krb5_prompt_type prompt_type;
251 krb5_sam_challenge *sam_challenge = 0;
252 krb5_sam_response sam_response;
253 /* these two get encrypted and stuffed in to sam_response */
254 krb5_enc_sam_response_enc enc_sam_response_enc;
258 if (prompter == NULL)
261 tmpsam.length = in_padata->length;
262 tmpsam.data = (char *) in_padata->contents;
263 if ((ret = decode_krb5_sam_challenge(&tmpsam, &sam_challenge)))
266 if (sam_challenge->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
267 krb5_xfree(sam_challenge);
268 return(KRB5_SAM_UNSUPPORTED);
271 /* If we need the password from the user (USE_SAD_AS_KEY not set), */
272 /* then get it here. Exception for "old" KDCs with CryptoCard */
273 /* support which uses the USE_SAD_AS_KEY flag, but still needs pwd */
275 if (!(sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) ||
276 (sam_challenge->sam_type == PA_SAM_TYPE_CRYPTOCARD)) {
278 /* etype has either been set by caller or by KRB5_PADATA_ETYPE_INFO */
279 /* message from the KDC. If it is not set, pick an enctype that we */
280 /* think the KDC will have for us. */
282 if (etype && *etype == 0)
283 *etype = ENCTYPE_DES_CBC_CRC;
285 if (ret = (gak_fct)(context, request->client, *etype, prompter,
286 prompter_data, salt, as_key, gak_data))
289 sprintf(name, "%.*s",
290 SAMDATA(sam_challenge->sam_type_name, "SAM Authentication",
293 sprintf(banner, "%.*s",
294 SAMDATA(sam_challenge->sam_challenge_label,
295 sam_challenge_banner(sam_challenge->sam_type),
298 /* sprintf(prompt, "Challenge is [%s], %s: ", challenge, prompt); */
299 sprintf(prompt, "%s%.*s%s%.*s",
300 sam_challenge->sam_challenge.length?"Challenge is [":"",
301 SAMDATA(sam_challenge->sam_challenge, "", 20),
302 sam_challenge->sam_challenge.length?"], ":"",
303 SAMDATA(sam_challenge->sam_response_prompt, "passcode", 55));
305 response_data.data = response;
306 response_data.length = sizeof(response);
308 kprompt.prompt = prompt;
310 kprompt.reply = &response_data;
311 prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
313 /* PROMPTER_INVOCATION */
314 krb5int_set_prompt_types(context, &prompt_type);
315 if ((ret = ((*prompter)(context, prompter_data, name,
316 banner, 1, &kprompt)))) {
317 krb5_xfree(sam_challenge);
318 krb5int_set_prompt_types(context, 0);
321 krb5int_set_prompt_types(context, 0);
323 enc_sam_response_enc.sam_nonce = sam_challenge->sam_nonce;
324 if (sam_challenge->sam_nonce == 0) {
325 if ((ret = krb5_us_timeofday(context,
326 &enc_sam_response_enc.sam_timestamp,
327 &enc_sam_response_enc.sam_usec))) {
328 krb5_xfree(sam_challenge);
332 sam_response.sam_patimestamp = enc_sam_response_enc.sam_timestamp;
335 /* XXX What if more than one flag is set? */
336 if (sam_challenge->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
338 /* Most of this should be taken care of before we get here. We */
339 /* will need the user's password and as_key to encrypt the SAD */
340 /* and we want to preserve ordering of user prompts (first */
341 /* password, then SAM data) so that user's won't be confused. */
343 if (as_key->length) {
344 krb5_free_keyblock_contents(context, as_key);
348 /* generate a salt using the requested principal */
350 if ((salt->length == -1 || salt->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) {
351 if ((ret = krb5_principal2salt(context, request->client,
353 krb5_xfree(sam_challenge);
362 /* generate a key using the supplied password */
364 ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
365 (krb5_data *)gak_data, salt, as_key);
368 krb5_xfree(defsalt.data);
371 krb5_xfree(sam_challenge);
375 /* encrypt the passcode with the key from above */
377 enc_sam_response_enc.sam_sad = response_data;
378 } else if (sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
380 /* process the key as password */
382 if (as_key->length) {
383 krb5_free_keyblock_contents(context, as_key);
388 if ((salt->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) {
389 if (ret = krb5_principal2salt(context, request->client,
391 krb5_xfree(sam_challenge);
404 /* XXX As of the passwords-04 draft, no enctype is specified,
405 the server uses ENCTYPE_DES_CBC_MD5. In the future the
406 server should send a PA-SAM-ETYPE-INFO containing the enctype. */
408 ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
409 &response_data, salt, as_key);
412 krb5_xfree(defsalt.data);
415 krb5_xfree(sam_challenge);
419 enc_sam_response_enc.sam_sad.length = 0;
421 /* Eventually, combine SAD with long-term key to get
423 return KRB5_PREAUTH_BAD_TYPE;
426 /* copy things from the challenge */
427 sam_response.sam_nonce = sam_challenge->sam_nonce;
428 sam_response.sam_flags = sam_challenge->sam_flags;
429 sam_response.sam_track_id = sam_challenge->sam_track_id;
430 sam_response.sam_type = sam_challenge->sam_type;
431 sam_response.magic = KV5M_SAM_RESPONSE;
433 krb5_xfree(sam_challenge);
435 /* encode the encoded part of the response */
436 if ((ret = encode_krb5_enc_sam_response_enc(&enc_sam_response_enc,
440 ret = krb5_encrypt_data(context, as_key, 0, scratch,
441 &sam_response.sam_enc_nonce_or_ts);
443 krb5_free_data(context, scratch);
448 /* sam_enc_key is reserved for future use */
449 sam_response.sam_enc_key.ciphertext.length = 0;
451 if ((pa = malloc(sizeof(krb5_pa_data))) == NULL)
454 if ((ret = encode_krb5_sam_response(&sam_response, &scratch))) {
459 pa->magic = KV5M_PA_DATA;
460 pa->pa_type = KRB5_PADATA_SAM_RESPONSE;
461 pa->length = scratch->length;
462 pa->contents = (krb5_octet *) scratch->data;
470 krb5_error_code pa_sam_2(krb5_context context,
471 krb5_kdc_req *request,
472 krb5_pa_data *in_padata,
473 krb5_pa_data **out_padata,
476 krb5_keyblock *as_key,
477 krb5_prompter_fct prompter,
479 krb5_gic_get_as_key_fct gak_fct,
482 krb5_error_code retval;
483 krb5_sam_challenge_2 *sc2 = NULL;
484 krb5_sam_challenge_2_body *sc2b = NULL;
486 krb5_data response_data;
487 char name[100], banner[100], prompt[100], response[100];
489 krb5_prompt_type prompt_type;
491 krb5_checksum **cksum;
492 krb5_data *scratch = NULL;
493 krb5_boolean valid_cksum = 0;
494 krb5_enc_sam_response_enc_2 enc_sam_response_enc_2;
495 krb5_sam_response_2 sr2;
496 krb5_pa_data *sam_padata;
498 if (prompter == NULL)
499 return KRB5_LIBOS_CANTREADPWD;
501 tmp_data.length = in_padata->length;
502 tmp_data.data = (char *)in_padata->contents;
504 if (retval = decode_krb5_sam_challenge_2(&tmp_data, &sc2))
507 retval = decode_krb5_sam_challenge_2_body(&sc2->sam_challenge_2_body, &sc2b);
512 if (!sc2->sam_cksum || ! *sc2->sam_cksum) {
513 krb5_free_sam_challenge_2(context, sc2);
514 krb5_free_sam_challenge_2_body(context, sc2b);
515 return(KRB5_SAM_NO_CHECKSUM);
518 if (sc2b->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
519 krb5_free_sam_challenge_2(context, sc2);
520 krb5_free_sam_challenge_2_body(context, sc2b);
521 return(KRB5_SAM_UNSUPPORTED);
524 if (!valid_enctype(sc2b->sam_etype)) {
525 krb5_free_sam_challenge_2(context, sc2);
526 krb5_free_sam_challenge_2_body(context, sc2b);
527 return(KRB5_SAM_INVALID_ETYPE);
530 /* All of the above error checks are KDC-specific, that is, they */
531 /* assume a failure in the KDC reply. By returning anything other */
532 /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED, */
533 /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will */
534 /* most likely go on to try the AS_REQ against master KDC */
536 if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
537 /* We will need the password to obtain the key used for */
538 /* the checksum, and encryption of the sam_response. */
539 /* Go ahead and get it now, preserving the ordering of */
540 /* prompts for the user. */
542 retval = (gak_fct)(context, request->client,
543 sc2b->sam_etype, prompter,
544 prompter_data, salt, as_key, gak_data);
546 krb5_free_sam_challenge_2(context, sc2);
547 krb5_free_sam_challenge_2_body(context, sc2b);
552 sprintf(name, "%.*s",
553 SAMDATA(sc2b->sam_type_name, "SAM Authentication",
556 sprintf(banner, "%.*s",
557 SAMDATA(sc2b->sam_challenge_label,
558 sam_challenge_banner(sc2b->sam_type),
561 sprintf(prompt, "%s%.*s%s%.*s",
562 sc2b->sam_challenge.length?"Challenge is [":"",
563 SAMDATA(sc2b->sam_challenge, "", 20),
564 sc2b->sam_challenge.length?"], ":"",
565 SAMDATA(sc2b->sam_response_prompt, "passcode", 55));
567 response_data.data = response;
568 response_data.length = sizeof(response);
569 kprompt.prompt = prompt;
571 kprompt.reply = &response_data;
573 prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
574 krb5int_set_prompt_types(context, &prompt_type);
576 if (retval = ((*prompter)(context, prompter_data, name,
577 banner, 1, &kprompt))) {
578 krb5_free_sam_challenge_2(context, sc2);
579 krb5_free_sam_challenge_2_body(context, sc2b);
580 krb5int_set_prompt_types(context, 0);
584 krb5int_set_prompt_types(context, (krb5_prompt_type *)NULL);
586 /* Generate salt used by string_to_key() */
587 if ((salt->length == -1) && (salt->data == NULL)) {
588 if (retval = krb5_principal2salt(context, request->client, &defsalt)) {
589 krb5_free_sam_challenge_2(context, sc2);
590 krb5_free_sam_challenge_2_body(context, sc2b);
598 /* Get encryption key to be used for checksum and sam_response */
599 if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
600 /* as_key = string_to_key(password) */
603 if (as_key->length) {
604 krb5_free_keyblock_contents(context, as_key);
608 /* generate a key using the supplied password */
609 retval = krb5_c_string_to_key(context, sc2b->sam_etype,
610 (krb5_data *)gak_data, salt, as_key);
613 krb5_free_sam_challenge_2(context, sc2);
614 krb5_free_sam_challenge_2_body(context, sc2b);
615 if (defsalt.length) krb5_xfree(defsalt.data);
619 if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD)) {
620 /* as_key = combine_key (as_key, string_to_key(SAD)) */
621 krb5_keyblock tmp_kb;
623 retval = krb5_c_string_to_key(context, sc2b->sam_etype,
624 &response_data, salt, &tmp_kb);
627 krb5_free_sam_challenge_2(context, sc2);
628 krb5_free_sam_challenge_2_body(context, sc2b);
629 if (defsalt.length) krb5_xfree(defsalt.data);
633 /* This should be a call to the crypto library some day */
634 /* key types should already match the sam_etype */
635 retval = krb5int_c_combine_keys(context, as_key, &tmp_kb, as_key);
638 krb5_free_sam_challenge_2(context, sc2);
639 krb5_free_sam_challenge_2_body(context, sc2b);
640 if (defsalt.length) krb5_xfree(defsalt.data);
643 krb5_free_keyblock_contents(context, &tmp_kb);
647 krb5_xfree(defsalt.data);
650 /* as_key = string_to_key(SAD) */
652 if (as_key->length) {
653 krb5_free_keyblock_contents(context, as_key);
657 /* generate a key using the supplied password */
658 retval = krb5_c_string_to_key(context, sc2b->sam_etype,
659 &response_data, salt, as_key);
662 krb5_xfree(defsalt.data);
665 krb5_free_sam_challenge_2(context, sc2);
666 krb5_free_sam_challenge_2_body(context, sc2b);
671 /* Now we have a key, verify the checksum on the sam_challenge */
673 cksum = sc2->sam_cksum;
676 /* Check this cksum */
677 retval = krb5_c_verify_checksum(context, as_key,
678 KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
679 &sc2->sam_challenge_2_body,
680 *cksum, &valid_cksum);
682 krb5_free_data(context, scratch);
683 krb5_free_sam_challenge_2(context, sc2);
684 krb5_free_sam_challenge_2_body(context, sc2b);
694 /* If KRB5_SAM_SEND_ENCRYPTED_SAD is set, then password is only */
695 /* source for checksum key. Therefore, a bad checksum means a */
696 /* bad password. Don't give that direct feedback to someone */
697 /* trying to brute-force passwords. */
699 if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD))
700 krb5_free_sam_challenge_2(context, sc2);
701 krb5_free_sam_challenge_2_body(context, sc2b);
703 * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications
704 * can interpret that as "password incorrect", which is probably
705 * the best error we can return in this situation.
707 return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
710 /* fill in enc_sam_response_enc_2 */
711 enc_sam_response_enc_2.magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
712 enc_sam_response_enc_2.sam_nonce = sc2b->sam_nonce;
713 if (sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
714 enc_sam_response_enc_2.sam_sad = response_data;
716 enc_sam_response_enc_2.sam_sad.data = NULL;
717 enc_sam_response_enc_2.sam_sad.length = 0;
720 /* encode and encrypt enc_sam_response_enc_2 with as_key */
721 retval = encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2,
724 krb5_free_sam_challenge_2(context, sc2);
725 krb5_free_sam_challenge_2_body(context, sc2b);
729 /* Fill in sam_response_2 */
730 memset(&sr2, 0, sizeof(sr2));
731 sr2.sam_type = sc2b->sam_type;
732 sr2.sam_flags = sc2b->sam_flags;
733 sr2.sam_track_id = sc2b->sam_track_id;
734 sr2.sam_nonce = sc2b->sam_nonce;
736 /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded */
737 /* enc_sam_response_enc_2 from above */
739 retval = krb5_c_encrypt_length(context, as_key->enctype, scratch->length,
740 (unsigned int *) &sr2.sam_enc_nonce_or_sad.ciphertext.length);
742 krb5_free_sam_challenge_2(context, sc2);
743 krb5_free_sam_challenge_2_body(context, sc2b);
747 sr2.sam_enc_nonce_or_sad.ciphertext.data =
748 (char *)malloc(sr2.sam_enc_nonce_or_sad.ciphertext.length);
750 if (!sr2.sam_enc_nonce_or_sad.ciphertext.data) {
751 krb5_free_sam_challenge_2(context, sc2);
752 krb5_free_sam_challenge_2_body(context, sc2b);
756 retval = krb5_c_encrypt(context, as_key, KRB5_KEYUSAGE_PA_SAM_RESPONSE,
757 NULL, scratch, &sr2.sam_enc_nonce_or_sad);
759 krb5_free_sam_challenge_2(context, sc2);
760 krb5_free_sam_challenge_2_body(context, sc2b);
761 krb5_free_data(context, scratch);
762 krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
765 krb5_free_data(context, scratch);
768 /* Encode the sam_response_2 */
769 retval = encode_krb5_sam_response_2(&sr2, &scratch);
770 krb5_free_sam_challenge_2(context, sc2);
771 krb5_free_sam_challenge_2_body(context, sc2b);
772 krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
778 /* Almost there, just need to make padata ! */
779 sam_padata = malloc(sizeof(krb5_pa_data));
780 if (sam_padata == NULL) {
781 krb5_free_data(context, scratch);
785 sam_padata->magic = KV5M_PA_DATA;
786 sam_padata->pa_type = KRB5_PADATA_SAM_RESPONSE_2;
787 sam_padata->length = scratch->length;
788 sam_padata->contents = (krb5_octet *) scratch->data;
790 *out_padata = sam_padata;
795 static const pa_types_t pa_types[] = {
802 KRB5_PADATA_AFS3_SALT,
807 KRB5_PADATA_ENC_TIMESTAMP,
812 KRB5_PADATA_SAM_CHALLENGE_2,
817 KRB5_PADATA_SAM_CHALLENGE,
829 krb5_do_preauth(krb5_context context,
830 krb5_kdc_req *request,
831 krb5_pa_data **in_padata, krb5_pa_data ***out_padata,
832 krb5_data *salt, krb5_enctype *etype,
833 krb5_keyblock *as_key,
834 krb5_prompter_fct prompter, void *prompter_data,
835 krb5_gic_get_as_key_fct gak_fct, void *gak_data)
837 int h, i, j, out_pa_list_size;
838 krb5_pa_data *out_pa, **out_pa_list;
840 krb5_etype_info etype_info = NULL;
842 static const int paorder[] = { PA_INFO, PA_REAL };
845 if (in_padata == NULL) {
851 fprintf (stderr, "salt len=%d", salt->length);
852 if (salt->length > 0)
853 fprintf (stderr, " '%*s'", salt->length, salt->data);
854 fprintf (stderr, "; preauth data types:");
855 for (i = 0; in_padata[i]; i++) {
856 fprintf (stderr, " %d", in_padata[i]->pa_type);
858 fprintf (stderr, "\n");
862 out_pa_list_size = 0;
864 /* first do all the informational preauths, then the first real one */
866 for (h=0; h<(sizeof(paorder)/sizeof(paorder[0])); h++) {
868 for (i=0; in_padata[i] && !realdone; i++) {
870 * This is really gross, but is necessary to prevent
871 * lossge when talking to a 1.0.x KDC, which returns an
872 * erroneous PA-PW-SALT when it returns a KRB-ERROR
873 * requiring additional preauth.
875 switch (in_padata[i]->pa_type) {
876 case KRB5_PADATA_ETYPE_INFO:
879 scratch.length = in_padata[i]->length;
880 scratch.data = (char *) in_padata[i]->contents;
881 ret = decode_krb5_etype_info(&scratch, &etype_info);
884 out_pa_list[out_pa_list_size++] = NULL;
885 krb5_free_pa_data(context, out_pa_list);
889 if (etype_info[0] == NULL) {
890 krb5_free_etype_info(context, etype_info);
894 salt->data = (char *) etype_info[0]->salt;
895 salt->length = etype_info[0]->length;
896 *etype = etype_info[0]->etype;
898 for (j = 0; etype_info[j]; j++) {
899 krb5_etype_info_entry *e = etype_info[j];
900 fprintf (stderr, "etype info %d: etype %d salt len=%d",
901 j, e->etype, e->length);
902 if (e->length > 0 && e->length != KRB5_ETYPE_NO_SALT)
903 fprintf (stderr, " '%*s'", e->length, e->salt);
904 fprintf (stderr, "\n");
908 case KRB5_PADATA_PW_SALT:
909 case KRB5_PADATA_AFS3_SALT:
916 for (j=0; pa_types[j].type >= 0; j++) {
917 if ((in_padata[i]->pa_type == pa_types[j].type) &&
918 (pa_types[j].flags & paorder[h])) {
921 if ((ret = ((*pa_types[j].fct)(context, request,
922 in_padata[i], &out_pa,
924 prompter, prompter_data,
925 gak_fct, gak_data)))) {
927 out_pa_list[out_pa_list_size++] = NULL;
928 krb5_free_pa_data(context, out_pa_list);
931 krb5_free_etype_info(context, etype_info);
936 if (out_pa_list == NULL) {
939 malloc(2*sizeof(krb5_pa_data *)))
946 (out_pa_list_size+2)*
947 sizeof(krb5_pa_data *)))
949 /* XXX this will leak the pointers which
950 have already been allocated. oh well. */
954 out_pa_list[out_pa_list_size++] = out_pa;
956 if (paorder[h] == PA_REAL)
964 out_pa_list[out_pa_list_size++] = NULL;
966 *out_padata = out_pa_list;