2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
8 * Copyright 1995, 2003 by the Massachusetts Institute of Technology. All
11 * Export of this software from the United States of America may
12 * require a specific license from the United States Government.
13 * It is the responsibility of any person or organization contemplating
14 * export to obtain such a license before exporting.
16 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
17 * distribute this software and its documentation for any purpose and
18 * without fee is hereby granted, provided that the above copyright
19 * notice appear in all copies and that both that copyright notice and
20 * this permission notice appear in supporting documentation, and that
21 * the name of M.I.T. not be used in advertising or publicity pertaining
22 * to distribution of the software without specific, written prior
23 * permission. Furthermore if you modify this software you must label
24 * your software as modified software and not distribute it in such a
25 * fashion that it might be confused with the original M.I.T. software.
26 * M.I.T. makes no representations about the suitability of
27 * this software for any purpose. It is provided "as is" without express
28 * or implied warranty.
33 * This file contains routines for establishing, verifying, and any other
34 * necessary functions, for utilizing the pre-authentication field of the
35 * kerberos kdc request, with various hardware/software verification devices.
40 #include <preauth_plugin.h>
41 #include "int-proto.h"
48 static const char *objdirs
[] = { KRB5_PLUGIN_BUNDLE_DIR
, LIBDIR
"/krb5/plugins/preauth", NULL
}; /* should be a list */
50 /* Solaris Kerberos */
51 static const char *objdirs
[] = { LIBDIR
"/krb5/plugins/preauth", NULL
};
54 typedef krb5_error_code (*pa_function
)(krb5_context
,
55 krb5_kdc_req
*request
,
56 krb5_pa_data
*in_padata
,
57 krb5_pa_data
**out_padata
,
58 krb5_data
*salt
, krb5_data
*s2kparams
,
60 krb5_keyblock
*as_key
,
61 krb5_prompter_fct prompter_fct
,
63 krb5_gic_get_as_key_fct gak_fct
,
66 typedef struct _pa_types_t
{
67 krb5_preauthtype type
;
72 /* Create the per-krb5_context context. This means loading the modules
73 * if we haven't done that yet (applications which never obtain initial
74 * credentials should never hit this routine), breaking up the module's
75 * list of support pa_types so that we can iterate over the modules more
76 * easily, and copying over the relevant parts of the module's table. */
78 krb5_init_preauth_context(krb5_context kcontext
)
80 int n_modules
, n_tables
, i
, j
, k
;
82 struct krb5plugin_preauth_client_ftable_v1
*table
;
83 krb5_preauth_context
*context
= NULL
;
85 krb5_preauthtype pa_type
;
88 /* Only do this once for each krb5_context */
89 if (kcontext
->preauth_context
!= NULL
)
92 /* load the plugins for the current context */
93 if (PLUGIN_DIR_OPEN(&kcontext
->preauth_plugins
) == 0) {
94 if (krb5int_open_plugin_dirs(objdirs
, NULL
,
95 &kcontext
->preauth_plugins
,
96 &kcontext
->err
) != 0) {
101 /* pull out the module function tables for all of the modules */
103 if (krb5int_get_plugin_dir_data(&kcontext
->preauth_plugins
,
104 "preauthentication_client_1",
106 &kcontext
->err
) != 0) {
109 if (tables
== NULL
) {
113 /* count how many modules we ended up loading, and how many preauth
114 * types we may claim to support as a result */
117 (tables
!= NULL
) && (tables
[n_tables
] != NULL
);
119 table
= tables
[n_tables
];
120 if ((table
->pa_type_list
!= NULL
) && (table
->process
!= NULL
)) {
121 for (j
= 0; table
->pa_type_list
[j
] > 0; j
++) {
127 /* allocate the space we need */
128 context
= malloc(sizeof(*context
));
129 if (context
== NULL
) {
130 krb5int_free_plugin_dir_data(tables
);
133 context
->modules
= malloc(sizeof(context
->modules
[0]) * n_modules
);
134 if (context
->modules
== NULL
) {
135 krb5int_free_plugin_dir_data(tables
);
139 memset(context
->modules
, 0, sizeof(context
->modules
[0]) * n_modules
);
140 context
->n_modules
= n_modules
;
142 /* fill in the structure */
144 for (i
= 0; i
< n_tables
; i
++) {
146 if ((table
->pa_type_list
!= NULL
) && (table
->process
!= NULL
)) {
147 plugin_context
= NULL
;
148 if ((table
->init
!= NULL
) &&
149 ((*table
->init
)(kcontext
, &plugin_context
) != 0)) {
151 fprintf (stderr
, "init err, skipping module \"%s\"\n",
158 for (j
= 0; table
->pa_type_list
[j
] > 0; j
++) {
159 pa_type
= table
->pa_type_list
[j
];
160 context
->modules
[k
].pa_type
= pa_type
;
161 context
->modules
[k
].enctypes
= table
->enctype_list
;
162 context
->modules
[k
].plugin_context
= plugin_context
;
163 /* Only call client_fini once per plugin */
165 context
->modules
[k
].client_fini
= table
->fini
;
167 context
->modules
[k
].client_fini
= NULL
;
168 context
->modules
[k
].ftable
= table
;
169 context
->modules
[k
].name
= table
->name
;
170 context
->modules
[k
].flags
= (*table
->flags
)(kcontext
, pa_type
);
171 context
->modules
[k
].use_count
= 0;
172 context
->modules
[k
].client_process
= table
->process
;
173 context
->modules
[k
].client_tryagain
= table
->tryagain
;
175 context
->modules
[k
].client_supply_gic_opts
= table
->gic_opts
;
177 context
->modules
[k
].client_supply_gic_opts
= NULL
;
178 context
->modules
[k
].request_context
= NULL
;
180 * Only call request_init and request_fini once per plugin.
181 * Only the first module within each plugin will ever
182 * have request_context filled in. Every module within
183 * the plugin will have its request_context_pp pointing
184 * to that entry's request_context. That way all the
185 * modules within the plugin share the same request_context
188 context
->modules
[k
].client_req_init
= table
->request_init
;
189 context
->modules
[k
].client_req_fini
= table
->request_fini
;
190 rcpp
= &context
->modules
[k
].request_context
;
192 context
->modules
[k
].client_req_init
= NULL
;
193 context
->modules
[k
].client_req_fini
= NULL
;
195 context
->modules
[k
].request_context_pp
= rcpp
;
197 fprintf (stderr
, "init module \"%s\", pa_type %d, flag %d\n",
198 context
->modules
[k
].name
,
199 context
->modules
[k
].pa_type
,
200 context
->modules
[k
].flags
);
206 krb5int_free_plugin_dir_data(tables
);
208 /* return the result */
209 kcontext
->preauth_context
= context
;
212 /* Zero the use counts for the modules herein. Usually used before we
213 * start processing any data from the server, at which point every module
214 * will again be able to take a crack at whatever the server sent. */
216 krb5_clear_preauth_context_use_counts(krb5_context context
)
219 if (context
->preauth_context
!= NULL
) {
220 for (i
= 0; i
< context
->preauth_context
->n_modules
; i
++) {
221 context
->preauth_context
->modules
[i
].use_count
= 0;
227 * Give all the preauth plugins a look at the preauth option which
231 krb5_preauth_supply_preauth_data(krb5_context context
,
232 krb5_gic_opt_ext
*opte
,
236 krb5_error_code retval
;
239 const char *emsg
= NULL
;
241 if (context
->preauth_context
== NULL
)
242 krb5_init_preauth_context(context
);
243 if (context
->preauth_context
== NULL
) {
245 krb5int_set_error(&context
->err
, retval
,
246 "krb5_preauth_supply_preauth_data: "
247 "Unable to initialize preauth context");
252 * Go down the list of preauth modules, and supply them with the
253 * attribute/value pair.
255 for (i
= 0; i
< context
->preauth_context
->n_modules
; i
++) {
256 if (context
->preauth_context
->modules
[i
].client_supply_gic_opts
== NULL
)
258 pctx
= context
->preauth_context
->modules
[i
].plugin_context
;
259 retval
= (*context
->preauth_context
->modules
[i
].client_supply_gic_opts
)
261 (krb5_get_init_creds_opt
*)opte
, attr
, value
);
263 emsg
= krb5_get_error_message(context
, retval
);
264 krb5int_set_error(&context
->err
, retval
, "Preauth plugin %s: %s",
265 context
->preauth_context
->modules
[i
].name
, emsg
);
272 /* Free the per-krb5_context preauth_context. This means clearing any
273 * plugin-specific context which may have been created, and then
274 * freeing the context itself. */
276 krb5_free_preauth_context(krb5_context context
)
280 if (context
->preauth_context
!= NULL
) {
281 for (i
= 0; i
< context
->preauth_context
->n_modules
; i
++) {
282 pctx
= context
->preauth_context
->modules
[i
].plugin_context
;
283 if (context
->preauth_context
->modules
[i
].client_fini
!= NULL
) {
284 (*context
->preauth_context
->modules
[i
].client_fini
)(context
, pctx
);
286 memset(&context
->preauth_context
->modules
[i
], 0,
287 sizeof(context
->preauth_context
->modules
[i
]));
289 if (context
->preauth_context
->modules
!= NULL
) {
290 free(context
->preauth_context
->modules
);
291 context
->preauth_context
->modules
= NULL
;
293 free(context
->preauth_context
);
294 context
->preauth_context
= NULL
;
298 /* Initialize the per-AS-REQ context. This means calling the client_req_init
299 * function to give the plugin a chance to allocate a per-request context. */
301 krb5_preauth_request_context_init(krb5_context context
)
306 /* Limit this to only one attempt per context? */
307 if (context
->preauth_context
== NULL
)
308 krb5_init_preauth_context(context
);
309 if (context
->preauth_context
!= NULL
) {
310 for (i
= 0; i
< context
->preauth_context
->n_modules
; i
++) {
311 pctx
= context
->preauth_context
->modules
[i
].plugin_context
;
312 if (context
->preauth_context
->modules
[i
].client_req_init
!= NULL
) {
313 rctx
= context
->preauth_context
->modules
[i
].request_context_pp
;
314 (*context
->preauth_context
->modules
[i
].client_req_init
) (context
, pctx
, rctx
);
320 /* Free the per-AS-REQ context. This means clearing any request-specific
321 * context which the plugin may have created. */
323 krb5_preauth_request_context_fini(krb5_context context
)
327 if (context
->preauth_context
!= NULL
) {
328 for (i
= 0; i
< context
->preauth_context
->n_modules
; i
++) {
329 pctx
= context
->preauth_context
->modules
[i
].plugin_context
;
330 rctx
= context
->preauth_context
->modules
[i
].request_context
;
332 if (context
->preauth_context
->modules
[i
].client_req_fini
!= NULL
) {
333 (*context
->preauth_context
->modules
[i
].client_req_fini
)(context
, pctx
, rctx
);
335 context
->preauth_context
->modules
[i
].request_context
= NULL
;
341 /* Add the named encryption type to the existing list of ktypes. */
343 grow_ktypes(krb5_enctype
**out_ktypes
, int *out_nktypes
, krb5_enctype ktype
)
346 krb5_enctype
*ktypes
;
347 for (i
= 0; i
< *out_nktypes
; i
++) {
348 if ((*out_ktypes
)[i
] == ktype
)
351 ktypes
= malloc((*out_nktypes
+ 2) * sizeof(ktype
));
353 for (i
= 0; i
< *out_nktypes
; i
++)
354 ktypes
[i
] = (*out_ktypes
)[i
];
358 *out_ktypes
= ktypes
;
364 * Add the given list of pa_data items to the existing list of items.
365 * Factored out here to make reading the do_preauth logic easier to read.
368 grow_pa_list(krb5_pa_data
***out_pa_list
, int *out_pa_list_size
,
369 krb5_pa_data
**addition
, int num_addition
)
371 krb5_pa_data
**pa_list
;
374 if (out_pa_list
== NULL
|| addition
== NULL
) {
378 if (*out_pa_list
== NULL
) {
379 /* Allocate room for the new additions and a NULL terminator. */
380 pa_list
= malloc((num_addition
+ 1) * sizeof(krb5_pa_data
*));
383 for (i
= 0; i
< num_addition
; i
++)
384 pa_list
[i
] = addition
[i
];
386 *out_pa_list
= pa_list
;
387 *out_pa_list_size
= num_addition
;
390 * Allocate room for the existing entries plus
391 * the new additions and a NULL terminator.
393 pa_list
= malloc((*out_pa_list_size
+ num_addition
+ 1)
394 * sizeof(krb5_pa_data
*));
397 for (i
= 0; i
< *out_pa_list_size
; i
++)
398 pa_list
[i
] = (*out_pa_list
)[i
];
399 for (j
= 0; j
< num_addition
;)
400 pa_list
[i
++] = addition
[j
++];
403 *out_pa_list
= pa_list
;
404 *out_pa_list_size
= i
;
410 * Retrieve a specific piece of information required by the plugin and
411 * return it in a new krb5_data item. There are separate request_types
412 * to obtain the data and free it.
414 * This may require massaging data into a contrived format, but it will
415 * hopefully keep us from having to reveal library-internal functions
416 * or data to the plugin modules.
419 static krb5_error_code
420 client_data_proc(krb5_context kcontext
,
421 krb5_preauth_client_rock
*rock
,
422 krb5_int32 request_type
,
428 if (rock
->magic
!= CLIENT_ROCK_MAGIC
)
433 switch (request_type
) {
434 case krb5plugin_preauth_client_get_etype
:
437 if (rock
->as_reply
== NULL
)
439 ret
= malloc(sizeof(krb5_data
));
442 data
= malloc(sizeof(krb5_enctype
));
448 ret
->length
= sizeof(krb5_enctype
);
449 eptr
= (krb5_enctype
*)data
;
450 *eptr
= rock
->as_reply
->enc_part
.enctype
;
455 case krb5plugin_preauth_client_free_etype
:
468 /* Tweak the request body, for now adding any enctypes which the module claims
469 * to add support for to the list, but in the future perhaps doing more
470 * involved things. */
472 krb5_preauth_prepare_request(krb5_context kcontext
,
473 krb5_gic_opt_ext
*opte
,
474 krb5_kdc_req
*request
)
478 if (kcontext
->preauth_context
== NULL
) {
481 /* Add the module-specific enctype list to the request, but only if
482 * it's something we can safely modify. */
483 if (!(opte
&& (opte
->flags
& KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST
))) {
484 for (i
= 0; i
< kcontext
->preauth_context
->n_modules
; i
++) {
485 if (kcontext
->preauth_context
->modules
[i
].enctypes
== NULL
)
487 for (j
= 0; kcontext
->preauth_context
->modules
[i
].enctypes
[j
] != 0; j
++) {
488 grow_ktypes(&request
->ktype
, &request
->nktypes
,
489 kcontext
->preauth_context
->modules
[i
].enctypes
[j
]);
495 /* Find the first module which provides for the named preauth type which also
496 * hasn't had a chance to run yet (INFO modules don't count, because as a rule
497 * they don't generate preauth data), and run it. */
498 static krb5_error_code
499 krb5_run_preauth_plugins(krb5_context kcontext
,
500 int module_required_flags
,
501 krb5_kdc_req
*request
,
502 krb5_data
*encoded_request_body
,
503 krb5_data
*encoded_previous_request
,
504 krb5_pa_data
*in_padata
,
505 krb5_prompter_fct prompter
,
507 preauth_get_as_key_proc gak_fct
,
509 krb5_data
*s2kparams
,
511 krb5_preauth_client_rock
*get_data_rock
,
512 krb5_keyblock
*as_key
,
513 krb5_pa_data
***out_pa_list
,
514 int *out_pa_list_size
,
517 krb5_gic_opt_ext
*opte
)
520 krb5_pa_data
**out_pa_data
;
522 struct _krb5_preauth_context_module
*module
;
524 if (kcontext
->preauth_context
== NULL
) {
527 /* iterate over all loaded modules */
528 for (i
= 0; i
< kcontext
->preauth_context
->n_modules
; i
++) {
529 module
= &kcontext
->preauth_context
->modules
[i
];
530 /* skip over those which don't match the preauth type */
531 if (module
->pa_type
!= in_padata
->pa_type
)
533 /* skip over those which don't match the flags (INFO vs REAL, mainly) */
534 if ((module
->flags
& module_required_flags
) == 0)
536 /* if it's a REAL module, try to call it only once per library call */
537 if (module_required_flags
& PA_REAL
) {
538 if (module
->use_count
> 0) {
540 fprintf(stderr
, "skipping already-used module \"%s\"(%d)\n",
541 module
->name
, module
->pa_type
);
547 /* run the module's callback function */
550 fprintf(stderr
, "using module \"%s\" (%d), flags = %d\n",
551 module
->name
, module
->pa_type
, module
->flags
);
553 ret
= module
->client_process(kcontext
,
554 module
->plugin_context
,
555 *module
->request_context_pp
,
556 (krb5_get_init_creds_opt
*)opte
,
560 encoded_request_body
,
561 encoded_previous_request
,
563 prompter
, prompter_data
,
564 gak_fct
, gak_data
, salt
, s2kparams
,
567 /* Make note of the module's flags and status. */
568 *module_flags
= module
->flags
;
570 /* Save the new preauth data item. */
571 if (out_pa_data
!= NULL
) {
573 for (j
= 0; out_pa_data
[j
] != NULL
; j
++);
574 ret
= grow_pa_list(out_pa_list
, out_pa_list_size
, out_pa_data
, j
);
581 if (i
>= kcontext
->preauth_context
->n_modules
) {
588 krb5_error_code
pa_salt(krb5_context context
,
589 krb5_kdc_req
*request
,
590 krb5_pa_data
*in_padata
,
591 krb5_pa_data
**out_padata
,
592 krb5_data
*salt
, krb5_data
*s2kparams
,
594 krb5_keyblock
*as_key
,
595 krb5_prompter_fct prompter
, void *prompter_data
,
596 krb5_gic_get_as_key_fct gak_fct
, void *gak_data
)
600 /* Solaris Kerberos - resync */
601 tmp
.data
= (char *)in_padata
->contents
;
602 tmp
.length
= in_padata
->length
;
603 krb5_free_data_contents(context
, salt
);
604 krb5int_copy_data_contents(context
, &tmp
, salt
);
607 if (in_padata
->pa_type
== KRB5_PADATA_AFS3_SALT
)
608 salt
->length
= SALT_TYPE_AFS_LENGTH
;
615 krb5_error_code
pa_enc_timestamp(krb5_context context
,
616 krb5_kdc_req
*request
,
617 krb5_pa_data
*in_padata
,
618 krb5_pa_data
**out_padata
,
620 krb5_data
*s2kparams
,
622 krb5_keyblock
*as_key
,
623 krb5_prompter_fct prompter
,
625 krb5_gic_get_as_key_fct gak_fct
,
629 krb5_pa_enc_ts pa_enc
;
631 krb5_enc_data enc_data
;
634 if (as_key
->length
== 0) {
636 /* Solaris Kerberos */
637 if (salt
!= NULL
&& salt
->data
!= NULL
) {
638 fprintf (stderr
, "%s:%d: salt len=%d", __FILE__
, __LINE__
,
640 if ((int) salt
->length
> 0)
641 fprintf (stderr
, " '%.*s'", salt
->length
, salt
->data
);
642 fprintf (stderr
, "; *etype=%d request->ktype[0]=%d\n",
643 *etype
, request
->ktype
[0]);
646 if ((ret
= ((*gak_fct
)(context
, request
->client
,
647 *etype
? *etype
: request
->ktype
[0],
648 prompter
, prompter_data
,
649 salt
, s2kparams
, as_key
, gak_data
))))
653 /* now get the time of day, and encrypt it accordingly */
655 if ((ret
= krb5_us_timeofday(context
, &pa_enc
.patimestamp
, &pa_enc
.pausec
)))
658 if ((ret
= encode_krb5_pa_enc_ts(&pa_enc
, &tmp
)))
662 fprintf (stderr
, "key type %d bytes %02x %02x ...\n",
664 as_key
->contents
[0], as_key
->contents
[1]);
666 ret
= krb5_encrypt_helper(context
, as_key
,
667 KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS
,
670 fprintf (stderr
, "enc data { type=%d kvno=%d data=%02x %02x ... }\n",
671 enc_data
.enctype
, enc_data
.kvno
,
672 0xff & enc_data
.ciphertext
.data
[0],
673 0xff & enc_data
.ciphertext
.data
[1]);
676 krb5_free_data(context
, tmp
);
679 krb5_xfree(enc_data
.ciphertext
.data
);
683 ret
= encode_krb5_enc_data(&enc_data
, &tmp
);
685 krb5_xfree(enc_data
.ciphertext
.data
);
690 if ((pa
= (krb5_pa_data
*) malloc(sizeof(krb5_pa_data
))) == NULL
) {
691 krb5_free_data(context
, tmp
);
695 pa
->magic
= KV5M_PA_DATA
;
696 pa
->pa_type
= KRB5_PADATA_ENC_TIMESTAMP
;
697 pa
->length
= tmp
->length
;
698 pa
->contents
= (krb5_octet
*) tmp
->data
;
708 char *sam_challenge_banner(krb5_int32 sam_type
)
713 case PA_SAM_TYPE_ENIGMA
: /* Enigma Logic */
714 label
= "Challenge for Enigma Logic mechanism";
716 case PA_SAM_TYPE_DIGI_PATH
: /* Digital Pathways */
717 case PA_SAM_TYPE_DIGI_PATH_HEX
: /* Digital Pathways */
718 label
= "Challenge for Digital Pathways mechanism";
720 case PA_SAM_TYPE_ACTIVCARD_DEC
: /* Digital Pathways */
721 case PA_SAM_TYPE_ACTIVCARD_HEX
: /* Digital Pathways */
722 label
= "Challenge for Activcard mechanism";
724 case PA_SAM_TYPE_SKEY_K0
: /* S/key where KDC has key 0 */
725 label
= "Challenge for Enhanced S/Key mechanism";
727 case PA_SAM_TYPE_SKEY
: /* Traditional S/Key */
728 label
= "Challenge for Traditional S/Key mechanism";
730 case PA_SAM_TYPE_SECURID
: /* Security Dynamics */
731 label
= "Challenge for Security Dynamics mechanism";
733 case PA_SAM_TYPE_SECURID_PREDICT
: /* predictive Security Dynamics */
734 label
= "Challenge for Security Dynamics mechanism";
737 label
= "Challenge from authentication server";
744 /* this macro expands to the int,ptr necessary for "%.*s" in an sprintf */
746 #define SAMDATA(kdata, str, maxsize) \
747 (int)((kdata.length)? \
748 ((((kdata.length)<=(maxsize))?(kdata.length):strlen(str))): \
751 ((((kdata.length)<=(maxsize))?(kdata.data):(str))):(str)
753 /* XXX Danger! This code is not in sync with the kerberos-password-02
754 draft. This draft cannot be implemented as written. This code is
755 compatible with earlier versions of mit krb5 and cygnus kerbnet. */
759 krb5_error_code
pa_sam(krb5_context context
,
760 krb5_kdc_req
*request
,
761 krb5_pa_data
*in_padata
,
762 krb5_pa_data
**out_padata
,
764 krb5_data
*s2kparams
,
766 krb5_keyblock
*as_key
,
767 krb5_prompter_fct prompter
,
769 krb5_gic_get_as_key_fct gak_fct
,
774 char name
[100], banner
[100];
775 char prompt
[100], response
[100];
776 krb5_data response_data
;
778 krb5_prompt_type prompt_type
;
780 krb5_sam_challenge
*sam_challenge
= 0;
781 krb5_sam_response sam_response
;
782 /* these two get encrypted and stuffed in to sam_response */
783 krb5_enc_sam_response_enc enc_sam_response_enc
;
787 /* Solaris Kerberos */
788 krb5_enc_data
* enc_data
;
791 if (prompter
== NULL
)
794 tmpsam
.length
= in_padata
->length
;
795 tmpsam
.data
= (char *) in_padata
->contents
;
796 if ((ret
= decode_krb5_sam_challenge(&tmpsam
, &sam_challenge
)))
799 if (sam_challenge
->sam_flags
& KRB5_SAM_MUST_PK_ENCRYPT_SAD
) {
800 krb5_xfree(sam_challenge
);
801 return(KRB5_SAM_UNSUPPORTED
);
804 /* If we need the password from the user (USE_SAD_AS_KEY not set), */
805 /* then get it here. Exception for "old" KDCs with CryptoCard */
806 /* support which uses the USE_SAD_AS_KEY flag, but still needs pwd */
808 if (!(sam_challenge
->sam_flags
& KRB5_SAM_USE_SAD_AS_KEY
) ||
809 (sam_challenge
->sam_type
== PA_SAM_TYPE_CRYPTOCARD
)) {
811 /* etype has either been set by caller or by KRB5_PADATA_ETYPE_INFO */
812 /* message from the KDC. If it is not set, pick an enctype that we */
813 /* think the KDC will have for us. */
815 if (etype
&& *etype
== 0)
816 *etype
= ENCTYPE_DES_CBC_CRC
;
818 if ((ret
= (gak_fct
)(context
, request
->client
, *etype
, prompter
,
819 prompter_data
, salt
, s2kparams
, as_key
, gak_data
)))
822 sprintf(name
, "%.*s",
823 SAMDATA(sam_challenge
->sam_type_name
, "SAM Authentication",
826 sprintf(banner
, "%.*s",
827 SAMDATA(sam_challenge
->sam_challenge_label
,
828 sam_challenge_banner(sam_challenge
->sam_type
),
831 /* sprintf(prompt, "Challenge is [%s], %s: ", challenge, prompt); */
832 sprintf(prompt
, "%s%.*s%s%.*s",
833 sam_challenge
->sam_challenge
.length
?"Challenge is [":"",
834 SAMDATA(sam_challenge
->sam_challenge
, "", 20),
835 sam_challenge
->sam_challenge
.length
?"], ":"",
836 SAMDATA(sam_challenge
->sam_response_prompt
, "passcode", 55));
838 response_data
.data
= response
;
839 response_data
.length
= sizeof(response
);
841 kprompt
.prompt
= prompt
;
843 kprompt
.reply
= &response_data
;
844 prompt_type
= KRB5_PROMPT_TYPE_PREAUTH
;
846 /* PROMPTER_INVOCATION */
847 krb5int_set_prompt_types(context
, &prompt_type
);
848 if ((ret
= ((*prompter
)(context
, prompter_data
, name
,
849 banner
, 1, &kprompt
)))) {
850 krb5_xfree(sam_challenge
);
851 krb5int_set_prompt_types(context
, 0);
854 krb5int_set_prompt_types(context
, 0);
856 enc_sam_response_enc
.sam_nonce
= sam_challenge
->sam_nonce
;
857 if (sam_challenge
->sam_nonce
== 0) {
858 if ((ret
= krb5_us_timeofday(context
,
859 &enc_sam_response_enc
.sam_timestamp
,
860 &enc_sam_response_enc
.sam_usec
))) {
861 krb5_xfree(sam_challenge
);
865 sam_response
.sam_patimestamp
= enc_sam_response_enc
.sam_timestamp
;
868 /* XXX What if more than one flag is set? */
869 if (sam_challenge
->sam_flags
& KRB5_SAM_SEND_ENCRYPTED_SAD
) {
871 /* Most of this should be taken care of before we get here. We */
872 /* will need the user's password and as_key to encrypt the SAD */
873 /* and we want to preserve ordering of user prompts (first */
874 /* password, then SAM data) so that user's won't be confused. */
876 if (as_key
->length
) {
877 krb5_free_keyblock_contents(context
, as_key
);
881 /* generate a salt using the requested principal */
883 if ((salt
->length
== -1 || salt
->length
== SALT_TYPE_AFS_LENGTH
) && (salt
->data
== NULL
)) {
884 if ((ret
= krb5_principal2salt(context
, request
->client
,
886 krb5_xfree(sam_challenge
);
895 /* generate a key using the supplied password */
897 ret
= krb5_c_string_to_key(context
, ENCTYPE_DES_CBC_MD5
,
898 (krb5_data
*)gak_data
, salt
, as_key
);
901 krb5_xfree(defsalt
.data
);
904 krb5_xfree(sam_challenge
);
908 /* encrypt the passcode with the key from above */
910 enc_sam_response_enc
.sam_sad
= response_data
;
911 } else if (sam_challenge
->sam_flags
& KRB5_SAM_USE_SAD_AS_KEY
) {
913 /* process the key as password */
915 if (as_key
->length
) {
916 krb5_free_keyblock_contents(context
, as_key
);
921 if ((salt
->length
== SALT_TYPE_AFS_LENGTH
) && (salt
->data
== NULL
)) {
922 if (ret
= krb5_principal2salt(context
, request
->client
,
924 krb5_xfree(sam_challenge
);
937 /* XXX As of the passwords-04 draft, no enctype is specified,
938 the server uses ENCTYPE_DES_CBC_MD5. In the future the
939 server should send a PA-SAM-ETYPE-INFO containing the enctype. */
941 ret
= krb5_c_string_to_key(context
, ENCTYPE_DES_CBC_MD5
,
942 &response_data
, salt
, as_key
);
945 krb5_xfree(defsalt
.data
);
948 krb5_xfree(sam_challenge
);
952 enc_sam_response_enc
.sam_sad
.length
= 0;
954 /* Eventually, combine SAD with long-term key to get
956 return KRB5_PREAUTH_BAD_TYPE
;
959 /* copy things from the challenge */
960 sam_response
.sam_nonce
= sam_challenge
->sam_nonce
;
961 sam_response
.sam_flags
= sam_challenge
->sam_flags
;
962 sam_response
.sam_track_id
= sam_challenge
->sam_track_id
;
963 sam_response
.sam_type
= sam_challenge
->sam_type
;
964 sam_response
.magic
= KV5M_SAM_RESPONSE
;
966 krb5_xfree(sam_challenge
);
968 /* encode the encoded part of the response */
969 if ((ret
= encode_krb5_enc_sam_response_enc(&enc_sam_response_enc
,
975 * Using new crypto interface now so we can get rid of the
978 if ((ret
= krb5_c_encrypt_length(context
, as_key
->enctype
,
979 scratch
->length
, &enclen
))) {
980 krb5_free_data(context
, scratch
);
984 enc_data
= &sam_response
.sam_enc_nonce_or_ts
;
985 enc_data
->magic
= KV5M_ENC_DATA
;
987 enc_data
->enctype
= as_key
->enctype
;
988 enc_data
->ciphertext
.length
= enclen
;
990 if ((enc_data
->ciphertext
.data
= MALLOC(enclen
)) == NULL
) {
991 enc_data
->ciphertext
.length
= 0;
992 krb5_free_data(context
, scratch
);
996 if ((ret
= krb5_c_encrypt(context
, as_key
, 0, 0,
997 scratch
, enc_data
))) {
998 FREE(enc_data
->ciphertext
.data
, enclen
);
999 enc_data
->ciphertext
.data
= NULL
;
1000 enc_data
->ciphertext
.length
= 0;
1003 krb5_free_data(context
, scratch
);
1008 /* sam_enc_key is reserved for future use */
1009 sam_response
.sam_enc_key
.ciphertext
.length
= 0;
1011 if ((pa
= malloc(sizeof(krb5_pa_data
))) == NULL
)
1014 if ((ret
= encode_krb5_sam_response(&sam_response
, &scratch
))) {
1019 pa
->magic
= KV5M_PA_DATA
;
1020 pa
->pa_type
= KRB5_PADATA_SAM_RESPONSE
;
1021 pa
->length
= scratch
->length
;
1022 pa
->contents
= (krb5_octet
*) scratch
->data
;
1030 krb5_error_code
pa_sam_2(krb5_context context
,
1031 krb5_kdc_req
*request
,
1032 krb5_pa_data
*in_padata
,
1033 krb5_pa_data
**out_padata
,
1035 krb5_data
*s2kparams
,
1036 krb5_enctype
*etype
,
1037 krb5_keyblock
*as_key
,
1038 krb5_prompter_fct prompter
,
1039 void *prompter_data
,
1040 krb5_gic_get_as_key_fct gak_fct
,
1043 krb5_error_code retval
;
1044 krb5_sam_challenge_2
*sc2
= NULL
;
1045 krb5_sam_challenge_2_body
*sc2b
= NULL
;
1047 krb5_data response_data
;
1048 char name
[100], banner
[100], prompt
[100], response
[100];
1049 krb5_prompt kprompt
;
1050 krb5_prompt_type prompt_type
;
1052 krb5_checksum
**cksum
;
1053 krb5_data
*scratch
= NULL
;
1054 krb5_boolean valid_cksum
= 0;
1055 krb5_enc_sam_response_enc_2 enc_sam_response_enc_2
;
1056 krb5_sam_response_2 sr2
;
1058 krb5_pa_data
*sam_padata
;
1060 if (prompter
== NULL
)
1061 return KRB5_LIBOS_CANTREADPWD
;
1063 tmp_data
.length
= in_padata
->length
;
1064 tmp_data
.data
= (char *)in_padata
->contents
;
1066 if ((retval
= decode_krb5_sam_challenge_2(&tmp_data
, &sc2
)))
1069 retval
= decode_krb5_sam_challenge_2_body(&sc2
->sam_challenge_2_body
, &sc2b
);
1074 if (!sc2
->sam_cksum
|| ! *sc2
->sam_cksum
) {
1075 krb5_free_sam_challenge_2(context
, sc2
);
1076 krb5_free_sam_challenge_2_body(context
, sc2b
);
1077 return(KRB5_SAM_NO_CHECKSUM
);
1080 if (sc2b
->sam_flags
& KRB5_SAM_MUST_PK_ENCRYPT_SAD
) {
1081 krb5_free_sam_challenge_2(context
, sc2
);
1082 krb5_free_sam_challenge_2_body(context
, sc2b
);
1083 return(KRB5_SAM_UNSUPPORTED
);
1086 if (!valid_enctype(sc2b
->sam_etype
)) {
1087 krb5_free_sam_challenge_2(context
, sc2
);
1088 krb5_free_sam_challenge_2_body(context
, sc2b
);
1089 return(KRB5_SAM_INVALID_ETYPE
);
1092 /* All of the above error checks are KDC-specific, that is, they */
1093 /* assume a failure in the KDC reply. By returning anything other */
1094 /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED, */
1095 /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will */
1096 /* most likely go on to try the AS_REQ against master KDC */
1098 if (!(sc2b
->sam_flags
& KRB5_SAM_USE_SAD_AS_KEY
)) {
1099 /* We will need the password to obtain the key used for */
1100 /* the checksum, and encryption of the sam_response. */
1101 /* Go ahead and get it now, preserving the ordering of */
1102 /* prompts for the user. */
1104 retval
= (gak_fct
)(context
, request
->client
,
1105 sc2b
->sam_etype
, prompter
,
1106 prompter_data
, salt
, s2kparams
, as_key
, gak_data
);
1108 krb5_free_sam_challenge_2(context
, sc2
);
1109 krb5_free_sam_challenge_2_body(context
, sc2b
);
1114 sprintf(name
, "%.*s",
1115 SAMDATA(sc2b
->sam_type_name
, "SAM Authentication",
1118 sprintf(banner
, "%.*s",
1119 SAMDATA(sc2b
->sam_challenge_label
,
1120 sam_challenge_banner(sc2b
->sam_type
),
1123 sprintf(prompt
, "%s%.*s%s%.*s",
1124 sc2b
->sam_challenge
.length
?"Challenge is [":"",
1125 SAMDATA(sc2b
->sam_challenge
, "", 20),
1126 sc2b
->sam_challenge
.length
?"], ":"",
1127 SAMDATA(sc2b
->sam_response_prompt
, "passcode", 55));
1129 response_data
.data
= response
;
1130 response_data
.length
= sizeof(response
);
1131 kprompt
.prompt
= prompt
;
1133 kprompt
.reply
= &response_data
;
1135 prompt_type
= KRB5_PROMPT_TYPE_PREAUTH
;
1136 krb5int_set_prompt_types(context
, &prompt_type
);
1138 if ((retval
= ((*prompter
)(context
, prompter_data
, name
,
1139 banner
, 1, &kprompt
)))) {
1140 krb5_free_sam_challenge_2(context
, sc2
);
1141 krb5_free_sam_challenge_2_body(context
, sc2b
);
1142 krb5int_set_prompt_types(context
, 0);
1146 krb5int_set_prompt_types(context
, (krb5_prompt_type
*)NULL
);
1148 /* Generate salt used by string_to_key() */
1149 if ((salt
->length
== -1) && (salt
->data
== NULL
)) {
1151 krb5_principal2salt(context
, request
->client
, &defsalt
))) {
1152 krb5_free_sam_challenge_2(context
, sc2
);
1153 krb5_free_sam_challenge_2_body(context
, sc2b
);
1161 /* Get encryption key to be used for checksum and sam_response */
1162 if (!(sc2b
->sam_flags
& KRB5_SAM_USE_SAD_AS_KEY
)) {
1163 /* as_key = string_to_key(password) */
1165 if (as_key
->length
) {
1166 krb5_free_keyblock_contents(context
, as_key
);
1170 /* generate a key using the supplied password */
1171 retval
= krb5_c_string_to_key(context
, sc2b
->sam_etype
,
1172 (krb5_data
*)gak_data
, salt
, as_key
);
1175 krb5_free_sam_challenge_2(context
, sc2
);
1176 krb5_free_sam_challenge_2_body(context
, sc2b
);
1177 if (defsalt
.length
) krb5_xfree(defsalt
.data
);
1181 if (!(sc2b
->sam_flags
& KRB5_SAM_SEND_ENCRYPTED_SAD
)) {
1182 /* as_key = combine_key (as_key, string_to_key(SAD)) */
1183 krb5_keyblock tmp_kb
;
1185 retval
= krb5_c_string_to_key(context
, sc2b
->sam_etype
,
1186 &response_data
, salt
, &tmp_kb
);
1189 krb5_free_sam_challenge_2(context
, sc2
);
1190 krb5_free_sam_challenge_2_body(context
, sc2b
);
1191 if (defsalt
.length
) krb5_xfree(defsalt
.data
);
1195 /* This should be a call to the crypto library some day */
1196 /* key types should already match the sam_etype */
1197 retval
= krb5int_c_combine_keys(context
, as_key
, &tmp_kb
, as_key
);
1200 krb5_free_sam_challenge_2(context
, sc2
);
1201 krb5_free_sam_challenge_2_body(context
, sc2b
);
1202 if (defsalt
.length
) krb5_xfree(defsalt
.data
);
1205 krb5_free_keyblock_contents(context
, &tmp_kb
);
1209 krb5_xfree(defsalt
.data
);
1212 /* as_key = string_to_key(SAD) */
1214 if (as_key
->length
) {
1215 krb5_free_keyblock_contents(context
, as_key
);
1219 /* generate a key using the supplied password */
1220 retval
= krb5_c_string_to_key(context
, sc2b
->sam_etype
,
1221 &response_data
, salt
, as_key
);
1224 krb5_xfree(defsalt
.data
);
1227 krb5_free_sam_challenge_2(context
, sc2
);
1228 krb5_free_sam_challenge_2_body(context
, sc2b
);
1233 /* Now we have a key, verify the checksum on the sam_challenge */
1235 cksum
= sc2
->sam_cksum
;
1238 /* Check this cksum */
1239 retval
= krb5_c_verify_checksum(context
, as_key
,
1240 KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM
,
1241 &sc2
->sam_challenge_2_body
,
1242 *cksum
, &valid_cksum
);
1244 krb5_free_data(context
, scratch
);
1245 krb5_free_sam_challenge_2(context
, sc2
);
1246 krb5_free_sam_challenge_2_body(context
, sc2b
);
1256 /* If KRB5_SAM_SEND_ENCRYPTED_SAD is set, then password is only */
1257 /* source for checksum key. Therefore, a bad checksum means a */
1258 /* bad password. Don't give that direct feedback to someone */
1259 /* trying to brute-force passwords. */
1261 if (!(sc2b
->sam_flags
& KRB5_SAM_SEND_ENCRYPTED_SAD
))
1262 krb5_free_sam_challenge_2(context
, sc2
);
1263 krb5_free_sam_challenge_2_body(context
, sc2b
);
1265 * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications
1266 * can interpret that as "password incorrect", which is probably
1267 * the best error we can return in this situation.
1269 return(KRB5KRB_AP_ERR_BAD_INTEGRITY
);
1272 /* fill in enc_sam_response_enc_2 */
1273 enc_sam_response_enc_2
.magic
= KV5M_ENC_SAM_RESPONSE_ENC_2
;
1274 enc_sam_response_enc_2
.sam_nonce
= sc2b
->sam_nonce
;
1275 if (sc2b
->sam_flags
& KRB5_SAM_SEND_ENCRYPTED_SAD
) {
1276 enc_sam_response_enc_2
.sam_sad
= response_data
;
1278 enc_sam_response_enc_2
.sam_sad
.data
= NULL
;
1279 enc_sam_response_enc_2
.sam_sad
.length
= 0;
1282 /* encode and encrypt enc_sam_response_enc_2 with as_key */
1283 retval
= encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2
,
1286 krb5_free_sam_challenge_2(context
, sc2
);
1287 krb5_free_sam_challenge_2_body(context
, sc2b
);
1291 /* Fill in sam_response_2 */
1292 memset(&sr2
, 0, sizeof(sr2
));
1293 sr2
.sam_type
= sc2b
->sam_type
;
1294 sr2
.sam_flags
= sc2b
->sam_flags
;
1295 sr2
.sam_track_id
= sc2b
->sam_track_id
;
1296 sr2
.sam_nonce
= sc2b
->sam_nonce
;
1298 /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded */
1299 /* enc_sam_response_enc_2 from above */
1301 retval
= krb5_c_encrypt_length(context
, as_key
->enctype
, scratch
->length
,
1304 krb5_free_sam_challenge_2(context
, sc2
);
1305 krb5_free_sam_challenge_2_body(context
, sc2b
);
1308 sr2
.sam_enc_nonce_or_sad
.ciphertext
.length
= ciph_len
;
1310 sr2
.sam_enc_nonce_or_sad
.ciphertext
.data
=
1311 (char *)malloc(sr2
.sam_enc_nonce_or_sad
.ciphertext
.length
);
1313 if (!sr2
.sam_enc_nonce_or_sad
.ciphertext
.data
) {
1314 krb5_free_sam_challenge_2(context
, sc2
);
1315 krb5_free_sam_challenge_2_body(context
, sc2b
);
1319 retval
= krb5_c_encrypt(context
, as_key
, KRB5_KEYUSAGE_PA_SAM_RESPONSE
,
1320 NULL
, scratch
, &sr2
.sam_enc_nonce_or_sad
);
1322 krb5_free_sam_challenge_2(context
, sc2
);
1323 krb5_free_sam_challenge_2_body(context
, sc2b
);
1324 krb5_free_data(context
, scratch
);
1325 krb5_free_data_contents(context
, &sr2
.sam_enc_nonce_or_sad
.ciphertext
);
1328 krb5_free_data(context
, scratch
);
1331 /* Encode the sam_response_2 */
1332 retval
= encode_krb5_sam_response_2(&sr2
, &scratch
);
1333 krb5_free_sam_challenge_2(context
, sc2
);
1334 krb5_free_sam_challenge_2_body(context
, sc2b
);
1335 krb5_free_data_contents(context
, &sr2
.sam_enc_nonce_or_sad
.ciphertext
);
1341 /* Almost there, just need to make padata ! */
1342 sam_padata
= malloc(sizeof(krb5_pa_data
));
1343 if (sam_padata
== NULL
) {
1344 krb5_free_data(context
, scratch
);
1348 sam_padata
->magic
= KV5M_PA_DATA
;
1349 sam_padata
->pa_type
= KRB5_PADATA_SAM_RESPONSE_2
;
1350 sam_padata
->length
= scratch
->length
;
1351 sam_padata
->contents
= (krb5_octet
*) scratch
->data
;
1353 *out_padata
= sam_padata
;
1358 static const pa_types_t pa_types
[] = {
1360 KRB5_PADATA_PW_SALT
,
1365 KRB5_PADATA_AFS3_SALT
,
1370 KRB5_PADATA_ENC_TIMESTAMP
,
1375 KRB5_PADATA_SAM_CHALLENGE_2
,
1380 KRB5_PADATA_SAM_CHALLENGE
,
1392 * If one of the modules can adjust its AS_REQ data using the contents of the
1393 * err_reply, return 0. If it's the sort of correction which requires that we
1394 * ask the user another question, we let the calling application deal with it.
1396 krb5_error_code KRB5_CALLCONV
1397 krb5_do_preauth_tryagain(krb5_context kcontext
,
1398 krb5_kdc_req
*request
,
1399 krb5_data
*encoded_request_body
,
1400 krb5_data
*encoded_previous_request
,
1401 krb5_pa_data
**padata
,
1402 krb5_pa_data
***return_padata
,
1403 krb5_error
*err_reply
,
1404 krb5_data
*salt
, krb5_data
*s2kparams
,
1405 krb5_enctype
*etype
,
1406 krb5_keyblock
*as_key
,
1407 krb5_prompter_fct prompter
, void *prompter_data
,
1408 krb5_gic_get_as_key_fct gak_fct
, void *gak_data
,
1409 krb5_preauth_client_rock
*get_data_rock
,
1410 krb5_gic_opt_ext
*opte
)
1412 krb5_error_code ret
;
1413 krb5_pa_data
**out_padata
;
1414 krb5_preauth_context
*context
;
1415 struct _krb5_preauth_context_module
*module
;
1417 int out_pa_list_size
= 0;
1419 ret
= KRB5KRB_ERR_GENERIC
;
1420 if (kcontext
->preauth_context
== NULL
) {
1421 return KRB5KRB_ERR_GENERIC
;
1423 context
= kcontext
->preauth_context
;
1424 if (context
== NULL
) {
1425 return KRB5KRB_ERR_GENERIC
;
1428 for (i
= 0; padata
[i
] != NULL
&& padata
[i
]->pa_type
!= 0; i
++) {
1430 for (j
= 0; j
< context
->n_modules
; j
++) {
1431 module
= &context
->modules
[j
];
1432 if (module
->pa_type
!= padata
[i
]->pa_type
) {
1435 if (module
->client_tryagain
== NULL
) {
1438 if ((*module
->client_tryagain
)(kcontext
,
1439 module
->plugin_context
,
1440 *module
->request_context_pp
,
1441 (krb5_get_init_creds_opt
*)opte
,
1445 encoded_request_body
,
1446 encoded_previous_request
,
1449 prompter
, prompter_data
,
1450 gak_fct
, gak_data
, salt
, s2kparams
,
1452 &out_padata
) == 0) {
1453 if (out_padata
!= NULL
) {
1455 for (k
= 0; out_padata
[k
] != NULL
; k
++);
1456 grow_pa_list(return_padata
, &out_pa_list_size
,
1467 krb5_error_code KRB5_CALLCONV
1468 krb5_do_preauth(krb5_context context
,
1469 krb5_kdc_req
*request
,
1470 krb5_data
*encoded_request_body
,
1471 krb5_data
*encoded_previous_request
,
1472 krb5_pa_data
**in_padata
, krb5_pa_data
***out_padata
,
1473 krb5_data
*salt
, krb5_data
*s2kparams
,
1474 krb5_enctype
*etype
,
1475 krb5_keyblock
*as_key
,
1476 krb5_prompter_fct prompter
, void *prompter_data
,
1477 krb5_gic_get_as_key_fct gak_fct
, void *gak_data
,
1478 krb5_preauth_client_rock
*get_data_rock
,
1479 krb5_gic_opt_ext
*opte
)
1481 int h
, i
, j
, out_pa_list_size
;
1482 int seen_etype_info2
= 0;
1483 krb5_pa_data
*out_pa
= NULL
, **out_pa_list
= NULL
;
1485 krb5_etype_info etype_info
= NULL
;
1486 krb5_error_code ret
;
1487 static const int paorder
[] = { PA_INFO
, PA_REAL
};
1490 /* Solaris Kerberos */
1491 KRB5_LOG0(KRB5_INFO
, "krb5_do_preauth() start");
1493 if (in_padata
== NULL
) {
1499 /* Solaris Kerberos */
1500 if (salt
&& salt
->data
&& salt
->length
> 0) {
1501 fprintf (stderr
, "salt len=%d", salt
->length
);
1502 if ((int) salt
->length
> 0)
1503 fprintf (stderr
, " '%*s'", salt
->length
, salt
->data
);
1504 fprintf (stderr
, "; preauth data types:");
1505 for (i
= 0; in_padata
[i
]; i
++) {
1506 fprintf (stderr
, " %d", in_padata
[i
]->pa_type
);
1508 fprintf (stderr
, "\n");
1513 out_pa_list_size
= 0;
1515 /* first do all the informational preauths, then the first real one */
1517 for (h
=0; h
<(sizeof(paorder
)/sizeof(paorder
[0])); h
++) {
1519 for (i
=0; in_padata
[i
] && !realdone
; i
++) {
1520 int k
, l
, etype_found
, valid_etype_found
;
1522 * This is really gross, but is necessary to prevent
1523 * lossage when talking to a 1.0.x KDC, which returns an
1524 * erroneous PA-PW-SALT when it returns a KRB-ERROR
1525 * requiring additional preauth.
1527 switch (in_padata
[i
]->pa_type
) {
1528 case KRB5_PADATA_ETYPE_INFO
:
1529 case KRB5_PADATA_ETYPE_INFO2
:
1531 krb5_preauthtype pa_type
= in_padata
[i
]->pa_type
;
1533 if (seen_etype_info2
|| pa_type
!= KRB5_PADATA_ETYPE_INFO2
)
1535 if (pa_type
== KRB5_PADATA_ETYPE_INFO2
) {
1536 krb5_free_etype_info( context
, etype_info
);
1541 scratch
.length
= in_padata
[i
]->length
;
1542 scratch
.data
= (char *) in_padata
[i
]->contents
;
1543 if (pa_type
== KRB5_PADATA_ETYPE_INFO2
) {
1545 ret
= decode_krb5_etype_info2(&scratch
, &etype_info
);
1547 else ret
= decode_krb5_etype_info(&scratch
, &etype_info
);
1549 ret
= 0; /*Ignore error and etype_info element*/
1551 krb5_free_etype_info( context
, etype_info
);
1555 if (etype_info
[0] == NULL
) {
1556 krb5_free_etype_info(context
, etype_info
);
1561 * Select first etype in our request which is also in
1562 * etype-info (preferring client request ktype order).
1564 for (etype_found
= 0, valid_etype_found
= 0, k
= 0;
1565 !etype_found
&& k
< request
->nktypes
; k
++) {
1566 for (l
= 0; etype_info
[l
]; l
++) {
1567 if (etype_info
[l
]->etype
== request
->ktype
[k
]) {
1571 /* check if program has support for this etype for more
1572 * precise error reporting.
1574 if (valid_enctype(etype_info
[l
]->etype
))
1575 valid_etype_found
++;
1579 /* Solaris Kerberos */
1580 KRB5_LOG(KRB5_ERR
, "error !etype_found, "
1581 "valid_etype_found = %d",
1583 if (valid_etype_found
) {
1584 /* supported enctype but not requested */
1585 ret
= KRB5_CONFIG_ETYPE_NOSUPP
;
1589 /* unsupported enctype */
1590 ret
= KRB5_PROG_ETYPE_NOSUPP
;
1595 scratch
.data
= (char *) etype_info
[l
]->salt
;
1596 scratch
.length
= etype_info
[l
]->length
;
1597 krb5_free_data_contents(context
, salt
);
1598 if (scratch
.length
== KRB5_ETYPE_NO_SALT
)
1601 if ((ret
= krb5int_copy_data_contents( context
, &scratch
, salt
)) != 0)
1603 *etype
= etype_info
[l
]->etype
;
1604 krb5_free_data_contents(context
, s2kparams
);
1605 if ((ret
= krb5int_copy_data_contents(context
,
1606 &etype_info
[l
]->s2kparams
,
1610 for (j
= 0; etype_info
[j
]; j
++) {
1611 krb5_etype_info_entry
*e
= etype_info
[j
];
1612 fprintf (stderr
, "etype info %d: etype %d salt len=%d",
1613 j
, e
->etype
, e
->length
);
1614 if (e
->length
> 0 && e
->length
!= KRB5_ETYPE_NO_SALT
)
1615 fprintf (stderr
, " '%.*s'", e
->length
, e
->salt
);
1616 fprintf (stderr
, "\n");
1621 case KRB5_PADATA_PW_SALT
:
1622 case KRB5_PADATA_AFS3_SALT
:
1629 /* Try the internally-provided preauth type list. */
1630 if (!realdone
) for (j
=0; pa_types
[j
].type
>= 0; j
++) {
1631 if ((in_padata
[i
]->pa_type
== pa_types
[j
].type
) &&
1632 (pa_types
[j
].flags
& paorder
[h
])) {
1634 fprintf (stderr
, "calling internal function for pa_type "
1635 "%d, flag %d\n", pa_types
[j
].type
, paorder
[h
]);
1639 if ((ret
= ((*pa_types
[j
].fct
)(context
, request
,
1640 in_padata
[i
], &out_pa
,
1641 salt
, s2kparams
, etype
, as_key
,
1642 prompter
, prompter_data
,
1643 gak_fct
, gak_data
)))) {
1647 ret
= grow_pa_list(&out_pa_list
, &out_pa_list_size
,
1652 if (paorder
[h
] == PA_REAL
)
1657 /* Try to use plugins now. */
1659 krb5_init_preauth_context(context
);
1660 if (context
->preauth_context
!= NULL
) {
1661 int module_ret
, module_flags
;
1663 fprintf (stderr
, "trying modules for pa_type %d, flag %d\n",
1664 in_padata
[i
]->pa_type
, paorder
[h
]);
1666 ret
= krb5_run_preauth_plugins(context
,
1669 encoded_request_body
,
1670 encoded_previous_request
,
1685 if (module_ret
== 0) {
1686 if (paorder
[h
] == PA_REAL
) {
1696 *out_padata
= out_pa_list
;
1698 krb5_free_etype_info(context
, etype_info
);
1700 /* Solaris Kerberos */
1701 KRB5_LOG0(KRB5_INFO
, "krb5_do_preauth() end");
1705 out_pa_list
[out_pa_list_size
++] = NULL
;
1706 krb5_free_pa_data(context
, out_pa_list
);
1709 krb5_free_etype_info(context
, etype_info
);
1711 /* Solaris Kerberos */
1712 KRB5_LOG0(KRB5_INFO
, "krb5_do_preauth() end");