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
:
469 /* Tweak the request body, for now adding any enctypes which the module claims
470 * to add support for to the list, but in the future perhaps doing more
471 * involved things. */
473 krb5_preauth_prepare_request(krb5_context kcontext
,
474 krb5_gic_opt_ext
*opte
,
475 krb5_kdc_req
*request
)
479 if (kcontext
->preauth_context
== NULL
) {
482 /* Add the module-specific enctype list to the request, but only if
483 * it's something we can safely modify. */
484 if (!(opte
&& (opte
->flags
& KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST
))) {
485 for (i
= 0; i
< kcontext
->preauth_context
->n_modules
; i
++) {
486 if (kcontext
->preauth_context
->modules
[i
].enctypes
== NULL
)
488 for (j
= 0; kcontext
->preauth_context
->modules
[i
].enctypes
[j
] != 0; j
++) {
489 grow_ktypes(&request
->ktype
, &request
->nktypes
,
490 kcontext
->preauth_context
->modules
[i
].enctypes
[j
]);
496 /* Find the first module which provides for the named preauth type which also
497 * hasn't had a chance to run yet (INFO modules don't count, because as a rule
498 * they don't generate preauth data), and run it. */
499 static krb5_error_code
500 krb5_run_preauth_plugins(krb5_context kcontext
,
501 int module_required_flags
,
502 krb5_kdc_req
*request
,
503 krb5_data
*encoded_request_body
,
504 krb5_data
*encoded_previous_request
,
505 krb5_pa_data
*in_padata
,
506 krb5_prompter_fct prompter
,
508 preauth_get_as_key_proc gak_fct
,
510 krb5_data
*s2kparams
,
512 krb5_preauth_client_rock
*get_data_rock
,
513 krb5_keyblock
*as_key
,
514 krb5_pa_data
***out_pa_list
,
515 int *out_pa_list_size
,
518 krb5_gic_opt_ext
*opte
)
521 krb5_pa_data
**out_pa_data
;
523 struct _krb5_preauth_context_module
*module
;
525 if (kcontext
->preauth_context
== NULL
) {
528 /* iterate over all loaded modules */
529 for (i
= 0; i
< kcontext
->preauth_context
->n_modules
; i
++) {
530 module
= &kcontext
->preauth_context
->modules
[i
];
531 /* skip over those which don't match the preauth type */
532 if (module
->pa_type
!= in_padata
->pa_type
)
534 /* skip over those which don't match the flags (INFO vs REAL, mainly) */
535 if ((module
->flags
& module_required_flags
) == 0)
537 /* if it's a REAL module, try to call it only once per library call */
538 if (module_required_flags
& PA_REAL
) {
539 if (module
->use_count
> 0) {
541 fprintf(stderr
, "skipping already-used module \"%s\"(%d)\n",
542 module
->name
, module
->pa_type
);
548 /* run the module's callback function */
551 fprintf(stderr
, "using module \"%s\" (%d), flags = %d\n",
552 module
->name
, module
->pa_type
, module
->flags
);
554 ret
= module
->client_process(kcontext
,
555 module
->plugin_context
,
556 *module
->request_context_pp
,
557 (krb5_get_init_creds_opt
*)opte
,
561 encoded_request_body
,
562 encoded_previous_request
,
564 prompter
, prompter_data
,
565 gak_fct
, gak_data
, salt
, s2kparams
,
568 /* Make note of the module's flags and status. */
569 *module_flags
= module
->flags
;
571 /* Save the new preauth data item. */
572 if (out_pa_data
!= NULL
) {
574 for (j
= 0; out_pa_data
[j
] != NULL
; j
++);
575 ret
= grow_pa_list(out_pa_list
, out_pa_list_size
, out_pa_data
, j
);
582 if (i
>= kcontext
->preauth_context
->n_modules
) {
589 krb5_error_code
pa_salt(krb5_context context
,
590 krb5_kdc_req
*request
,
591 krb5_pa_data
*in_padata
,
592 krb5_pa_data
**out_padata
,
593 krb5_data
*salt
, krb5_data
*s2kparams
,
595 krb5_keyblock
*as_key
,
596 krb5_prompter_fct prompter
, void *prompter_data
,
597 krb5_gic_get_as_key_fct gak_fct
, void *gak_data
)
601 /* Solaris Kerberos - resync */
602 tmp
.data
= (char *)in_padata
->contents
;
603 tmp
.length
= in_padata
->length
;
604 krb5_free_data_contents(context
, salt
);
605 krb5int_copy_data_contents(context
, &tmp
, salt
);
608 if (in_padata
->pa_type
== KRB5_PADATA_AFS3_SALT
)
609 salt
->length
= SALT_TYPE_AFS_LENGTH
;
616 krb5_error_code
pa_enc_timestamp(krb5_context context
,
617 krb5_kdc_req
*request
,
618 krb5_pa_data
*in_padata
,
619 krb5_pa_data
**out_padata
,
621 krb5_data
*s2kparams
,
623 krb5_keyblock
*as_key
,
624 krb5_prompter_fct prompter
,
626 krb5_gic_get_as_key_fct gak_fct
,
630 krb5_pa_enc_ts pa_enc
;
632 krb5_enc_data enc_data
;
635 if (as_key
->length
== 0) {
637 /* Solaris Kerberos */
638 if (salt
!= NULL
&& salt
->data
!= NULL
) {
639 fprintf (stderr
, "%s:%d: salt len=%d", __FILE__
, __LINE__
,
641 if ((int) salt
->length
> 0)
642 fprintf (stderr
, " '%.*s'", salt
->length
, salt
->data
);
643 fprintf (stderr
, "; *etype=%d request->ktype[0]=%d\n",
644 *etype
, request
->ktype
[0]);
647 if ((ret
= ((*gak_fct
)(context
, request
->client
,
648 *etype
? *etype
: request
->ktype
[0],
649 prompter
, prompter_data
,
650 salt
, s2kparams
, as_key
, gak_data
))))
654 /* now get the time of day, and encrypt it accordingly */
656 if ((ret
= krb5_us_timeofday(context
, &pa_enc
.patimestamp
, &pa_enc
.pausec
)))
659 if ((ret
= encode_krb5_pa_enc_ts(&pa_enc
, &tmp
)))
663 fprintf (stderr
, "key type %d bytes %02x %02x ...\n",
665 as_key
->contents
[0], as_key
->contents
[1]);
667 ret
= krb5_encrypt_helper(context
, as_key
,
668 KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS
,
671 fprintf (stderr
, "enc data { type=%d kvno=%d data=%02x %02x ... }\n",
672 enc_data
.enctype
, enc_data
.kvno
,
673 0xff & enc_data
.ciphertext
.data
[0],
674 0xff & enc_data
.ciphertext
.data
[1]);
677 krb5_free_data(context
, tmp
);
680 krb5_xfree(enc_data
.ciphertext
.data
);
684 ret
= encode_krb5_enc_data(&enc_data
, &tmp
);
686 krb5_xfree(enc_data
.ciphertext
.data
);
691 if ((pa
= (krb5_pa_data
*) malloc(sizeof(krb5_pa_data
))) == NULL
) {
692 krb5_free_data(context
, tmp
);
696 pa
->magic
= KV5M_PA_DATA
;
697 pa
->pa_type
= KRB5_PADATA_ENC_TIMESTAMP
;
698 pa
->length
= tmp
->length
;
699 pa
->contents
= (krb5_octet
*) tmp
->data
;
709 char *sam_challenge_banner(krb5_int32 sam_type
)
714 case PA_SAM_TYPE_ENIGMA
: /* Enigma Logic */
715 label
= "Challenge for Enigma Logic mechanism";
717 case PA_SAM_TYPE_DIGI_PATH
: /* Digital Pathways */
718 case PA_SAM_TYPE_DIGI_PATH_HEX
: /* Digital Pathways */
719 label
= "Challenge for Digital Pathways mechanism";
721 case PA_SAM_TYPE_ACTIVCARD_DEC
: /* Digital Pathways */
722 case PA_SAM_TYPE_ACTIVCARD_HEX
: /* Digital Pathways */
723 label
= "Challenge for Activcard mechanism";
725 case PA_SAM_TYPE_SKEY_K0
: /* S/key where KDC has key 0 */
726 label
= "Challenge for Enhanced S/Key mechanism";
728 case PA_SAM_TYPE_SKEY
: /* Traditional S/Key */
729 label
= "Challenge for Traditional S/Key mechanism";
731 case PA_SAM_TYPE_SECURID
: /* Security Dynamics */
732 label
= "Challenge for Security Dynamics mechanism";
734 case PA_SAM_TYPE_SECURID_PREDICT
: /* predictive Security Dynamics */
735 label
= "Challenge for Security Dynamics mechanism";
738 label
= "Challenge from authentication server";
745 /* this macro expands to the int,ptr necessary for "%.*s" in an sprintf */
747 #define SAMDATA(kdata, str, maxsize) \
748 (int)((kdata.length)? \
749 ((((kdata.length)<=(maxsize))?(kdata.length):strlen(str))): \
752 ((((kdata.length)<=(maxsize))?(kdata.data):(str))):(str)
754 /* XXX Danger! This code is not in sync with the kerberos-password-02
755 draft. This draft cannot be implemented as written. This code is
756 compatible with earlier versions of mit krb5 and cygnus kerbnet. */
760 krb5_error_code
pa_sam(krb5_context context
,
761 krb5_kdc_req
*request
,
762 krb5_pa_data
*in_padata
,
763 krb5_pa_data
**out_padata
,
765 krb5_data
*s2kparams
,
767 krb5_keyblock
*as_key
,
768 krb5_prompter_fct prompter
,
770 krb5_gic_get_as_key_fct gak_fct
,
775 char name
[100], banner
[100];
776 char prompt
[100], response
[100];
777 krb5_data response_data
;
779 krb5_prompt_type prompt_type
;
781 krb5_sam_challenge
*sam_challenge
= 0;
782 krb5_sam_response sam_response
;
783 /* these two get encrypted and stuffed in to sam_response */
784 krb5_enc_sam_response_enc enc_sam_response_enc
;
788 /* Solaris Kerberos */
789 krb5_enc_data
* enc_data
;
792 if (prompter
== NULL
)
795 tmpsam
.length
= in_padata
->length
;
796 tmpsam
.data
= (char *) in_padata
->contents
;
797 if ((ret
= decode_krb5_sam_challenge(&tmpsam
, &sam_challenge
)))
800 if (sam_challenge
->sam_flags
& KRB5_SAM_MUST_PK_ENCRYPT_SAD
) {
801 krb5_xfree(sam_challenge
);
802 return(KRB5_SAM_UNSUPPORTED
);
805 /* If we need the password from the user (USE_SAD_AS_KEY not set), */
806 /* then get it here. Exception for "old" KDCs with CryptoCard */
807 /* support which uses the USE_SAD_AS_KEY flag, but still needs pwd */
809 if (!(sam_challenge
->sam_flags
& KRB5_SAM_USE_SAD_AS_KEY
) ||
810 (sam_challenge
->sam_type
== PA_SAM_TYPE_CRYPTOCARD
)) {
812 /* etype has either been set by caller or by KRB5_PADATA_ETYPE_INFO */
813 /* message from the KDC. If it is not set, pick an enctype that we */
814 /* think the KDC will have for us. */
816 if (etype
&& *etype
== 0)
817 *etype
= ENCTYPE_DES_CBC_CRC
;
819 if ((ret
= (gak_fct
)(context
, request
->client
, *etype
, prompter
,
820 prompter_data
, salt
, s2kparams
, as_key
, gak_data
)))
823 sprintf(name
, "%.*s",
824 SAMDATA(sam_challenge
->sam_type_name
, "SAM Authentication",
827 sprintf(banner
, "%.*s",
828 SAMDATA(sam_challenge
->sam_challenge_label
,
829 sam_challenge_banner(sam_challenge
->sam_type
),
832 /* sprintf(prompt, "Challenge is [%s], %s: ", challenge, prompt); */
833 sprintf(prompt
, "%s%.*s%s%.*s",
834 sam_challenge
->sam_challenge
.length
?"Challenge is [":"",
835 SAMDATA(sam_challenge
->sam_challenge
, "", 20),
836 sam_challenge
->sam_challenge
.length
?"], ":"",
837 SAMDATA(sam_challenge
->sam_response_prompt
, "passcode", 55));
839 response_data
.data
= response
;
840 response_data
.length
= sizeof(response
);
842 kprompt
.prompt
= prompt
;
844 kprompt
.reply
= &response_data
;
845 prompt_type
= KRB5_PROMPT_TYPE_PREAUTH
;
847 /* PROMPTER_INVOCATION */
848 krb5int_set_prompt_types(context
, &prompt_type
);
849 if ((ret
= ((*prompter
)(context
, prompter_data
, name
,
850 banner
, 1, &kprompt
)))) {
851 krb5_xfree(sam_challenge
);
852 krb5int_set_prompt_types(context
, 0);
855 krb5int_set_prompt_types(context
, 0);
857 enc_sam_response_enc
.sam_nonce
= sam_challenge
->sam_nonce
;
858 if (sam_challenge
->sam_nonce
== 0) {
859 if ((ret
= krb5_us_timeofday(context
,
860 &enc_sam_response_enc
.sam_timestamp
,
861 &enc_sam_response_enc
.sam_usec
))) {
862 krb5_xfree(sam_challenge
);
866 sam_response
.sam_patimestamp
= enc_sam_response_enc
.sam_timestamp
;
869 /* XXX What if more than one flag is set? */
870 if (sam_challenge
->sam_flags
& KRB5_SAM_SEND_ENCRYPTED_SAD
) {
872 /* Most of this should be taken care of before we get here. We */
873 /* will need the user's password and as_key to encrypt the SAD */
874 /* and we want to preserve ordering of user prompts (first */
875 /* password, then SAM data) so that user's won't be confused. */
877 if (as_key
->length
) {
878 krb5_free_keyblock_contents(context
, as_key
);
882 /* generate a salt using the requested principal */
884 if ((salt
->length
== -1 || salt
->length
== SALT_TYPE_AFS_LENGTH
) && (salt
->data
== NULL
)) {
885 if ((ret
= krb5_principal2salt(context
, request
->client
,
887 krb5_xfree(sam_challenge
);
896 /* generate a key using the supplied password */
898 ret
= krb5_c_string_to_key(context
, ENCTYPE_DES_CBC_MD5
,
899 (krb5_data
*)gak_data
, salt
, as_key
);
902 krb5_xfree(defsalt
.data
);
905 krb5_xfree(sam_challenge
);
909 /* encrypt the passcode with the key from above */
911 enc_sam_response_enc
.sam_sad
= response_data
;
912 } else if (sam_challenge
->sam_flags
& KRB5_SAM_USE_SAD_AS_KEY
) {
914 /* process the key as password */
916 if (as_key
->length
) {
917 krb5_free_keyblock_contents(context
, as_key
);
922 if ((salt
->length
== SALT_TYPE_AFS_LENGTH
) && (salt
->data
== NULL
)) {
923 if (ret
= krb5_principal2salt(context
, request
->client
,
925 krb5_xfree(sam_challenge
);
938 /* XXX As of the passwords-04 draft, no enctype is specified,
939 the server uses ENCTYPE_DES_CBC_MD5. In the future the
940 server should send a PA-SAM-ETYPE-INFO containing the enctype. */
942 ret
= krb5_c_string_to_key(context
, ENCTYPE_DES_CBC_MD5
,
943 &response_data
, salt
, as_key
);
946 krb5_xfree(defsalt
.data
);
949 krb5_xfree(sam_challenge
);
953 enc_sam_response_enc
.sam_sad
.length
= 0;
955 /* Eventually, combine SAD with long-term key to get
957 return KRB5_PREAUTH_BAD_TYPE
;
960 /* copy things from the challenge */
961 sam_response
.sam_nonce
= sam_challenge
->sam_nonce
;
962 sam_response
.sam_flags
= sam_challenge
->sam_flags
;
963 sam_response
.sam_track_id
= sam_challenge
->sam_track_id
;
964 sam_response
.sam_type
= sam_challenge
->sam_type
;
965 sam_response
.magic
= KV5M_SAM_RESPONSE
;
967 krb5_xfree(sam_challenge
);
969 /* encode the encoded part of the response */
970 if ((ret
= encode_krb5_enc_sam_response_enc(&enc_sam_response_enc
,
976 * Using new crypto interface now so we can get rid of the
979 if ((ret
= krb5_c_encrypt_length(context
, as_key
->enctype
,
980 scratch
->length
, &enclen
))) {
981 krb5_free_data(context
, scratch
);
985 enc_data
= &sam_response
.sam_enc_nonce_or_ts
;
986 enc_data
->magic
= KV5M_ENC_DATA
;
988 enc_data
->enctype
= as_key
->enctype
;
989 enc_data
->ciphertext
.length
= enclen
;
991 if ((enc_data
->ciphertext
.data
= MALLOC(enclen
)) == NULL
) {
992 enc_data
->ciphertext
.length
= 0;
993 krb5_free_data(context
, scratch
);
997 if ((ret
= krb5_c_encrypt(context
, as_key
, 0, 0,
998 scratch
, enc_data
))) {
999 FREE(enc_data
->ciphertext
.data
, enclen
);
1000 enc_data
->ciphertext
.data
= NULL
;
1001 enc_data
->ciphertext
.length
= 0;
1004 krb5_free_data(context
, scratch
);
1009 /* sam_enc_key is reserved for future use */
1010 sam_response
.sam_enc_key
.ciphertext
.length
= 0;
1012 if ((pa
= malloc(sizeof(krb5_pa_data
))) == NULL
)
1015 if ((ret
= encode_krb5_sam_response(&sam_response
, &scratch
))) {
1020 pa
->magic
= KV5M_PA_DATA
;
1021 pa
->pa_type
= KRB5_PADATA_SAM_RESPONSE
;
1022 pa
->length
= scratch
->length
;
1023 pa
->contents
= (krb5_octet
*) scratch
->data
;
1031 krb5_error_code
pa_sam_2(krb5_context context
,
1032 krb5_kdc_req
*request
,
1033 krb5_pa_data
*in_padata
,
1034 krb5_pa_data
**out_padata
,
1036 krb5_data
*s2kparams
,
1037 krb5_enctype
*etype
,
1038 krb5_keyblock
*as_key
,
1039 krb5_prompter_fct prompter
,
1040 void *prompter_data
,
1041 krb5_gic_get_as_key_fct gak_fct
,
1044 krb5_error_code retval
;
1045 krb5_sam_challenge_2
*sc2
= NULL
;
1046 krb5_sam_challenge_2_body
*sc2b
= NULL
;
1048 krb5_data response_data
;
1049 char name
[100], banner
[100], prompt
[100], response
[100];
1050 krb5_prompt kprompt
;
1051 krb5_prompt_type prompt_type
;
1053 krb5_checksum
**cksum
;
1054 krb5_data
*scratch
= NULL
;
1055 krb5_boolean valid_cksum
= 0;
1056 krb5_enc_sam_response_enc_2 enc_sam_response_enc_2
;
1057 krb5_sam_response_2 sr2
;
1059 krb5_pa_data
*sam_padata
;
1061 if (prompter
== NULL
)
1062 return KRB5_LIBOS_CANTREADPWD
;
1064 tmp_data
.length
= in_padata
->length
;
1065 tmp_data
.data
= (char *)in_padata
->contents
;
1067 if ((retval
= decode_krb5_sam_challenge_2(&tmp_data
, &sc2
)))
1070 retval
= decode_krb5_sam_challenge_2_body(&sc2
->sam_challenge_2_body
, &sc2b
);
1075 if (!sc2
->sam_cksum
|| ! *sc2
->sam_cksum
) {
1076 krb5_free_sam_challenge_2(context
, sc2
);
1077 krb5_free_sam_challenge_2_body(context
, sc2b
);
1078 return(KRB5_SAM_NO_CHECKSUM
);
1081 if (sc2b
->sam_flags
& KRB5_SAM_MUST_PK_ENCRYPT_SAD
) {
1082 krb5_free_sam_challenge_2(context
, sc2
);
1083 krb5_free_sam_challenge_2_body(context
, sc2b
);
1084 return(KRB5_SAM_UNSUPPORTED
);
1087 if (!valid_enctype(sc2b
->sam_etype
)) {
1088 krb5_free_sam_challenge_2(context
, sc2
);
1089 krb5_free_sam_challenge_2_body(context
, sc2b
);
1090 return(KRB5_SAM_INVALID_ETYPE
);
1093 /* All of the above error checks are KDC-specific, that is, they */
1094 /* assume a failure in the KDC reply. By returning anything other */
1095 /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED, */
1096 /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will */
1097 /* most likely go on to try the AS_REQ against master KDC */
1099 if (!(sc2b
->sam_flags
& KRB5_SAM_USE_SAD_AS_KEY
)) {
1100 /* We will need the password to obtain the key used for */
1101 /* the checksum, and encryption of the sam_response. */
1102 /* Go ahead and get it now, preserving the ordering of */
1103 /* prompts for the user. */
1105 retval
= (gak_fct
)(context
, request
->client
,
1106 sc2b
->sam_etype
, prompter
,
1107 prompter_data
, salt
, s2kparams
, as_key
, gak_data
);
1109 krb5_free_sam_challenge_2(context
, sc2
);
1110 krb5_free_sam_challenge_2_body(context
, sc2b
);
1115 sprintf(name
, "%.*s",
1116 SAMDATA(sc2b
->sam_type_name
, "SAM Authentication",
1119 sprintf(banner
, "%.*s",
1120 SAMDATA(sc2b
->sam_challenge_label
,
1121 sam_challenge_banner(sc2b
->sam_type
),
1124 sprintf(prompt
, "%s%.*s%s%.*s",
1125 sc2b
->sam_challenge
.length
?"Challenge is [":"",
1126 SAMDATA(sc2b
->sam_challenge
, "", 20),
1127 sc2b
->sam_challenge
.length
?"], ":"",
1128 SAMDATA(sc2b
->sam_response_prompt
, "passcode", 55));
1130 response_data
.data
= response
;
1131 response_data
.length
= sizeof(response
);
1132 kprompt
.prompt
= prompt
;
1134 kprompt
.reply
= &response_data
;
1136 prompt_type
= KRB5_PROMPT_TYPE_PREAUTH
;
1137 krb5int_set_prompt_types(context
, &prompt_type
);
1139 if ((retval
= ((*prompter
)(context
, prompter_data
, name
,
1140 banner
, 1, &kprompt
)))) {
1141 krb5_free_sam_challenge_2(context
, sc2
);
1142 krb5_free_sam_challenge_2_body(context
, sc2b
);
1143 krb5int_set_prompt_types(context
, 0);
1147 krb5int_set_prompt_types(context
, (krb5_prompt_type
*)NULL
);
1149 /* Generate salt used by string_to_key() */
1150 if ((salt
->length
== -1) && (salt
->data
== NULL
)) {
1152 krb5_principal2salt(context
, request
->client
, &defsalt
))) {
1153 krb5_free_sam_challenge_2(context
, sc2
);
1154 krb5_free_sam_challenge_2_body(context
, sc2b
);
1162 /* Get encryption key to be used for checksum and sam_response */
1163 if (!(sc2b
->sam_flags
& KRB5_SAM_USE_SAD_AS_KEY
)) {
1164 /* as_key = string_to_key(password) */
1166 if (as_key
->length
) {
1167 krb5_free_keyblock_contents(context
, as_key
);
1171 /* generate a key using the supplied password */
1172 retval
= krb5_c_string_to_key(context
, sc2b
->sam_etype
,
1173 (krb5_data
*)gak_data
, salt
, as_key
);
1176 krb5_free_sam_challenge_2(context
, sc2
);
1177 krb5_free_sam_challenge_2_body(context
, sc2b
);
1178 if (defsalt
.length
) krb5_xfree(defsalt
.data
);
1182 if (!(sc2b
->sam_flags
& KRB5_SAM_SEND_ENCRYPTED_SAD
)) {
1183 /* as_key = combine_key (as_key, string_to_key(SAD)) */
1184 krb5_keyblock tmp_kb
;
1186 retval
= krb5_c_string_to_key(context
, sc2b
->sam_etype
,
1187 &response_data
, salt
, &tmp_kb
);
1190 krb5_free_sam_challenge_2(context
, sc2
);
1191 krb5_free_sam_challenge_2_body(context
, sc2b
);
1192 if (defsalt
.length
) krb5_xfree(defsalt
.data
);
1196 /* This should be a call to the crypto library some day */
1197 /* key types should already match the sam_etype */
1198 retval
= krb5int_c_combine_keys(context
, as_key
, &tmp_kb
, as_key
);
1201 krb5_free_sam_challenge_2(context
, sc2
);
1202 krb5_free_sam_challenge_2_body(context
, sc2b
);
1203 if (defsalt
.length
) krb5_xfree(defsalt
.data
);
1206 krb5_free_keyblock_contents(context
, &tmp_kb
);
1210 krb5_xfree(defsalt
.data
);
1213 /* as_key = string_to_key(SAD) */
1215 if (as_key
->length
) {
1216 krb5_free_keyblock_contents(context
, as_key
);
1220 /* generate a key using the supplied password */
1221 retval
= krb5_c_string_to_key(context
, sc2b
->sam_etype
,
1222 &response_data
, salt
, as_key
);
1225 krb5_xfree(defsalt
.data
);
1228 krb5_free_sam_challenge_2(context
, sc2
);
1229 krb5_free_sam_challenge_2_body(context
, sc2b
);
1234 /* Now we have a key, verify the checksum on the sam_challenge */
1236 cksum
= sc2
->sam_cksum
;
1239 /* Check this cksum */
1240 retval
= krb5_c_verify_checksum(context
, as_key
,
1241 KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM
,
1242 &sc2
->sam_challenge_2_body
,
1243 *cksum
, &valid_cksum
);
1245 krb5_free_data(context
, scratch
);
1246 krb5_free_sam_challenge_2(context
, sc2
);
1247 krb5_free_sam_challenge_2_body(context
, sc2b
);
1257 /* If KRB5_SAM_SEND_ENCRYPTED_SAD is set, then password is only */
1258 /* source for checksum key. Therefore, a bad checksum means a */
1259 /* bad password. Don't give that direct feedback to someone */
1260 /* trying to brute-force passwords. */
1262 if (!(sc2b
->sam_flags
& KRB5_SAM_SEND_ENCRYPTED_SAD
))
1263 krb5_free_sam_challenge_2(context
, sc2
);
1264 krb5_free_sam_challenge_2_body(context
, sc2b
);
1266 * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications
1267 * can interpret that as "password incorrect", which is probably
1268 * the best error we can return in this situation.
1270 return(KRB5KRB_AP_ERR_BAD_INTEGRITY
);
1273 /* fill in enc_sam_response_enc_2 */
1274 enc_sam_response_enc_2
.magic
= KV5M_ENC_SAM_RESPONSE_ENC_2
;
1275 enc_sam_response_enc_2
.sam_nonce
= sc2b
->sam_nonce
;
1276 if (sc2b
->sam_flags
& KRB5_SAM_SEND_ENCRYPTED_SAD
) {
1277 enc_sam_response_enc_2
.sam_sad
= response_data
;
1279 enc_sam_response_enc_2
.sam_sad
.data
= NULL
;
1280 enc_sam_response_enc_2
.sam_sad
.length
= 0;
1283 /* encode and encrypt enc_sam_response_enc_2 with as_key */
1284 retval
= encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2
,
1287 krb5_free_sam_challenge_2(context
, sc2
);
1288 krb5_free_sam_challenge_2_body(context
, sc2b
);
1292 /* Fill in sam_response_2 */
1293 memset(&sr2
, 0, sizeof(sr2
));
1294 sr2
.sam_type
= sc2b
->sam_type
;
1295 sr2
.sam_flags
= sc2b
->sam_flags
;
1296 sr2
.sam_track_id
= sc2b
->sam_track_id
;
1297 sr2
.sam_nonce
= sc2b
->sam_nonce
;
1299 /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded */
1300 /* enc_sam_response_enc_2 from above */
1302 retval
= krb5_c_encrypt_length(context
, as_key
->enctype
, scratch
->length
,
1305 krb5_free_sam_challenge_2(context
, sc2
);
1306 krb5_free_sam_challenge_2_body(context
, sc2b
);
1309 sr2
.sam_enc_nonce_or_sad
.ciphertext
.length
= ciph_len
;
1311 sr2
.sam_enc_nonce_or_sad
.ciphertext
.data
=
1312 (char *)malloc(sr2
.sam_enc_nonce_or_sad
.ciphertext
.length
);
1314 if (!sr2
.sam_enc_nonce_or_sad
.ciphertext
.data
) {
1315 krb5_free_sam_challenge_2(context
, sc2
);
1316 krb5_free_sam_challenge_2_body(context
, sc2b
);
1320 retval
= krb5_c_encrypt(context
, as_key
, KRB5_KEYUSAGE_PA_SAM_RESPONSE
,
1321 NULL
, scratch
, &sr2
.sam_enc_nonce_or_sad
);
1323 krb5_free_sam_challenge_2(context
, sc2
);
1324 krb5_free_sam_challenge_2_body(context
, sc2b
);
1325 krb5_free_data(context
, scratch
);
1326 krb5_free_data_contents(context
, &sr2
.sam_enc_nonce_or_sad
.ciphertext
);
1329 krb5_free_data(context
, scratch
);
1332 /* Encode the sam_response_2 */
1333 retval
= encode_krb5_sam_response_2(&sr2
, &scratch
);
1334 krb5_free_sam_challenge_2(context
, sc2
);
1335 krb5_free_sam_challenge_2_body(context
, sc2b
);
1336 krb5_free_data_contents(context
, &sr2
.sam_enc_nonce_or_sad
.ciphertext
);
1342 /* Almost there, just need to make padata ! */
1343 sam_padata
= malloc(sizeof(krb5_pa_data
));
1344 if (sam_padata
== NULL
) {
1345 krb5_free_data(context
, scratch
);
1349 sam_padata
->magic
= KV5M_PA_DATA
;
1350 sam_padata
->pa_type
= KRB5_PADATA_SAM_RESPONSE_2
;
1351 sam_padata
->length
= scratch
->length
;
1352 sam_padata
->contents
= (krb5_octet
*) scratch
->data
;
1354 *out_padata
= sam_padata
;
1359 static const pa_types_t pa_types
[] = {
1361 KRB5_PADATA_PW_SALT
,
1366 KRB5_PADATA_AFS3_SALT
,
1371 KRB5_PADATA_ENC_TIMESTAMP
,
1376 KRB5_PADATA_SAM_CHALLENGE_2
,
1381 KRB5_PADATA_SAM_CHALLENGE
,
1393 * If one of the modules can adjust its AS_REQ data using the contents of the
1394 * err_reply, return 0. If it's the sort of correction which requires that we
1395 * ask the user another question, we let the calling application deal with it.
1397 krb5_error_code KRB5_CALLCONV
1398 krb5_do_preauth_tryagain(krb5_context kcontext
,
1399 krb5_kdc_req
*request
,
1400 krb5_data
*encoded_request_body
,
1401 krb5_data
*encoded_previous_request
,
1402 krb5_pa_data
**padata
,
1403 krb5_pa_data
***return_padata
,
1404 krb5_error
*err_reply
,
1405 krb5_data
*salt
, krb5_data
*s2kparams
,
1406 krb5_enctype
*etype
,
1407 krb5_keyblock
*as_key
,
1408 krb5_prompter_fct prompter
, void *prompter_data
,
1409 krb5_gic_get_as_key_fct gak_fct
, void *gak_data
,
1410 krb5_preauth_client_rock
*get_data_rock
,
1411 krb5_gic_opt_ext
*opte
)
1413 krb5_error_code ret
;
1414 krb5_pa_data
**out_padata
;
1415 krb5_preauth_context
*context
;
1416 struct _krb5_preauth_context_module
*module
;
1418 int out_pa_list_size
= 0;
1420 ret
= KRB5KRB_ERR_GENERIC
;
1421 if (kcontext
->preauth_context
== NULL
) {
1422 return KRB5KRB_ERR_GENERIC
;
1424 context
= kcontext
->preauth_context
;
1425 if (context
== NULL
) {
1426 return KRB5KRB_ERR_GENERIC
;
1429 for (i
= 0; padata
[i
] != NULL
&& padata
[i
]->pa_type
!= 0; i
++) {
1431 for (j
= 0; j
< context
->n_modules
; j
++) {
1432 module
= &context
->modules
[j
];
1433 if (module
->pa_type
!= padata
[i
]->pa_type
) {
1436 if (module
->client_tryagain
== NULL
) {
1439 if ((*module
->client_tryagain
)(kcontext
,
1440 module
->plugin_context
,
1441 *module
->request_context_pp
,
1442 (krb5_get_init_creds_opt
*)opte
,
1446 encoded_request_body
,
1447 encoded_previous_request
,
1450 prompter
, prompter_data
,
1451 gak_fct
, gak_data
, salt
, s2kparams
,
1453 &out_padata
) == 0) {
1454 if (out_padata
!= NULL
) {
1456 for (k
= 0; out_padata
[k
] != NULL
; k
++);
1457 grow_pa_list(return_padata
, &out_pa_list_size
,
1468 krb5_error_code KRB5_CALLCONV
1469 krb5_do_preauth(krb5_context context
,
1470 krb5_kdc_req
*request
,
1471 krb5_data
*encoded_request_body
,
1472 krb5_data
*encoded_previous_request
,
1473 krb5_pa_data
**in_padata
, krb5_pa_data
***out_padata
,
1474 krb5_data
*salt
, krb5_data
*s2kparams
,
1475 krb5_enctype
*etype
,
1476 krb5_keyblock
*as_key
,
1477 krb5_prompter_fct prompter
, void *prompter_data
,
1478 krb5_gic_get_as_key_fct gak_fct
, void *gak_data
,
1479 krb5_preauth_client_rock
*get_data_rock
,
1480 krb5_gic_opt_ext
*opte
)
1482 int h
, i
, j
, out_pa_list_size
;
1483 int seen_etype_info2
= 0;
1484 krb5_pa_data
*out_pa
= NULL
, **out_pa_list
= NULL
;
1486 krb5_etype_info etype_info
= NULL
;
1487 krb5_error_code ret
;
1488 static const int paorder
[] = { PA_INFO
, PA_REAL
};
1491 /* Solaris Kerberos */
1492 KRB5_LOG0(KRB5_INFO
, "krb5_do_preauth() start");
1494 if (in_padata
== NULL
) {
1500 /* Solaris Kerberos */
1501 if (salt
&& salt
->data
&& salt
->length
> 0) {
1502 fprintf (stderr
, "salt len=%d", salt
->length
);
1503 if ((int) salt
->length
> 0)
1504 fprintf (stderr
, " '%*s'", salt
->length
, salt
->data
);
1505 fprintf (stderr
, "; preauth data types:");
1506 for (i
= 0; in_padata
[i
]; i
++) {
1507 fprintf (stderr
, " %d", in_padata
[i
]->pa_type
);
1509 fprintf (stderr
, "\n");
1514 out_pa_list_size
= 0;
1516 /* first do all the informational preauths, then the first real one */
1518 for (h
=0; h
<(sizeof(paorder
)/sizeof(paorder
[0])); h
++) {
1520 for (i
=0; in_padata
[i
] && !realdone
; i
++) {
1521 int k
, l
, etype_found
, valid_etype_found
;
1523 * This is really gross, but is necessary to prevent
1524 * lossage when talking to a 1.0.x KDC, which returns an
1525 * erroneous PA-PW-SALT when it returns a KRB-ERROR
1526 * requiring additional preauth.
1528 switch (in_padata
[i
]->pa_type
) {
1529 case KRB5_PADATA_ETYPE_INFO
:
1530 case KRB5_PADATA_ETYPE_INFO2
:
1532 krb5_preauthtype pa_type
= in_padata
[i
]->pa_type
;
1534 if (seen_etype_info2
|| pa_type
!= KRB5_PADATA_ETYPE_INFO2
)
1536 if (pa_type
== KRB5_PADATA_ETYPE_INFO2
) {
1537 krb5_free_etype_info( context
, etype_info
);
1542 scratch
.length
= in_padata
[i
]->length
;
1543 scratch
.data
= (char *) in_padata
[i
]->contents
;
1544 if (pa_type
== KRB5_PADATA_ETYPE_INFO2
) {
1546 ret
= decode_krb5_etype_info2(&scratch
, &etype_info
);
1548 else ret
= decode_krb5_etype_info(&scratch
, &etype_info
);
1550 ret
= 0; /*Ignore error and etype_info element*/
1552 krb5_free_etype_info( context
, etype_info
);
1556 if (etype_info
[0] == NULL
) {
1557 krb5_free_etype_info(context
, etype_info
);
1562 * Select first etype in our request which is also in
1563 * etype-info (preferring client request ktype order).
1565 for (etype_found
= 0, valid_etype_found
= 0, k
= 0;
1566 !etype_found
&& k
< request
->nktypes
; k
++) {
1567 for (l
= 0; etype_info
[l
]; l
++) {
1568 if (etype_info
[l
]->etype
== request
->ktype
[k
]) {
1572 /* check if program has support for this etype for more
1573 * precise error reporting.
1575 if (valid_enctype(etype_info
[l
]->etype
))
1576 valid_etype_found
++;
1580 /* Solaris Kerberos */
1581 KRB5_LOG(KRB5_ERR
, "error !etype_found, "
1582 "valid_etype_found = %d",
1584 if (valid_etype_found
) {
1585 /* supported enctype but not requested */
1586 ret
= KRB5_CONFIG_ETYPE_NOSUPP
;
1590 /* unsupported enctype */
1591 ret
= KRB5_PROG_ETYPE_NOSUPP
;
1596 scratch
.data
= (char *) etype_info
[l
]->salt
;
1597 scratch
.length
= etype_info
[l
]->length
;
1598 krb5_free_data_contents(context
, salt
);
1599 if (scratch
.length
== KRB5_ETYPE_NO_SALT
)
1602 if ((ret
= krb5int_copy_data_contents( context
, &scratch
, salt
)) != 0)
1604 *etype
= etype_info
[l
]->etype
;
1605 krb5_free_data_contents(context
, s2kparams
);
1606 if ((ret
= krb5int_copy_data_contents(context
,
1607 &etype_info
[l
]->s2kparams
,
1611 for (j
= 0; etype_info
[j
]; j
++) {
1612 krb5_etype_info_entry
*e
= etype_info
[j
];
1613 fprintf (stderr
, "etype info %d: etype %d salt len=%d",
1614 j
, e
->etype
, e
->length
);
1615 if (e
->length
> 0 && e
->length
!= KRB5_ETYPE_NO_SALT
)
1616 fprintf (stderr
, " '%.*s'", e
->length
, e
->salt
);
1617 fprintf (stderr
, "\n");
1622 case KRB5_PADATA_PW_SALT
:
1623 case KRB5_PADATA_AFS3_SALT
:
1630 /* Try the internally-provided preauth type list. */
1631 if (!realdone
) for (j
=0; pa_types
[j
].type
>= 0; j
++) {
1632 if ((in_padata
[i
]->pa_type
== pa_types
[j
].type
) &&
1633 (pa_types
[j
].flags
& paorder
[h
])) {
1635 fprintf (stderr
, "calling internal function for pa_type "
1636 "%d, flag %d\n", pa_types
[j
].type
, paorder
[h
]);
1640 if ((ret
= ((*pa_types
[j
].fct
)(context
, request
,
1641 in_padata
[i
], &out_pa
,
1642 salt
, s2kparams
, etype
, as_key
,
1643 prompter
, prompter_data
,
1644 gak_fct
, gak_data
)))) {
1648 ret
= grow_pa_list(&out_pa_list
, &out_pa_list_size
,
1653 if (paorder
[h
] == PA_REAL
)
1658 /* Try to use plugins now. */
1660 krb5_init_preauth_context(context
);
1661 if (context
->preauth_context
!= NULL
) {
1662 int module_ret
, module_flags
;
1664 fprintf (stderr
, "trying modules for pa_type %d, flag %d\n",
1665 in_padata
[i
]->pa_type
, paorder
[h
]);
1667 ret
= krb5_run_preauth_plugins(context
,
1670 encoded_request_body
,
1671 encoded_previous_request
,
1686 if (module_ret
== 0) {
1687 if (paorder
[h
] == PA_REAL
) {
1697 *out_padata
= out_pa_list
;
1699 krb5_free_etype_info(context
, etype_info
);
1701 /* Solaris Kerberos */
1702 KRB5_LOG0(KRB5_INFO
, "krb5_do_preauth() end");
1706 out_pa_list
[out_pa_list_size
++] = NULL
;
1707 krb5_free_pa_data(context
, out_pa_list
);
1710 krb5_free_etype_info(context
, etype_info
);
1712 /* Solaris Kerberos */
1713 KRB5_LOG0(KRB5_INFO
, "krb5_do_preauth() end");