1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 1995, 2003, 2008 by the Massachusetts Institute of Technology. All
6 * Export of this software from the United States of America may
7 * require a specific license from the United States Government.
8 * It is the responsibility of any person or organization contemplating
9 * export to obtain such a license before exporting.
11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12 * distribute this software and its documentation for any purpose and
13 * without fee is hereby granted, provided that the above copyright
14 * notice appear in all copies and that both that copyright notice and
15 * this permission notice appear in supporting documentation, and that
16 * the name of M.I.T. not be used in advertising or publicity pertaining
17 * to distribution of the software without specific, written prior
18 * permission. Furthermore if you modify this software you must label
19 * your software as modified software and not distribute it in such a
20 * fashion that it might be confused with the original M.I.T. software.
21 * M.I.T. makes no representations about the suitability of
22 * this software for any purpose. It is provided "as is" without express
23 * or implied warranty.
28 * This file contains routines for establishing, verifying, and any other
29 * necessary functions, for utilizing the pre-authentication field of the
30 * kerberos kdc request, with various hardware/software verification devices.
35 #include "pkinit_client.h"
36 #include "pkinit_cert_store.h"
37 #endif /* APPLE_PKINIT */
39 #include <krb5/preauth_plugin.h>
40 #include "int-proto.h"
47 /* This structure lets us keep track of all of the modules which are loaded,
48 * turning the list of modules and their lists of implemented preauth types
49 * into a single list which we can walk easily. */
50 struct krb5_preauth_context_st {
52 struct krb5_preauth_context_module_st {
53 /* Which of the possibly more than one preauth types which the
54 * module supports we're using at this point in the list. */
55 krb5_preauthtype pa_type;
56 /* Encryption types which the client claims to support -- we
57 * copy them directly into the krb5_kdc_req structure during
58 * krb5_preauth_prepare_request(). */
59 krb5_enctype *enctypes;
60 /* The plugin's module data and a function to clear it. */
61 krb5_clpreauth_moddata moddata;
62 krb5_clpreauth_fini_fn client_fini;
63 /* The module's table, and some of its members, copied here for
64 * convenience when we populated the list. */
67 krb5_clpreauth_process_fn client_process;
68 krb5_clpreauth_tryagain_fn client_tryagain;
69 krb5_clpreauth_supply_gic_opts_fn client_supply_gic_opts;
70 krb5_clpreauth_request_init_fn client_req_init;
71 krb5_clpreauth_request_fini_fn client_req_fini;
72 /* The per-request context which the client_req_init() function
73 * might allocate, which we'll need to clean up later by
74 * calling the client_req_fini() function. */
75 krb5_clpreauth_modreq modreq;
76 /* A pointer to the request_context pointer. All modules within
77 * a plugin will point at the request_context of the first
78 * module within the plugin. */
79 krb5_clpreauth_modreq *modreq_p;
83 typedef krb5_error_code (*pa_function)(krb5_context,
84 krb5_kdc_req *request,
85 krb5_pa_data *in_padata,
86 krb5_pa_data **out_padata,
87 krb5_data *salt, krb5_data *s2kparams,
89 krb5_keyblock *as_key,
90 krb5_prompter_fct prompter_fct,
92 krb5_gic_get_as_key_fct gak_fct,
95 typedef struct _pa_types_t {
96 krb5_preauthtype type;
101 /* Create the per-krb5_context context. This means loading the modules
102 * if we haven't done that yet (applications which never obtain initial
103 * credentials should never hit this routine), breaking up the module's
104 * list of support pa_types so that we can iterate over the modules more
105 * easily, and copying over the relevant parts of the module's table. */
107 krb5_init_preauth_context(krb5_context kcontext)
109 int n_tables, n_modules, i, count;
110 krb5_plugin_initvt_fn *plugins = NULL, *pl;
111 struct krb5_clpreauth_vtable_st *vtables = NULL, *vt;
112 struct krb5_preauth_context_module_st *mod;
113 krb5_preauth_context *context = NULL;
114 krb5_clpreauth_moddata moddata;
115 krb5_preauthtype pa_type, *pat;
117 krb5_clpreauth_modreq *rcpp;
119 /* Only do this once for each krb5_context */
120 if (kcontext->preauth_context != NULL)
123 /* Auto-register built-in modules. */
124 k5_plugin_register_dyn(kcontext, PLUGIN_INTERFACE_CLPREAUTH, "pkinit",
126 k5_plugin_register(kcontext, PLUGIN_INTERFACE_CLPREAUTH,
127 "encrypted_challenge",
128 clpreauth_encrypted_challenge_initvt);
129 k5_plugin_register(kcontext, PLUGIN_INTERFACE_CLPREAUTH,
130 "encrypted_timestamp",
131 clpreauth_encrypted_timestamp_initvt);
133 /* Get all available clpreauth vtables. */
134 if (k5_plugin_load_all(kcontext, PLUGIN_INTERFACE_CLPREAUTH, &plugins))
136 for (count = 0; plugins[count] != NULL; count++);
137 vtables = calloc(count, sizeof(*vtables));
140 for (pl = plugins, n_tables = 0; *pl != NULL; pl++) {
141 if ((*pl)(kcontext, 1, 1, (krb5_plugin_vtable)&vtables[n_tables]) == 0)
145 /* Count how many modules we ended up loading, and how many preauth
146 * types we may claim to support as a result. */
148 for (i = 0; i < n_tables; i++) {
149 for (count = 0; vtables[i].pa_type_list[count] > 0; count++);
153 /* Allocate the space we need. */
154 context = malloc(sizeof(*context));
157 context->modules = calloc(n_modules, sizeof(*context->modules));
158 if (context->modules == NULL)
161 /* fill in the structure */
163 for (i = 0; i < n_tables; i++) {
165 if ((vt->pa_type_list != NULL) && (vt->process != NULL)) {
167 if (vt->init != NULL && vt->init(kcontext, &moddata) != 0) {
169 fprintf(stderr, "init err, skipping module \"%s\"\n",
176 for (pat = vt->pa_type_list, first = TRUE; *pat > 0;
177 pat++, first = FALSE) {
179 mod = &context->modules[n_modules];
180 mod->pa_type = pa_type;
181 mod->enctypes = vt->enctype_list;
182 mod->moddata = moddata;
183 /* Only call client_fini once per plugin */
185 mod->client_fini = vt->fini;
187 mod->client_fini = NULL;
188 mod->name = vt->name;
189 mod->flags = (*vt->flags)(kcontext, pa_type);
191 mod->client_process = vt->process;
192 mod->client_tryagain = vt->tryagain;
193 mod->client_supply_gic_opts = first ? vt->gic_opts : NULL;
196 * Only call request_init and request_fini once per plugin.
197 * Only the first module within each plugin will ever
198 * have request_context filled in. Every module within
199 * the plugin will have its request_context_pp pointing
200 * to that entry's request_context. That way all the
201 * modules within the plugin share the same request_context
204 mod->client_req_init = vt->request_init;
205 mod->client_req_fini = vt->request_fini;
208 mod->client_req_init = NULL;
209 mod->client_req_fini = NULL;
211 mod->modreq_p = rcpp;
213 fprintf(stderr, "init module \"%s\", pa_type %d, flag %d\n",
214 mod->name, mod->pa_type, mod->flags);
220 context->n_modules = n_modules;
222 /* Place the constructed preauth context into the krb5 context. */
223 kcontext->preauth_context = context;
228 free(context->modules);
230 k5_plugin_free_modules(kcontext, plugins);
234 /* Zero the use counts for the modules herein. Usually used before we
235 * start processing any data from the server, at which point every module
236 * will again be able to take a crack at whatever the server sent. */
238 krb5_clear_preauth_context_use_counts(krb5_context context)
241 if (context->preauth_context != NULL) {
242 for (i = 0; i < context->preauth_context->n_modules; i++) {
243 context->preauth_context->modules[i].use_count = 0;
249 /* Free the per-krb5_context preauth_context. This means clearing any
250 * plugin-specific context which may have been created, and then
251 * freeing the context itself. */
253 krb5_free_preauth_context(krb5_context context)
256 struct krb5_preauth_context_module_st *mod;
258 if (context == NULL || context->preauth_context == NULL)
260 for (i = 0; i < context->preauth_context->n_modules; i++) {
261 mod = &context->preauth_context->modules[i];
262 if (mod->client_fini != NULL)
263 mod->client_fini(context, mod->moddata);
264 zap(mod, sizeof(*mod));
266 free(context->preauth_context->modules);
267 free(context->preauth_context);
268 context->preauth_context = NULL;
271 /* Initialize the per-AS-REQ context. This means calling the client_req_init
272 * function to give the plugin a chance to allocate a per-request context. */
274 krb5_preauth_request_context_init(krb5_context context)
277 struct krb5_preauth_context_module_st *mod;
279 if (context->preauth_context == NULL)
280 krb5_init_preauth_context(context);
281 if (context->preauth_context == NULL)
283 for (i = 0; i < context->preauth_context->n_modules; i++) {
284 mod = &context->preauth_context->modules[i];
285 if (mod->client_req_init != NULL)
286 mod->client_req_init(context, mod->moddata, mod->modreq_p);
290 /* Free the per-AS-REQ context. This means clearing any request-specific
291 * context which the plugin may have created. */
293 krb5_preauth_request_context_fini(krb5_context context)
296 struct krb5_preauth_context_module_st *mod;
298 if (context->preauth_context == NULL)
300 for (i = 0; i < context->preauth_context->n_modules; i++) {
301 mod = &context->preauth_context->modules[i];
302 if (mod->modreq != NULL) {
303 if (mod->client_req_fini != NULL)
304 mod->client_req_fini(context, mod->moddata, mod->modreq);
310 /* Add the named encryption type to the existing list of ktypes. */
312 grow_ktypes(krb5_enctype **out_ktypes, int *out_nktypes, krb5_enctype ktype)
315 krb5_enctype *ktypes;
316 for (i = 0; i < *out_nktypes; i++) {
317 if ((*out_ktypes)[i] == ktype)
320 ktypes = malloc((*out_nktypes + 2) * sizeof(ktype));
322 for (i = 0; i < *out_nktypes; i++)
323 ktypes[i] = (*out_ktypes)[i];
327 *out_ktypes = ktypes;
333 * Add the given list of pa_data items to the existing list of items.
334 * Factored out here to make reading the do_preauth logic easier to read.
337 grow_pa_list(krb5_pa_data ***out_pa_list, int *out_pa_list_size,
338 krb5_pa_data **addition, int num_addition)
340 krb5_pa_data **pa_list;
343 if (out_pa_list == NULL || addition == NULL) {
347 if (*out_pa_list == NULL) {
348 /* Allocate room for the new additions and a NULL terminator. */
349 pa_list = malloc((num_addition + 1) * sizeof(krb5_pa_data *));
352 for (i = 0; i < num_addition; i++)
353 pa_list[i] = addition[i];
355 *out_pa_list = pa_list;
356 *out_pa_list_size = num_addition;
359 * Allocate room for the existing entries plus
360 * the new additions and a NULL terminator.
362 pa_list = malloc((*out_pa_list_size + num_addition + 1)
363 * sizeof(krb5_pa_data *));
366 for (i = 0; i < *out_pa_list_size; i++)
367 pa_list[i] = (*out_pa_list)[i];
368 for (j = 0; j < num_addition;)
369 pa_list[i++] = addition[j++];
372 *out_pa_list = pa_list;
373 *out_pa_list_size = i;
379 get_etype(krb5_context context, krb5_clpreauth_rock rock)
384 static krb5_keyblock *
385 fast_armor(krb5_context context, krb5_clpreauth_rock rock)
387 return rock->fast_state->armor_key;
390 static krb5_error_code
391 get_as_key(krb5_context context, krb5_clpreauth_rock rock,
392 krb5_keyblock **keyblock)
396 if (rock->as_key->length == 0) {
397 ret = (*rock->gak_fct)(context, rock->client, *rock->etype,
398 rock->prompter, rock->prompter_data, rock->salt,
399 rock->s2kparams, rock->as_key, *rock->gak_data);
403 *keyblock = rock->as_key;
407 static krb5_error_code
408 set_as_key(krb5_context context, krb5_clpreauth_rock rock,
409 const krb5_keyblock *keyblock)
411 krb5_free_keyblock_contents(context, rock->as_key);
412 return krb5_copy_keyblock_contents(context, keyblock, rock->as_key);
415 static krb5_error_code
416 get_preauth_time(krb5_context context, krb5_clpreauth_rock rock,
417 krb5_boolean allow_unauth_time, krb5_timestamp *time_out,
418 krb5_int32 *usec_out)
420 if (rock->pa_offset_state != NO_OFFSET &&
421 (allow_unauth_time || rock->pa_offset_state == AUTH_OFFSET) &&
422 (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME)) {
423 /* Use the offset we got from the preauth-required error. */
424 return k5_time_with_offset(rock->pa_offset, rock->pa_offset_usec,
428 /* Use the time offset from the context, or no offset. */
429 return krb5_us_timeofday(context, time_out, usec_out);
433 static struct krb5_clpreauth_callbacks_st callbacks = {
442 /* Tweak the request body, for now adding any enctypes which the module claims
443 * to add support for to the list, but in the future perhaps doing more
444 * involved things. */
446 krb5_preauth_prepare_request(krb5_context kcontext,
447 krb5_gic_opt_ext *opte,
448 krb5_kdc_req *request)
452 if (kcontext->preauth_context == NULL) {
455 /* Add the module-specific enctype list to the request, but only if
456 * it's something we can safely modify. */
457 if (!(opte && (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))) {
458 for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
459 if (kcontext->preauth_context->modules[i].enctypes == NULL)
461 for (j = 0; kcontext->preauth_context->modules[i].enctypes[j] != 0; j++) {
462 grow_ktypes(&request->ktype, &request->nktypes,
463 kcontext->preauth_context->modules[i].enctypes[j]);
469 /* Find the first module which provides for the named preauth type which also
470 * hasn't had a chance to run yet (INFO modules don't count, because as a rule
471 * they don't generate preauth data), and run it. */
472 static krb5_error_code
473 run_preauth_plugins(krb5_context kcontext,
474 int module_required_flags,
475 krb5_kdc_req *request,
476 krb5_data *encoded_request_body,
477 krb5_data *encoded_previous_request,
478 krb5_pa_data *in_padata,
479 krb5_prompter_fct prompter,
481 krb5_clpreauth_rock preauth_rock,
482 krb5_pa_data ***out_pa_list,
483 int *out_pa_list_size,
486 krb5_gic_opt_ext *opte)
489 krb5_pa_data **out_pa_data;
491 struct krb5_preauth_context_module_st *module;
493 if (kcontext->preauth_context == NULL) {
496 /* iterate over all loaded modules */
497 for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
498 module = &kcontext->preauth_context->modules[i];
499 /* skip over those which don't match the preauth type */
500 if (module->pa_type != in_padata->pa_type)
502 /* skip over those which don't match the flags (INFO vs REAL, mainly) */
503 if ((module->flags & module_required_flags) == 0)
505 /* if it's a REAL module, try to call it only once per library call */
506 if (module_required_flags & PA_REAL) {
507 if (module->use_count > 0) {
508 TRACE_PREAUTH_SKIP(kcontext, module->name, module->pa_type);
513 /* run the module's callback function */
516 fprintf(stderr, "using module \"%s\" (%d), flags = %d\n",
517 module->name, module->pa_type, module->flags);
519 ret = module->client_process(kcontext, module->moddata,
521 (krb5_get_init_creds_opt *)opte,
522 &callbacks, preauth_rock,
523 request, encoded_request_body,
524 encoded_previous_request, in_padata,
525 prompter, prompter_data, &out_pa_data);
526 TRACE_PREAUTH_PROCESS(kcontext, module->name, module->pa_type,
528 /* Make note of the module's flags and status. */
529 *module_flags = module->flags;
531 /* Save the new preauth data item. */
532 if (out_pa_data != NULL) {
534 for (j = 0; out_pa_data[j] != NULL; j++);
535 ret = grow_pa_list(out_pa_list, out_pa_list_size, out_pa_data, j);
542 if (i >= kcontext->preauth_context->n_modules) {
548 static inline krb5_data
549 padata2data(krb5_pa_data p)
554 d.data = (char *) p.contents;
558 static krb5_error_code
559 pa_salt(krb5_context context, krb5_kdc_req *request, krb5_pa_data *in_padata,
560 krb5_pa_data **out_padata, krb5_data *salt, krb5_data *s2kparams,
561 krb5_enctype *etype, krb5_keyblock *as_key, krb5_prompter_fct prompter,
562 void *prompter_data, krb5_gic_get_as_key_fct gak_fct, void *gak_data)
565 krb5_error_code retval;
567 tmp = padata2data(*in_padata);
568 krb5_free_data_contents(context, salt);
569 retval = krb5int_copy_data_contents(context, &tmp, salt);
573 TRACE_PREAUTH_SALT(context, salt, in_padata->pa_type);
574 if (in_padata->pa_type == KRB5_PADATA_AFS3_SALT)
575 salt->length = SALT_TYPE_AFS_LENGTH;
580 static krb5_error_code
581 pa_fx_cookie(krb5_context context, krb5_kdc_req *request,
582 krb5_pa_data *in_padata, krb5_pa_data **out_padata,
583 krb5_data *salt, krb5_data *s2kparams, krb5_enctype *etype,
584 krb5_keyblock *as_key, krb5_prompter_fct prompter,
585 void *prompter_data, krb5_gic_get_as_key_fct gak_fct,
588 krb5_pa_data *pa = calloc(1, sizeof(krb5_pa_data));
589 krb5_octet *contents;
591 TRACE_PREAUTH_COOKIE(context, in_padata->length, in_padata->contents);
594 contents = malloc(in_padata->length);
595 if (contents == NULL) {
600 pa->contents = contents;
601 memcpy(contents, in_padata->contents, pa->length);
608 * PKINIT. One function to generate AS-REQ, one to parse AS-REP
610 #define PKINIT_DEBUG 0
612 #define kdcPkinitDebug(args...) printf(args)
614 #define kdcPkinitDebug(args...)
617 static krb5_error_code
618 pa_pkinit_gen_req(krb5_context context,
619 krb5_kdc_req *request,
620 krb5_pa_data *in_padata,
621 krb5_pa_data **out_padata,
623 krb5_data *s2kparams,
625 krb5_keyblock *as_key,
626 krb5_prompter_fct prompter,
628 krb5_gic_get_as_key_fct gak_fct,
631 krb5_error_code krtn;
632 krb5_data out_data = {0, 0, NULL};
633 krb5_timestamp kctime = 0;
634 krb5_int32 cusec = 0;
637 krb5_pkinit_signing_cert_t client_cert;
638 krb5_data *der_req = NULL;
639 char *client_principal = NULL;
640 char *server_principal = NULL;
641 unsigned char nonce_bytes[4];
642 krb5_data nonce_data = {0, 4, (char *)nonce_bytes};
646 * Trusted CA list and specific KC cert optionally obtained via
647 * krb5_pkinit_get_server_certs(). All are DER-encoded certs.
649 krb5_data *trusted_CAs = NULL;
650 krb5_ui_4 num_trusted_CAs;
651 krb5_data kdc_cert = {0};
653 kdcPkinitDebug("pa_pkinit_gen_req\n");
655 /* If we don't have a client cert, we're done */
656 if(request->client == NULL) {
657 kdcPkinitDebug("No request->client; aborting PKINIT\n");
658 return KRB5KDC_ERR_PREAUTH_FAILED;
660 krtn = krb5_unparse_name(context, request->client, &client_principal);
664 krtn = krb5_pkinit_get_client_cert(client_principal, &client_cert);
665 free(client_principal);
667 kdcPkinitDebug("No client cert; aborting PKINIT\n");
671 /* optional platform-dependent CA list and KDC cert */
672 krtn = krb5_unparse_name(context, request->server, &server_principal);
676 krtn = krb5_pkinit_get_server_certs(client_principal, server_principal,
677 &trusted_CAs, &num_trusted_CAs, &kdc_cert);
682 /* checksum of the encoded KDC-REQ-BODY */
683 krtn = encode_krb5_kdc_req_body(request, &der_req);
685 kdcPkinitDebug("encode_krb5_kdc_req_body returned %d\n", (int)krtn);
688 krtn = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0, der_req, &cksum);
693 krtn = krb5_us_timeofday(context, &kctime, &cusec);
698 /* cook up a random 4-byte nonce */
699 krtn = krb5_c_random_make_octets(context, &nonce_data);
703 for(dex=0; dex<4; dex++) {
705 nonce |= nonce_bytes[dex];
708 krtn = krb5int_pkinit_as_req_create(context,
709 kctime, cusec, nonce, &cksum,
711 trusted_CAs, num_trusted_CAs,
712 (kdc_cert.data ? &kdc_cert : NULL),
715 kdcPkinitDebug("error %d on pkinit_as_req_create; aborting PKINIT\n", (int)krtn);
718 *out_padata = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
719 if(*out_padata == NULL) {
724 (*out_padata)->magic = KV5M_PA_DATA;
725 (*out_padata)->pa_type = KRB5_PADATA_PK_AS_REQ;
726 (*out_padata)->length = out_data.length;
727 (*out_padata)->contents = (krb5_octet *)out_data.data;
731 krb5_pkinit_release_cert(client_cert);
734 free(cksum.contents);
737 krb5_free_data(context, der_req);
739 if(server_principal) {
740 free(server_principal);
742 /* free data mallocd by krb5_pkinit_get_server_certs() */
745 for(udex=0; udex<num_trusted_CAs; udex++) {
746 free(trusted_CAs[udex].data);
757 /* If and only if the realm is that of a Local KDC, accept
758 * the KDC certificate as valid if its hash matches the
762 local_kdc_cert_match(krb5_context context,
763 krb5_data *signer_cert,
764 krb5_principal client)
766 static const char lkdcprefix[] = "LKDC:SHA1.";
767 krb5_boolean match = FALSE;
768 size_t cert_hash_len;
770 const char *realm_hash;
771 size_t realm_hash_len;
773 if (client->realm.length <= sizeof(lkdcprefix) ||
774 0 != memcmp(lkdcprefix, client->realm.data, sizeof(lkdcprefix)-1))
776 realm_hash = &client->realm.data[sizeof(lkdcprefix)-1];
777 realm_hash_len = client->realm.length - sizeof(lkdcprefix) + 1;
778 kdcPkinitDebug("checking realm versus certificate hash\n");
779 if (NULL != (cert_hash = krb5_pkinit_cert_hash_str(signer_cert))) {
780 kdcPkinitDebug("hash = %s\n", cert_hash);
781 cert_hash_len = strlen(cert_hash);
782 if (cert_hash_len == realm_hash_len &&
783 0 == memcmp(cert_hash, realm_hash, cert_hash_len))
787 kdcPkinitDebug("result: %s\n", match ? "matches" : "does not match");
791 static krb5_error_code
792 pa_pkinit_parse_rep(krb5_context context,
793 krb5_kdc_req *request,
794 krb5_pa_data *in_padata,
795 krb5_pa_data **out_padata,
797 krb5_data *s2kparams,
799 krb5_keyblock *as_key,
800 krb5_prompter_fct prompter,
802 krb5_gic_get_as_key_fct gak_fct,
805 krb5int_cert_sig_status sig_status = (krb5int_cert_sig_status)-999;
806 krb5_error_code krtn;
808 krb5_keyblock local_key = {0};
809 krb5_pkinit_signing_cert_t client_cert;
810 char *princ_name = NULL;
811 krb5_checksum as_req_checksum_rcd = {0}; /* received checksum */
812 krb5_checksum as_req_checksum_gen = {0}; /* calculated checksum */
813 krb5_data *encoded_as_req = NULL;
814 krb5_data signer_cert = {0};
817 kdcPkinitDebug("pa_pkinit_parse_rep\n");
818 if((in_padata == NULL) || (in_padata->length== 0)) {
819 kdcPkinitDebug("pa_pkinit_parse_rep: no in_padata\n");
820 return KRB5KDC_ERR_PREAUTH_FAILED;
823 /* If we don't have a client cert, we're done */
824 if(request->client == NULL) {
825 kdcPkinitDebug("No request->client; aborting PKINIT\n");
826 return KRB5KDC_ERR_PREAUTH_FAILED;
828 krtn = krb5_unparse_name(context, request->client, &princ_name);
832 krtn = krb5_pkinit_get_client_cert(princ_name, &client_cert);
835 kdcPkinitDebug("No client cert; aborting PKINIT\n");
839 memset(&local_key, 0, sizeof(local_key));
840 asRep.data = (char *)in_padata->contents;
841 asRep.length = in_padata->length;
842 krtn = krb5int_pkinit_as_rep_parse(context, &asRep, client_cert,
843 &local_key, &as_req_checksum_rcd, &sig_status,
844 &signer_cert, NULL, NULL);
846 kdcPkinitDebug("pkinit_as_rep_parse returned %d\n", (int)krtn);
852 case pki_cs_unknown_root:
853 if (local_kdc_cert_match(context, &signer_cert, request->client))
857 kdcPkinitDebug("pa_pkinit_parse_rep: bad cert/sig status %d\n",
859 krtn = KRB5KDC_ERR_PREAUTH_FAILED;
863 /* calculate checksum of incoming AS-REQ using the decryption key
864 * we just got from the ReplyKeyPack */
865 krtn = encode_krb5_as_req(request, &encoded_as_req);
869 krtn = krb5_c_make_checksum(context, context->kdc_req_sumtype,
870 &local_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
871 encoded_as_req, &as_req_checksum_gen);
875 if((as_req_checksum_gen.length != as_req_checksum_rcd.length) ||
876 memcmp(as_req_checksum_gen.contents,
877 as_req_checksum_rcd.contents,
878 as_req_checksum_gen.length)) {
879 kdcPkinitDebug("pa_pkinit_parse_rep: checksum miscompare\n");
880 krtn = KRB5KDC_ERR_PREAUTH_FAILED;
884 /* We have the key; transfer to caller */
885 if (as_key->length) {
886 krb5_free_keyblock_contents(context, as_key);
891 fprintf(stderr, "pa_pkinit_parse_rep: SUCCESS\n");
892 fprintf(stderr, "enctype %d keylen %d keydata %02x %02x %02x %02x...\n",
893 (int)as_key->enctype, (int)as_key->length,
894 as_key->contents[0], as_key->contents[1],
895 as_key->contents[2], as_key->contents[3]);
901 if (signer_cert.data) {
902 free(signer_cert.data);
904 if(as_req_checksum_rcd.contents) {
905 free(as_req_checksum_rcd.contents);
907 if(as_req_checksum_gen.contents) {
908 free(as_req_checksum_gen.contents);
911 krb5_free_data(context, encoded_as_req);
913 if(krtn && (local_key.contents != NULL)) {
914 krb5_free_keyblock_contents(context, &local_key);
918 #endif /* APPLE_PKINIT */
920 /* this macro expands to the int,ptr necessary for "%.*s" in an sprintf */
922 #define SAMDATA(kdata, str, maxsize) \
923 (int)((kdata.length)? \
924 ((((kdata.length)<=(maxsize))?(kdata.length):strlen(str))): \
927 ((((kdata.length)<=(maxsize))?(kdata.data):(str))):(str)
929 sam_challenge_banner(krb5_int32 sam_type)
934 case PA_SAM_TYPE_ENIGMA: /* Enigma Logic */
935 label = _("Challenge for Enigma Logic mechanism");
937 case PA_SAM_TYPE_DIGI_PATH: /* Digital Pathways */
938 case PA_SAM_TYPE_DIGI_PATH_HEX: /* Digital Pathways */
939 label = _("Challenge for Digital Pathways mechanism");
941 case PA_SAM_TYPE_ACTIVCARD_DEC: /* Digital Pathways */
942 case PA_SAM_TYPE_ACTIVCARD_HEX: /* Digital Pathways */
943 label = _("Challenge for Activcard mechanism");
945 case PA_SAM_TYPE_SKEY_K0: /* S/key where KDC has key 0 */
946 label = _("Challenge for Enhanced S/Key mechanism");
948 case PA_SAM_TYPE_SKEY: /* Traditional S/Key */
949 label = _("Challenge for Traditional S/Key mechanism");
951 case PA_SAM_TYPE_SECURID: /* Security Dynamics */
952 label = _("Challenge for Security Dynamics mechanism");
954 case PA_SAM_TYPE_SECURID_PREDICT: /* predictive Security Dynamics */
955 label = _("Challenge for Security Dynamics mechanism");
958 label = _("Challenge from authentication server");
965 static krb5_error_code
966 pa_sam_2(krb5_context context, krb5_kdc_req *request, krb5_pa_data *in_padata,
967 krb5_pa_data **out_padata, krb5_data *salt, krb5_data *s2kparams,
968 krb5_enctype *etype, krb5_keyblock *as_key,
969 krb5_prompter_fct prompter, void *prompter_data,
970 krb5_gic_get_as_key_fct gak_fct, void *gak_data)
972 krb5_error_code retval;
973 krb5_sam_challenge_2 *sc2 = NULL;
974 krb5_sam_challenge_2_body *sc2b = NULL;
976 krb5_data response_data;
977 char name[100], banner[100], prompt[100], response[100];
979 krb5_prompt_type prompt_type;
981 krb5_checksum **cksum;
982 krb5_data *scratch = NULL;
983 krb5_boolean valid_cksum = 0;
984 krb5_enc_sam_response_enc_2 enc_sam_response_enc_2;
985 krb5_sam_response_2 sr2;
987 krb5_pa_data *sam_padata;
989 if (prompter == NULL)
990 return KRB5_LIBOS_CANTREADPWD;
992 tmp_data.length = in_padata->length;
993 tmp_data.data = (char *)in_padata->contents;
995 if ((retval = decode_krb5_sam_challenge_2(&tmp_data, &sc2)))
998 retval = decode_krb5_sam_challenge_2_body(&sc2->sam_challenge_2_body, &sc2b);
1001 krb5_free_sam_challenge_2(context, sc2);
1005 if (!sc2->sam_cksum || ! *sc2->sam_cksum) {
1006 krb5_free_sam_challenge_2(context, sc2);
1007 krb5_free_sam_challenge_2_body(context, sc2b);
1008 return(KRB5_SAM_NO_CHECKSUM);
1011 if (sc2b->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
1012 krb5_free_sam_challenge_2(context, sc2);
1013 krb5_free_sam_challenge_2_body(context, sc2b);
1014 return(KRB5_SAM_UNSUPPORTED);
1017 if (!krb5_c_valid_enctype(sc2b->sam_etype)) {
1018 krb5_free_sam_challenge_2(context, sc2);
1019 krb5_free_sam_challenge_2_body(context, sc2b);
1020 return(KRB5_SAM_INVALID_ETYPE);
1023 /* All of the above error checks are KDC-specific, that is, they */
1024 /* assume a failure in the KDC reply. By returning anything other */
1025 /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED, */
1026 /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will */
1027 /* most likely go on to try the AS_REQ against master KDC */
1029 if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
1030 /* We will need the password to obtain the key used for */
1031 /* the checksum, and encryption of the sam_response. */
1032 /* Go ahead and get it now, preserving the ordering of */
1033 /* prompts for the user. */
1035 retval = (gak_fct)(context, request->client,
1036 sc2b->sam_etype, prompter,
1037 prompter_data, salt, s2kparams, as_key, gak_data);
1039 krb5_free_sam_challenge_2(context, sc2);
1040 krb5_free_sam_challenge_2_body(context, sc2b);
1045 snprintf(name, sizeof(name), "%.*s",
1046 SAMDATA(sc2b->sam_type_name, _("SAM Authentication"),
1049 snprintf(banner, sizeof(banner), "%.*s",
1050 SAMDATA(sc2b->sam_challenge_label,
1051 sam_challenge_banner(sc2b->sam_type),
1054 snprintf(prompt, sizeof(prompt), "%s%.*s%s%.*s",
1055 sc2b->sam_challenge.length?"Challenge is [":"",
1056 SAMDATA(sc2b->sam_challenge, "", 20),
1057 sc2b->sam_challenge.length?"], ":"",
1058 SAMDATA(sc2b->sam_response_prompt, "passcode", 55));
1060 response_data.data = response;
1061 response_data.length = sizeof(response);
1062 kprompt.prompt = prompt;
1064 kprompt.reply = &response_data;
1066 prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
1067 krb5int_set_prompt_types(context, &prompt_type);
1069 if ((retval = ((*prompter)(context, prompter_data, name,
1070 banner, 1, &kprompt)))) {
1071 krb5_free_sam_challenge_2(context, sc2);
1072 krb5_free_sam_challenge_2_body(context, sc2b);
1073 krb5int_set_prompt_types(context, 0);
1077 krb5int_set_prompt_types(context, (krb5_prompt_type *)NULL);
1079 /* Generate salt used by string_to_key() */
1080 if (((int) salt->length == -1) && (salt->data == NULL)) {
1082 krb5_principal2salt(context, request->client, &defsalt))) {
1083 krb5_free_sam_challenge_2(context, sc2);
1084 krb5_free_sam_challenge_2_body(context, sc2b);
1092 /* Get encryption key to be used for checksum and sam_response */
1093 if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
1094 /* as_key = string_to_key(password) */
1096 if (as_key->length) {
1097 krb5_free_keyblock_contents(context, as_key);
1101 /* generate a key using the supplied password */
1102 retval = krb5_c_string_to_key(context, sc2b->sam_etype,
1103 (krb5_data *)gak_data, salt, as_key);
1106 krb5_free_sam_challenge_2(context, sc2);
1107 krb5_free_sam_challenge_2_body(context, sc2b);
1108 if (defsalt.length) free(defsalt.data);
1112 if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD)) {
1113 /* as_key = combine_key (as_key, string_to_key(SAD)) */
1114 krb5_keyblock tmp_kb;
1116 retval = krb5_c_string_to_key(context, sc2b->sam_etype,
1117 &response_data, salt, &tmp_kb);
1120 krb5_free_sam_challenge_2(context, sc2);
1121 krb5_free_sam_challenge_2_body(context, sc2b);
1122 if (defsalt.length) free(defsalt.data);
1126 /* This should be a call to the crypto library some day */
1127 /* key types should already match the sam_etype */
1128 retval = krb5int_c_combine_keys(context, as_key, &tmp_kb, as_key);
1131 krb5_free_sam_challenge_2(context, sc2);
1132 krb5_free_sam_challenge_2_body(context, sc2b);
1133 if (defsalt.length) free(defsalt.data);
1136 krb5_free_keyblock_contents(context, &tmp_kb);
1143 /* as_key = string_to_key(SAD) */
1145 if (as_key->length) {
1146 krb5_free_keyblock_contents(context, as_key);
1150 /* generate a key using the supplied password */
1151 retval = krb5_c_string_to_key(context, sc2b->sam_etype,
1152 &response_data, salt, as_key);
1158 krb5_free_sam_challenge_2(context, sc2);
1159 krb5_free_sam_challenge_2_body(context, sc2b);
1164 /* Now we have a key, verify the checksum on the sam_challenge */
1166 cksum = sc2->sam_cksum;
1168 for (; *cksum; cksum++) {
1169 if (!krb5_c_is_keyed_cksum((*cksum)->checksum_type))
1171 /* Check this cksum */
1172 retval = krb5_c_verify_checksum(context, as_key,
1173 KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
1174 &sc2->sam_challenge_2_body,
1175 *cksum, &valid_cksum);
1177 krb5_free_data(context, scratch);
1178 krb5_free_sam_challenge_2(context, sc2);
1179 krb5_free_sam_challenge_2_body(context, sc2b);
1187 krb5_free_sam_challenge_2(context, sc2);
1188 krb5_free_sam_challenge_2_body(context, sc2b);
1190 * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications
1191 * can interpret that as "password incorrect", which is probably
1192 * the best error we can return in this situation.
1194 return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
1197 /* fill in enc_sam_response_enc_2 */
1198 enc_sam_response_enc_2.magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
1199 enc_sam_response_enc_2.sam_nonce = sc2b->sam_nonce;
1200 if (sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
1201 enc_sam_response_enc_2.sam_sad = response_data;
1203 enc_sam_response_enc_2.sam_sad.data = NULL;
1204 enc_sam_response_enc_2.sam_sad.length = 0;
1207 /* encode and encrypt enc_sam_response_enc_2 with as_key */
1208 retval = encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2,
1211 krb5_free_sam_challenge_2(context, sc2);
1212 krb5_free_sam_challenge_2_body(context, sc2b);
1216 /* Fill in sam_response_2 */
1217 memset(&sr2, 0, sizeof(sr2));
1218 sr2.sam_type = sc2b->sam_type;
1219 sr2.sam_flags = sc2b->sam_flags;
1220 sr2.sam_track_id = sc2b->sam_track_id;
1221 sr2.sam_nonce = sc2b->sam_nonce;
1223 /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded */
1224 /* enc_sam_response_enc_2 from above */
1226 retval = krb5_c_encrypt_length(context, as_key->enctype, scratch->length,
1229 krb5_free_sam_challenge_2(context, sc2);
1230 krb5_free_sam_challenge_2_body(context, sc2b);
1231 krb5_free_data(context, scratch);
1234 sr2.sam_enc_nonce_or_sad.ciphertext.length = ciph_len;
1236 sr2.sam_enc_nonce_or_sad.ciphertext.data =
1237 (char *)malloc(sr2.sam_enc_nonce_or_sad.ciphertext.length);
1239 if (!sr2.sam_enc_nonce_or_sad.ciphertext.data) {
1240 krb5_free_sam_challenge_2(context, sc2);
1241 krb5_free_sam_challenge_2_body(context, sc2b);
1242 krb5_free_data(context, scratch);
1246 retval = krb5_c_encrypt(context, as_key, KRB5_KEYUSAGE_PA_SAM_RESPONSE,
1247 NULL, scratch, &sr2.sam_enc_nonce_or_sad);
1249 krb5_free_sam_challenge_2(context, sc2);
1250 krb5_free_sam_challenge_2_body(context, sc2b);
1251 krb5_free_data(context, scratch);
1252 krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
1255 krb5_free_data(context, scratch);
1258 /* Encode the sam_response_2 */
1259 retval = encode_krb5_sam_response_2(&sr2, &scratch);
1260 krb5_free_sam_challenge_2(context, sc2);
1261 krb5_free_sam_challenge_2_body(context, sc2b);
1262 krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
1268 /* Almost there, just need to make padata ! */
1269 sam_padata = malloc(sizeof(krb5_pa_data));
1270 if (sam_padata == NULL) {
1271 krb5_free_data(context, scratch);
1275 sam_padata->magic = KV5M_PA_DATA;
1276 sam_padata->pa_type = KRB5_PADATA_SAM_RESPONSE_2;
1277 sam_padata->length = scratch->length;
1278 sam_padata->contents = (krb5_octet *) scratch->data;
1281 *out_padata = sam_padata;
1286 static krb5_error_code
1287 pa_s4u_x509_user(krb5_context context, krb5_kdc_req *request,
1288 krb5_pa_data *in_padata, krb5_pa_data **out_padata,
1289 krb5_data *salt, krb5_data *s2kparams, krb5_enctype *etype,
1290 krb5_keyblock *as_key, krb5_prompter_fct prompter,
1291 void *prompter_data, krb5_gic_get_as_key_fct gak_fct,
1294 krb5_s4u_userid *userid = (krb5_s4u_userid *)gak_data; /* XXX private contract */
1295 krb5_pa_data *s4u_padata;
1296 krb5_error_code code;
1297 krb5_principal client;
1304 code = krb5_copy_principal(context, request->client, &client);
1308 if (userid->user != NULL)
1309 krb5_free_principal(context, userid->user);
1310 userid->user = client;
1312 if (userid->subject_cert.length != 0) {
1313 s4u_padata = malloc(sizeof(*s4u_padata));
1314 if (s4u_padata == NULL)
1317 s4u_padata->magic = KV5M_PA_DATA;
1318 s4u_padata->pa_type = KRB5_PADATA_S4U_X509_USER;
1319 s4u_padata->contents = malloc(userid->subject_cert.length);
1320 if (s4u_padata->contents == NULL) {
1324 memcpy(s4u_padata->contents, userid->subject_cert.data, userid->subject_cert.length);
1325 s4u_padata->length = userid->subject_cert.length;
1327 *out_padata = s4u_padata;
1333 /* FIXME - order significant? */
1334 static const pa_types_t pa_types[] = {
1336 KRB5_PADATA_PW_SALT,
1341 KRB5_PADATA_AFS3_SALT,
1347 KRB5_PADATA_PK_AS_REQ,
1352 KRB5_PADATA_PK_AS_REP,
1353 pa_pkinit_parse_rep,
1356 #endif /* APPLE_PKINIT */
1358 KRB5_PADATA_SAM_CHALLENGE_2,
1363 KRB5_PADATA_FX_COOKIE,
1368 KRB5_PADATA_S4U_X509_USER,
1380 * If one of the modules can adjust its AS_REQ data using the contents of the
1381 * err_reply, return 0. If it's the sort of correction which requires that we
1382 * ask the user another question, we let the calling application deal with it.
1384 krb5_error_code KRB5_CALLCONV
1385 krb5_do_preauth_tryagain(krb5_context kcontext,
1386 krb5_kdc_req *request,
1387 krb5_data *encoded_request_body,
1388 krb5_data *encoded_previous_request,
1389 krb5_pa_data **padata,
1390 krb5_pa_data ***return_padata,
1391 krb5_error *err_reply,
1392 krb5_pa_data **err_padata,
1393 krb5_prompter_fct prompter, void *prompter_data,
1394 krb5_clpreauth_rock preauth_rock,
1395 krb5_gic_opt_ext *opte)
1397 krb5_error_code ret;
1398 krb5_pa_data **out_padata;
1399 krb5_preauth_context *context;
1400 struct krb5_preauth_context_module_st *module;
1402 int out_pa_list_size = 0;
1404 ret = KRB5KRB_ERR_GENERIC;
1405 if (kcontext->preauth_context == NULL) {
1406 return KRB5KRB_ERR_GENERIC;
1408 context = kcontext->preauth_context;
1409 if (context == NULL) {
1410 return KRB5KRB_ERR_GENERIC;
1413 TRACE_PREAUTH_TRYAGAIN_INPUT(kcontext, padata);
1415 for (i = 0; padata[i] != NULL && padata[i]->pa_type != 0; i++) {
1417 for (j = 0; j < context->n_modules; j++) {
1418 module = &context->modules[j];
1419 if (module->pa_type != padata[i]->pa_type) {
1422 if (module->client_tryagain == NULL) {
1425 if ((*module->client_tryagain)(kcontext, module->moddata,
1427 (krb5_get_init_creds_opt *)opte,
1428 &callbacks, preauth_rock,
1430 encoded_request_body,
1431 encoded_previous_request,
1433 err_reply, err_padata,
1434 prompter, prompter_data,
1435 &out_padata) == 0) {
1436 if (out_padata != NULL) {
1438 for (k = 0; out_padata[k] != NULL; k++);
1439 grow_pa_list(return_padata, &out_pa_list_size,
1442 TRACE_PREAUTH_TRYAGAIN_OUTPUT(kcontext, *return_padata);
1451 krb5_error_code KRB5_CALLCONV
1452 krb5_do_preauth(krb5_context context, krb5_kdc_req *request,
1453 krb5_data *encoded_request_body,
1454 krb5_data *encoded_previous_request,
1455 krb5_pa_data **in_padata, krb5_pa_data ***out_padata,
1456 krb5_prompter_fct prompter, void *prompter_data,
1457 krb5_clpreauth_rock rock, krb5_gic_opt_ext *opte,
1458 krb5_boolean *got_real_out)
1461 int i, j, out_pa_list_size;
1462 int seen_etype_info2 = 0;
1463 krb5_pa_data *out_pa = NULL, **out_pa_list = NULL;
1465 krb5_etype_info etype_info = NULL;
1466 krb5_error_code ret;
1467 static const int paorder[] = { PA_INFO, PA_REAL };
1470 *got_real_out = FALSE;
1472 if (in_padata == NULL) {
1477 TRACE_PREAUTH_INPUT(context, in_padata);
1480 out_pa_list_size = 0;
1482 /* first do all the informational preauths, then the first real one */
1484 for (h=0; h<(sizeof(paorder)/sizeof(paorder[0])); h++) {
1486 for (i=0; in_padata[i] && !realdone; i++) {
1487 int k, l, etype_found, valid_etype_found;
1489 * This is really gross, but is necessary to prevent
1490 * lossage when talking to a 1.0.x KDC, which returns an
1491 * erroneous PA-PW-SALT when it returns a KRB-ERROR
1492 * requiring additional preauth.
1494 switch (in_padata[i]->pa_type) {
1495 case KRB5_PADATA_ETYPE_INFO:
1496 case KRB5_PADATA_ETYPE_INFO2:
1498 krb5_preauthtype pa_type = in_padata[i]->pa_type;
1500 if (seen_etype_info2 || pa_type != KRB5_PADATA_ETYPE_INFO2)
1502 if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
1503 krb5_free_etype_info( context, etype_info);
1508 scratch.length = in_padata[i]->length;
1509 scratch.data = (char *) in_padata[i]->contents;
1510 if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
1512 ret = decode_krb5_etype_info2(&scratch, &etype_info);
1514 else ret = decode_krb5_etype_info(&scratch, &etype_info);
1516 ret = 0; /*Ignore error and etype_info element*/
1518 krb5_free_etype_info( context, etype_info);
1522 if (etype_info[0] == NULL) {
1523 krb5_free_etype_info(context, etype_info);
1528 * Select first etype in our request which is also in
1529 * etype-info (preferring client request ktype order).
1531 for (etype_found = 0, valid_etype_found = 0, k = 0;
1532 !etype_found && k < request->nktypes; k++) {
1533 for (l = 0; etype_info[l]; l++) {
1534 if (etype_info[l]->etype == request->ktype[k]) {
1538 /* check if program has support for this etype for more
1539 * precise error reporting.
1541 if (krb5_c_valid_enctype(etype_info[l]->etype))
1542 valid_etype_found++;
1546 if (valid_etype_found) {
1547 /* supported enctype but not requested */
1548 ret = KRB5_CONFIG_ETYPE_NOSUPP;
1552 /* unsupported enctype */
1553 ret = KRB5_PROG_ETYPE_NOSUPP;
1558 scratch.data = (char *) etype_info[l]->salt;
1559 scratch.length = etype_info[l]->length;
1560 krb5_free_data_contents(context, rock->salt);
1561 if (scratch.length == KRB5_ETYPE_NO_SALT)
1562 rock->salt->data = NULL;
1564 ret = krb5int_copy_data_contents(context, &scratch,
1569 *rock->etype = etype_info[l]->etype;
1570 krb5_free_data_contents(context, rock->s2kparams);
1571 ret = krb5int_copy_data_contents(context,
1572 &etype_info[l]->s2kparams,
1576 TRACE_PREAUTH_ETYPE_INFO(context, *rock->etype, rock->salt,
1580 case KRB5_PADATA_PW_SALT:
1581 case KRB5_PADATA_AFS3_SALT:
1588 /* Try the internally-provided preauth type list. */
1589 if (!realdone) for (j=0; pa_types[j].type >= 0; j++) {
1590 if ((in_padata[i]->pa_type == pa_types[j].type) &&
1591 (pa_types[j].flags & paorder[h])) {
1593 fprintf (stderr, "calling internal function for pa_type "
1594 "%d, flag %d\n", pa_types[j].type, paorder[h]);
1598 ret = pa_types[j].fct(context, request, in_padata[i],
1599 &out_pa, rock->salt,
1600 rock->s2kparams, rock->etype,
1601 rock->as_key, prompter,
1602 prompter_data, *rock->gak_fct,
1605 if (paorder[h] == PA_INFO) {
1606 TRACE_PREAUTH_INFO_FAIL(context,
1607 in_padata[i]->pa_type,
1610 continue; /* PA_INFO type failed, ignore */
1616 ret = grow_pa_list(&out_pa_list, &out_pa_list_size,
1621 if (paorder[h] == PA_REAL)
1626 /* Try to use plugins now. */
1628 krb5_init_preauth_context(context);
1629 if (context->preauth_context != NULL) {
1630 int module_ret = 0, module_flags;
1632 fprintf (stderr, "trying modules for pa_type %d, flag %d\n",
1633 in_padata[i]->pa_type, paorder[h]);
1635 ret = run_preauth_plugins(context,
1638 encoded_request_body,
1639 encoded_previous_request,
1650 if (module_ret == 0) {
1651 if (paorder[h] == PA_REAL) {
1661 TRACE_PREAUTH_OUTPUT(context, out_pa_list);
1662 *out_padata = out_pa_list;
1664 krb5_free_etype_info(context, etype_info);
1666 *got_real_out = realdone;
1670 out_pa_list[out_pa_list_size++] = NULL;
1671 krb5_free_pa_data(context, out_pa_list);
1674 krb5_free_etype_info(context, etype_info);
1679 * Give all the preauth plugins a look at the preauth option which
1683 krb5_preauth_supply_preauth_data(krb5_context context, krb5_gic_opt_ext *opte,
1684 const char *attr, const char *value)
1686 krb5_error_code retval = 0;
1688 struct krb5_preauth_context_module_st *mod;
1689 const char *emsg = NULL;
1691 if (context->preauth_context == NULL)
1692 krb5_init_preauth_context(context);
1693 if (context->preauth_context == NULL) {
1695 krb5_set_error_message(context, retval,
1696 _("Unable to initialize preauth context"));
1701 * Go down the list of preauth modules, and supply them with the
1702 * attribute/value pair.
1704 for (i = 0; i < context->preauth_context->n_modules; i++) {
1705 mod = &context->preauth_context->modules[i];
1706 if (mod->client_supply_gic_opts == NULL)
1708 retval = mod->client_supply_gic_opts(context, mod->moddata,
1709 (krb5_get_init_creds_opt *)opte,
1712 emsg = krb5_get_error_message(context, retval);
1713 krb5_set_error_message(context, retval, _("Preauth plugin %s: %s"),
1715 krb5_free_error_message(context, emsg);