1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6
7 /*
8 * kdc/kdc_preauth.c
9 *
10 * Copyright 1995, 2003 by the Massachusetts Institute of Technology.
11 * All Rights Reserved.
12 *
13 * Export of this software from the United States of America may
14 * require a specific license from the United States Government.
15 * It is the responsibility of any person or organization contemplating
16 * export to obtain such a license before exporting.
17 *
18 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19 * distribute this software and its documentation for any purpose and
20 * without fee is hereby granted, provided that the above copyright
21 * notice appear in all copies and that both that copyright notice and
22 * this permission notice appear in supporting documentation, and that
23 * the name of M.I.T. not be used in advertising or publicity pertaining
24 * to distribution of the software without specific, written prior
25 * permission. Furthermore if you modify this software you must label
26 * your software as modified software and not distribute it in such a
27 * fashion that it might be confused with the original M.I.T. software.
28 * M.I.T. makes no representations about the suitability of
29 * this software for any purpose. It is provided "as is" without express
30 * or implied warranty.
31 *
32 * Preauthentication routines for the KDC.
33 */
34
35 /*
36 * Copyright (C) 1998 by the FundsXpress, INC.
37 *
38 * All rights reserved.
39 *
40 * Export of this software from the United States of America may require
41 * a specific license from the United States Government. It is the
42 * responsibility of any person or organization contemplating export to
43 * obtain such a license before exporting.
44 *
45 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
46 * distribute this software and its documentation for any purpose and
47 * without fee is hereby granted, provided that the above copyright
48 * notice appear in all copies and that both that copyright notice and
49 * this permission notice appear in supporting documentation, and that
50 * the name of FundsXpress. not be used in advertising or publicity pertaining
51 * to distribution of the software without specific, written prior
52 * permission. FundsXpress makes no representations about the suitability of
53 * this software for any purpose. It is provided "as is" without express
54 * or implied warranty.
55 *
56 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
57 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
58 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
59 */
60
61 #include "k5-int.h"
62 #include "kdc_util.h"
63 #include "extern.h"
64 #include "com_err.h"
65 #include <assert.h>
66 #include <stdio.h>
67 #include "adm_proto.h"
68 #include <libintl.h>
69 #include <syslog.h>
70
71 #include <assert.h>
72 #include "preauth_plugin.h"
73
74 #if TARGET_OS_MAC
75 static const char *objdirs[] = { KRB5_PLUGIN_BUNDLE_DIR, LIBDIR "/krb5/plugins/preauth", NULL }; /* should be a list */
76 #else
77 static const char *objdirs[] = { LIBDIR "/krb5/plugins/preauth", NULL };
78 #endif
79
80 /* XXX This is ugly and should be in a header file somewhere */
81 #ifndef KRB5INT_DES_TYPES_DEFINED
82 #define KRB5INT_DES_TYPES_DEFINED
83 typedef unsigned char des_cblock[8]; /* crypto-block size */
84 #endif
85 typedef des_cblock mit_des_cblock;
86 extern void mit_des_fixup_key_parity (mit_des_cblock );
87 extern int mit_des_is_weak_key (mit_des_cblock );
88
89 typedef struct _krb5_preauth_systems {
90 const char *name;
91 int type;
92 int flags;
93 void *plugin_context;
94 preauth_server_init_proc init;
95 preauth_server_fini_proc fini;
96 preauth_server_edata_proc get_edata;
97 preauth_server_verify_proc verify_padata;
98 preauth_server_return_proc return_padata;
99 preauth_server_free_reqcontext_proc free_pa_reqctx;
100 } krb5_preauth_systems;
101
102 static krb5_error_code verify_enc_timestamp
103 (krb5_context, krb5_db_entry *client,
104 krb5_data *req_pkt,
105 krb5_kdc_req *request,
106 krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data,
107 preauth_get_entry_data_proc get_entry_data,
108 void *pa_system_context,
109 void **pa_request_context,
110 krb5_data **e_data,
111 krb5_authdata ***authz_data);
112
113 static krb5_error_code get_etype_info
114 (krb5_context, krb5_kdc_req *request,
115 krb5_db_entry *client, krb5_db_entry *server,
116 preauth_get_entry_data_proc get_entry_data,
117 void *pa_system_context,
118 krb5_pa_data *data);
119 static krb5_error_code
120 get_etype_info2(krb5_context context, krb5_kdc_req *request,
121 krb5_db_entry *client, krb5_db_entry *server,
122 preauth_get_entry_data_proc get_entry_data,
123 void *pa_system_context,
124 krb5_pa_data *pa_data);
125 static krb5_error_code
126 etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata,
127 krb5_db_entry *client,
128 krb5_kdc_req *request, krb5_kdc_rep *reply,
129 krb5_key_data *client_key,
130 krb5_keyblock *encrypting_key,
131 krb5_pa_data **send_pa,
132 int etype_info2);
133
134 static krb5_error_code
135 return_etype_info(krb5_context, krb5_pa_data * padata,
136 krb5_db_entry *client,
137 krb5_data *req_pkt,
138 krb5_kdc_req *request, krb5_kdc_rep *reply,
139 krb5_key_data *client_key,
140 krb5_keyblock *encrypting_key,
141 krb5_pa_data **send_pa,
142 preauth_get_entry_data_proc get_entry_data,
143 void *pa_system_context,
144 void **pa_request_context);
145
146 static krb5_error_code
147 return_etype_info2(krb5_context, krb5_pa_data * padata,
148 krb5_db_entry *client,
149 krb5_data *req_pkt,
150 krb5_kdc_req *request, krb5_kdc_rep *reply,
151 krb5_key_data *client_key,
152 krb5_keyblock *encrypting_key,
153 krb5_pa_data **send_pa,
154 preauth_get_entry_data_proc get_entry_data,
155 void *pa_system_context,
156 void **pa_request_context);
157
158 static krb5_error_code return_pw_salt
159 (krb5_context, krb5_pa_data * padata,
160 krb5_db_entry *client,
161 krb5_data *req_pkt,
162 krb5_kdc_req *request, krb5_kdc_rep *reply,
163 krb5_key_data *client_key,
164 krb5_keyblock *encrypting_key,
165 krb5_pa_data **send_pa,
166 preauth_get_entry_data_proc get_entry_data,
167 void *pa_system_context,
168 void **pa_request_context);
169
170 /* SAM preauth support */
171 static krb5_error_code verify_sam_response
172 (krb5_context, krb5_db_entry *client,
173 krb5_data *req_pkt,
174 krb5_kdc_req *request,
175 krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data,
176 preauth_get_entry_data_proc get_entry_data,
177 void *pa_module_context,
178 void **pa_request_context,
179 krb5_data **e_data,
180 krb5_authdata ***authz_data);
181
182 static krb5_error_code get_sam_edata
183 (krb5_context, krb5_kdc_req *request,
184 krb5_db_entry *client, krb5_db_entry *server,
185 preauth_get_entry_data_proc get_entry_data,
186 void *pa_module_context,
187 krb5_pa_data *data);
188 static krb5_error_code return_sam_data
189 (krb5_context, krb5_pa_data * padata,
190 krb5_db_entry *client,
191 krb5_data *req_pkt,
192 krb5_kdc_req *request, krb5_kdc_rep *reply,
193 krb5_key_data *client_key,
194 krb5_keyblock *encrypting_key,
195 krb5_pa_data **send_pa,
196 preauth_get_entry_data_proc get_entry_data,
197 void *pa_module_context,
198 void **pa_request_context);
199
200 static krb5_preauth_systems static_preauth_systems[] = {
201 {
202 "timestamp",
203 KRB5_PADATA_ENC_TIMESTAMP,
204 0,
205 NULL,
206 NULL,
207 NULL,
208 0,
209 verify_enc_timestamp,
210 0
211 },
212 {
213 "etype-info",
214 KRB5_PADATA_ETYPE_INFO,
215 0,
216 NULL,
217 NULL,
218 NULL,
219 get_etype_info,
220 0,
221 return_etype_info
222 },
223 {
224 "etype-info2",
225 KRB5_PADATA_ETYPE_INFO2,
226 0,
227 NULL,
228 NULL,
229 NULL,
230 get_etype_info2,
231 0,
232 return_etype_info2
233 },
234 {
235 "pw-salt",
236 KRB5_PADATA_PW_SALT,
237 PA_PSEUDO, /* Don't include this in the error list */
238 NULL,
239 NULL,
240 NULL,
241 0,
242 0,
243 return_pw_salt
244 },
245 {
246 "sam-response",
247 KRB5_PADATA_SAM_RESPONSE,
248 0,
249 NULL,
250 NULL,
251 NULL,
252 0,
253 verify_sam_response,
254 return_sam_data
255 },
256 {
257 "sam-challenge",
258 KRB5_PADATA_SAM_CHALLENGE,
259 PA_HARDWARE, /* causes get_preauth_hint_list to use this */
260 NULL,
261 NULL,
262 NULL,
263 get_sam_edata,
264 0,
265 0
266 },
267 { "[end]", -1,}
268 };
269
270 static krb5_preauth_systems *preauth_systems;
271 static int n_preauth_systems;
272 static struct plugin_dir_handle preauth_plugins;
273
274 krb5_error_code
load_preauth_plugins(krb5_context context)275 load_preauth_plugins(krb5_context context)
276 {
277 struct errinfo err;
278 void **preauth_plugins_ftables;
279 struct krb5plugin_preauth_server_ftable_v1 *ftable;
280 int module_count, i, j, k;
281 void *plugin_context;
282 preauth_server_init_proc server_init_proc = NULL;
283 char **kdc_realm_names = NULL;
284
285 memset(&err, 0, sizeof(err));
286
287 /* Attempt to load all of the preauth plugins we can find. */
288 PLUGIN_DIR_INIT(&preauth_plugins);
289 if (PLUGIN_DIR_OPEN(&preauth_plugins) == 0) {
290 if (krb5int_open_plugin_dirs(objdirs, NULL,
291 &preauth_plugins, &err) != 0) {
292 return KRB5_PLUGIN_NO_HANDLE;
293 }
294 }
295
296 /* Get the method tables provided by the loaded plugins. */
297 preauth_plugins_ftables = NULL;
298 if (krb5int_get_plugin_dir_data(&preauth_plugins,
299 "preauthentication_server_1",
300 &preauth_plugins_ftables, &err) != 0) {
301 return KRB5_PLUGIN_NO_HANDLE;
302 }
303
304 /* Count the valid modules. */
305 module_count = sizeof(static_preauth_systems)
306 / sizeof(static_preauth_systems[0]);
307 if (preauth_plugins_ftables != NULL) {
308 for (i = 0; preauth_plugins_ftables[i] != NULL; i++) {
309 ftable = preauth_plugins_ftables[i];
310 if ((ftable->flags_proc == NULL) &&
311 (ftable->edata_proc == NULL) &&
312 (ftable->verify_proc == NULL) &&
313 (ftable->return_proc == NULL)) {
314 continue;
315 }
316 for (j = 0;
317 ftable->pa_type_list != NULL &&
318 ftable->pa_type_list[j] > 0;
319 j++) {
320 module_count++;
321 }
322 }
323 }
324
325 /* Build the complete list of supported preauthentication options, and
326 * leave room for a terminator entry. */
327 preauth_systems = malloc(sizeof(krb5_preauth_systems) * (module_count + 1));
328 if (preauth_systems == NULL) {
329 krb5int_free_plugin_dir_data(preauth_plugins_ftables);
330 return ENOMEM;
331 }
332
333 /* Build a list of the names of the supported realms for this KDC.
334 * The list of names is terminated with a NULL. */
335 kdc_realm_names = malloc(sizeof(char *) * (kdc_numrealms + 1));
336 if (kdc_realm_names == NULL) {
337 krb5int_free_plugin_dir_data(preauth_plugins_ftables);
338 return ENOMEM;
339 }
340 for (i = 0; i < kdc_numrealms; i++) {
341 kdc_realm_names[i] = kdc_realmlist[i]->realm_name;
342 }
343 kdc_realm_names[i] = NULL;
344
345 /* Add the locally-supplied mechanisms to the dynamic list first. */
346 for (i = 0, k = 0;
347 i < sizeof(static_preauth_systems) / sizeof(static_preauth_systems[0]);
348 i++) {
349 if (static_preauth_systems[i].type == -1)
350 break;
351 preauth_systems[k] = static_preauth_systems[i];
352 /* Try to initialize the preauth system. If it fails, we'll remove it
353 * from the list of systems we'll be using. */
354 plugin_context = NULL;
355 server_init_proc = static_preauth_systems[i].init;
356 if ((server_init_proc != NULL) &&
357 ((*server_init_proc)(context, &plugin_context, (const char **)kdc_realm_names) != 0)) {
358 memset(&preauth_systems[k], 0, sizeof(preauth_systems[k]));
359 continue;
360 }
361 preauth_systems[k].plugin_context = plugin_context;
362 k++;
363 }
364
365 /* Now add the dynamically-loaded mechanisms to the list. */
366 if (preauth_plugins_ftables != NULL) {
367 for (i = 0; preauth_plugins_ftables[i] != NULL; i++) {
368 ftable = preauth_plugins_ftables[i];
369 if ((ftable->flags_proc == NULL) &&
370 (ftable->edata_proc == NULL) &&
371 (ftable->verify_proc == NULL) &&
372 (ftable->return_proc == NULL)) {
373 continue;
374 }
375 plugin_context = NULL;
376 for (j = 0;
377 ftable->pa_type_list != NULL &&
378 ftable->pa_type_list[j] > 0;
379 j++) {
380 /* Try to initialize the plugin. If it fails, we'll remove it
381 * from the list of modules we'll be using. */
382 if (j == 0) {
383 server_init_proc = ftable->init_proc;
384 if (server_init_proc != NULL) {
385 krb5_error_code initerr;
386 initerr = (*server_init_proc)(context, &plugin_context, (const char **)kdc_realm_names);
387 if (initerr) {
388 const char *emsg;
389 emsg = krb5_get_error_message(context, initerr);
390 if (emsg) {
391 krb5_klog_syslog(LOG_ERR,
392 "preauth %s failed to initialize: %s",
393 ftable->name, emsg);
394 krb5_free_error_message(context, emsg);
395 }
396 memset(&preauth_systems[k], 0, sizeof(preauth_systems[k]));
397
398 break; /* skip all modules in this plugin */
399 }
400 }
401 }
402 preauth_systems[k].name = ftable->name;
403 preauth_systems[k].type = ftable->pa_type_list[j];
404 if (ftable->flags_proc != NULL)
405 preauth_systems[k].flags = ftable->flags_proc(context, preauth_systems[k].type);
406 else
407 preauth_systems[k].flags = 0;
408 preauth_systems[k].plugin_context = plugin_context;
409 preauth_systems[k].init = server_init_proc;
410 /* Only call fini once for each plugin */
411 if (j == 0)
412 preauth_systems[k].fini = ftable->fini_proc;
413 else
414 preauth_systems[k].fini = NULL;
415 preauth_systems[k].get_edata = ftable->edata_proc;
416 preauth_systems[k].verify_padata = ftable->verify_proc;
417 preauth_systems[k].return_padata = ftable->return_proc;
418 preauth_systems[k].free_pa_reqctx =
419 ftable->freepa_reqcontext_proc;
420 k++;
421 }
422 }
423 krb5int_free_plugin_dir_data(preauth_plugins_ftables);
424 }
425 free(kdc_realm_names);
426 n_preauth_systems = k;
427 /* Add the end-of-list marker. */
428 preauth_systems[k].name = "[end]";
429 preauth_systems[k].type = -1;
430 return 0;
431 }
432
433 krb5_error_code
unload_preauth_plugins(krb5_context context)434 unload_preauth_plugins(krb5_context context)
435 {
436 int i;
437 if (preauth_systems != NULL) {
438 for (i = 0; i < n_preauth_systems; i++) {
439 if (preauth_systems[i].fini != NULL) {
440 (*preauth_systems[i].fini)(context,
441 preauth_systems[i].plugin_context);
442 }
443 memset(&preauth_systems[i], 0, sizeof(preauth_systems[i]));
444 }
445 free(preauth_systems);
446 preauth_systems = NULL;
447 n_preauth_systems = 0;
448 krb5int_close_plugin_dirs(&preauth_plugins);
449 }
450 return 0;
451 }
452
453 /*
454 * The make_padata_context() function creates a space for storing any context
455 * information which will be needed by return_padata() later. Each preauth
456 * type gets a context storage location of its own.
457 */
458 struct request_pa_context {
459 int n_contexts;
460 struct {
461 krb5_preauth_systems *pa_system;
462 void *pa_context;
463 } *contexts;
464 };
465
466 static krb5_error_code
make_padata_context(krb5_context context,void ** padata_context)467 make_padata_context(krb5_context context, void **padata_context)
468 {
469 int i;
470 struct request_pa_context *ret;
471
472 ret = malloc(sizeof(*ret));
473 if (ret == NULL) {
474 return ENOMEM;
475 }
476
477 ret->n_contexts = n_preauth_systems;
478 ret->contexts = malloc(sizeof(ret->contexts[0]) * ret->n_contexts);
479 if (ret->contexts == NULL) {
480 free(ret);
481 return ENOMEM;
482 }
483
484 memset(ret->contexts, 0, sizeof(ret->contexts[0]) * ret->n_contexts);
485
486 for (i = 0; i < ret->n_contexts; i++) {
487 ret->contexts[i].pa_system = &preauth_systems[i];
488 ret->contexts[i].pa_context = NULL;
489 }
490
491 *padata_context = ret;
492
493 return 0;
494 }
495
496 /*
497 * The free_padata_context function frees any context information pointers
498 * which the check_padata() function created but which weren't already cleaned
499 * up by return_padata().
500 */
501 krb5_error_code
free_padata_context(krb5_context kcontext,void ** padata_context)502 free_padata_context(krb5_context kcontext, void **padata_context)
503 {
504 struct request_pa_context *context;
505 krb5_preauth_systems *preauth_system;
506 void **pctx, *mctx;
507 int i;
508
509 if (padata_context == NULL)
510 return 0;
511
512 context = *padata_context;
513
514 for (i = 0; i < context->n_contexts; i++) {
515 if (context->contexts[i].pa_context != NULL) {
516 preauth_system = context->contexts[i].pa_system;
517 mctx = preauth_system->plugin_context;
518 if (preauth_system->free_pa_reqctx != NULL) {
519 pctx = &context->contexts[i].pa_context;
520 (*preauth_system->free_pa_reqctx)(kcontext, mctx, pctx);
521 }
522 context->contexts[i].pa_context = NULL;
523 }
524 }
525
526 free(context->contexts);
527 free(context);
528
529 return 0;
530 }
531
532 /* Retrieve a specified tl_data item from the given entry, and return its
533 * contents in a new krb5_data, which must be freed by the caller. */
534 static krb5_error_code
get_entry_tl_data(krb5_context context,krb5_db_entry * entry,krb5_int16 tl_data_type,krb5_data ** result)535 get_entry_tl_data(krb5_context context, krb5_db_entry *entry,
536 krb5_int16 tl_data_type, krb5_data **result)
537 {
538 krb5_tl_data *tl;
539 for (tl = entry->tl_data; tl != NULL; tl = tl->tl_data_next) {
540 if (tl->tl_data_type == tl_data_type) {
541 *result = malloc(sizeof(krb5_data));
542 if (*result == NULL) {
543 return ENOMEM;
544 }
545 (*result)->magic = KV5M_DATA;
546 (*result)->data = malloc(tl->tl_data_length);
547 if ((*result)->data == NULL) {
548 free(*result);
549 *result = NULL;
550 return ENOMEM;
551 }
552 memcpy((*result)->data, tl->tl_data_contents, tl->tl_data_length);
553 return 0;
554 }
555 }
556 return ENOENT;
557 }
558
559 /*
560 * Retrieve a specific piece of information pertaining to the entry or the
561 * request and return it in a new krb5_data item which the caller must free.
562 *
563 * This may require massaging data into a contrived format, but it will
564 * hopefully keep us from having to reveal library-internal functions to
565 * modules.
566 */
567 static krb5_error_code
get_entry_data(krb5_context context,krb5_kdc_req * request,krb5_db_entry * entry,krb5_int32 type,krb5_data ** result)568 get_entry_data(krb5_context context,
569 krb5_kdc_req *request, krb5_db_entry *entry,
570 krb5_int32 type,
571 krb5_data **result)
572 {
573 int i, k;
574 krb5_data *ret;
575 krb5_deltat *delta;
576 krb5_keyblock *keys;
577 krb5_key_data *entry_key;
578
579 switch (type) {
580 case krb5plugin_preauth_entry_request_certificate:
581 return get_entry_tl_data(context, entry,
582 KRB5_TL_USER_CERTIFICATE, result);
583 break;
584 case krb5plugin_preauth_entry_max_time_skew:
585 ret = malloc(sizeof(krb5_data));
586 if (ret == NULL)
587 return ENOMEM;
588 delta = malloc(sizeof(krb5_deltat));
589 if (delta == NULL) {
590 free(ret);
591 return ENOMEM;
592 }
593 *delta = context->clockskew;
594 ret->data = (char *) delta;
595 ret->length = sizeof(*delta);
596 *result = ret;
597 return 0;
598 break;
599 case krb5plugin_preauth_keys:
600 ret = malloc(sizeof(krb5_data));
601 if (ret == NULL)
602 return ENOMEM;
603 keys = malloc(sizeof(krb5_keyblock) * (request->nktypes + 1));
604 if (keys == NULL) {
605 free(ret);
606 return ENOMEM;
607 }
608 ret->data = (char *) keys;
609 ret->length = sizeof(krb5_keyblock) * (request->nktypes + 1);
610 memset(ret->data, 0, ret->length);
611 k = 0;
612 for (i = 0; i < request->nktypes; i++) {
613 entry_key = NULL;
614 if (krb5_dbe_find_enctype(context, entry, request->ktype[i],
615 -1, 0, &entry_key) != 0)
616 continue;
617 if (krb5_dbekd_decrypt_key_data(context, &master_keyblock,
618 entry_key, &keys[k], NULL) != 0) {
619 if (keys[k].contents != NULL)
620 krb5_free_keyblock_contents(context, &keys[k]);
621 memset(&keys[k], 0, sizeof(keys[k]));
622 continue;
623 }
624 k++;
625 }
626 if (k > 0) {
627 *result = ret;
628 return 0;
629 } else {
630 free(keys);
631 free(ret);
632 }
633 break;
634 case krb5plugin_preauth_request_body:
635 ret = NULL;
636 encode_krb5_kdc_req_body(request, &ret);
637 if (ret != NULL) {
638 *result = ret;
639 return 0;
640 }
641 return ASN1_PARSE_ERROR;
642 break;
643 default:
644 break;
645 }
646 return ENOENT;
647 }
648
649 static krb5_error_code
find_pa_system(int type,krb5_preauth_systems ** preauth)650 find_pa_system(int type, krb5_preauth_systems **preauth)
651 {
652 krb5_preauth_systems *ap;
653
654 ap = preauth_systems ? preauth_systems : static_preauth_systems;
655 while ((ap->type != -1) && (ap->type != type))
656 ap++;
657 if (ap->type == -1)
658 return(KRB5_PREAUTH_BAD_TYPE);
659 *preauth = ap;
660 return 0;
661 }
662
663 static krb5_error_code
find_pa_context(krb5_preauth_systems * pa_sys,struct request_pa_context * context,void *** pa_context)664 find_pa_context(krb5_preauth_systems *pa_sys,
665 struct request_pa_context *context,
666 void ***pa_context)
667 {
668 int i;
669
670 *pa_context = 0;
671
672 if (context == NULL)
673 return KRB5KRB_ERR_GENERIC;
674
675 for (i = 0; i < context->n_contexts; i++) {
676 if (context->contexts[i].pa_system == pa_sys) {
677 *pa_context = &context->contexts[i].pa_context;
678 return 0;
679 }
680 }
681
682 return KRB5KRB_ERR_GENERIC;
683 }
684
685 /*
686 * Create a list of indices into the preauth_systems array, sorted by order of
687 * preference.
688 */
689 static krb5_boolean
pa_list_includes(krb5_pa_data ** pa_data,krb5_preauthtype pa_type)690 pa_list_includes(krb5_pa_data **pa_data, krb5_preauthtype pa_type)
691 {
692 while (*pa_data != NULL) {
693 if ((*pa_data)->pa_type == pa_type)
694 return TRUE;
695 pa_data++;
696 }
697 return FALSE;
698 }
699 static void
sort_pa_order(krb5_context context,krb5_kdc_req * request,int * pa_order)700 sort_pa_order(krb5_context context, krb5_kdc_req *request, int *pa_order)
701 {
702 int i, j, k, n_repliers, n_key_replacers;
703
704 /* First, set up the default order. */
705 i = 0;
706 for (j = 0; j < n_preauth_systems; j++) {
707 if (preauth_systems[j].return_padata != NULL)
708 pa_order[i++] = j;
709 }
710 n_repliers = i;
711 pa_order[n_repliers] = -1;
712
713 /* Reorder so that PA_REPLACES_KEY modules are listed first. */
714 for (i = 0; i < n_repliers; i++) {
715 /* If this module replaces the key, then it's okay to leave it where it
716 * is in the order. */
717 if (preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY)
718 continue;
719 /* If not, search for a module which does, and swap in the first one we
720 * find. */
721 for (j = i + 1; j < n_repliers; j++) {
722 if (preauth_systems[pa_order[j]].flags & PA_REPLACES_KEY) {
723 k = pa_order[j];
724 pa_order[j] = pa_order[i];
725 pa_order[i] = k;
726 break;
727 }
728 }
729 }
730
731 if (request->padata != NULL) {
732 /* Now reorder the subset of modules which replace the key,
733 * bubbling those which handle pa_data types provided by the
734 * client ahead of the others. */
735 for (i = 0; preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY; i++) {
736 continue;
737 }
738 n_key_replacers = i;
739 for (i = 0; i < n_key_replacers; i++) {
740 if (pa_list_includes(request->padata,
741 preauth_systems[pa_order[i]].type))
742 continue;
743 for (j = i + 1; j < n_key_replacers; j++) {
744 if (pa_list_includes(request->padata,
745 preauth_systems[pa_order[j]].type)) {
746 k = pa_order[j];
747 pa_order[j] = pa_order[i];
748 pa_order[i] = k;
749 break;
750 }
751 }
752 }
753 }
754 #ifdef DEBUG
755 krb5_klog_syslog(LOG_DEBUG, "original preauth mechanism list:");
756 for (i = 0; i < n_preauth_systems; i++) {
757 if (preauth_systems[i].return_padata != NULL)
758 krb5_klog_syslog(LOG_DEBUG, "... %s(%d)", preauth_systems[i].name,
759 preauth_systems[i].type);
760 }
761 krb5_klog_syslog(LOG_DEBUG, "sorted preauth mechanism list:");
762 for (i = 0; pa_order[i] != -1; i++) {
763 krb5_klog_syslog(LOG_DEBUG, "... %s(%d)",
764 preauth_systems[pa_order[i]].name,
765 preauth_systems[pa_order[i]].type);
766 }
767 #endif
768 }
769
missing_required_preauth(krb5_db_entry * client,krb5_db_entry * server,krb5_enc_tkt_part * enc_tkt_reply)770 const char *missing_required_preauth(krb5_db_entry *client,
771 krb5_db_entry *server,
772 krb5_enc_tkt_part *enc_tkt_reply)
773 {
774 #if 0
775 /*
776 * If this is the pwchange service, and the pre-auth bit is set,
777 * allow it even if the HW preauth would normally be required.
778 *
779 * Sandia national labs wanted this for some strange reason... we
780 * leave it disabled normally.
781 */
782 if (isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE) &&
783 isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
784 return 0;
785 #endif
786
787 #ifdef DEBUG
788 krb5_klog_syslog (LOG_DEBUG,
789 "client needs %spreauth, %shw preauth; request has %spreauth, %shw preauth",
790 isflagset (client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) ? "" : "no ",
791 isflagset (client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) ? "" : "no ",
792 isflagset (enc_tkt_reply->flags, TKT_FLG_PRE_AUTH) ? "" : "no ",
793 isflagset (enc_tkt_reply->flags, TKT_FLG_HW_AUTH) ? "" : "no ");
794 #endif
795
796 if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) &&
797 !isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
798 return "NEEDED_PREAUTH";
799
800 if (isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) &&
801 !isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH))
802 return "NEEDED_HW_PREAUTH";
803
804 return 0;
805 }
806
get_preauth_hint_list(krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,krb5_data * e_data)807 void get_preauth_hint_list(krb5_kdc_req *request, krb5_db_entry *client,
808 krb5_db_entry *server, krb5_data *e_data)
809 {
810 int hw_only;
811 krb5_preauth_systems *ap;
812 krb5_pa_data **pa_data, **pa;
813 krb5_data *edat;
814 krb5_error_code retval;
815
816 /* Zero these out in case we need to abort */
817 e_data->length = 0;
818 e_data->data = 0;
819
820 hw_only = isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH);
821 pa_data = malloc(sizeof(krb5_pa_data *) * (n_preauth_systems+1));
822 if (pa_data == 0)
823 return;
824 memset(pa_data, 0, sizeof(krb5_pa_data *) * (n_preauth_systems+1));
825 pa = pa_data;
826
827 for (ap = preauth_systems; ap->type != -1; ap++) {
828 if (hw_only && !(ap->flags & PA_HARDWARE))
829 continue;
830 if (ap->flags & PA_PSEUDO)
831 continue;
832 *pa = malloc(sizeof(krb5_pa_data));
833 if (*pa == 0)
834 goto errout;
835 memset(*pa, 0, sizeof(krb5_pa_data));
836 (*pa)->magic = KV5M_PA_DATA;
837 (*pa)->pa_type = ap->type;
838 if (ap->get_edata) {
839 retval = (ap->get_edata)(kdc_context, request, client, server,
840 get_entry_data, ap->plugin_context, *pa);
841 if (retval) {
842 /* just failed on this type, continue */
843 free(*pa);
844 *pa = 0;
845 continue;
846 }
847 }
848 pa++;
849 }
850 if (pa_data[0] == 0) {
851 krb5_klog_syslog (LOG_INFO,
852 "%spreauth required but hint list is empty",
853 hw_only ? "hw" : "");
854 }
855 retval = encode_krb5_padata_sequence((krb5_pa_data * const *) pa_data,
856 &edat);
857 if (retval)
858 goto errout;
859 *e_data = *edat;
860 free(edat);
861
862 errout:
863 krb5_free_pa_data(kdc_context, pa_data);
864 return;
865 }
866
867 /*
868 * Add authorization data returned from preauth modules to the ticket
869 * It is assumed that ad is a "null-terminated" array of krb5_authdata ptrs
870 */
871 static krb5_error_code
add_authorization_data(krb5_enc_tkt_part * enc_tkt_part,krb5_authdata ** ad)872 add_authorization_data(krb5_enc_tkt_part *enc_tkt_part, krb5_authdata **ad)
873 {
874 krb5_authdata **newad;
875 int oldones, newones;
876 int i;
877
878 if (enc_tkt_part == NULL || ad == NULL)
879 return EINVAL;
880
881 for (newones = 0; ad[newones] != NULL; newones++);
882 if (newones == 0)
883 return 0; /* nothing to add */
884
885 if (enc_tkt_part->authorization_data == NULL)
886 oldones = 0;
887 else
888 for (oldones = 0;
889 enc_tkt_part->authorization_data[oldones] != NULL; oldones++);
890
891 newad = malloc((oldones + newones + 1) * sizeof(krb5_authdata *));
892 if (newad == NULL)
893 return ENOMEM;
894
895 /* Copy any existing pointers */
896 for (i = 0; i < oldones; i++)
897 newad[i] = enc_tkt_part->authorization_data[i];
898
899 /* Add the new ones */
900 for (i = 0; i < newones; i++)
901 newad[oldones+i] = ad[i];
902
903 /* Terminate the new list */
904 newad[oldones+i] = NULL;
905
906 /* Free any existing list */
907 if (enc_tkt_part->authorization_data != NULL)
908 free(enc_tkt_part->authorization_data);
909
910 /* Install our new list */
911 enc_tkt_part->authorization_data = newad;
912
913 return 0;
914 }
915
916 /*
917 * This routine is called to verify the preauthentication information
918 * for a V5 request.
919 *
920 * Returns 0 if the pre-authentication is valid, non-zero to indicate
921 * an error code of some sort.
922 */
923
924 krb5_error_code
check_padata(krb5_context context,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_enc_tkt_part * enc_tkt_reply,void ** padata_context,krb5_data * e_data)925 check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
926 krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
927 void **padata_context, krb5_data *e_data)
928 {
929 krb5_error_code retval = 0;
930 krb5_pa_data **padata;
931 krb5_preauth_systems *pa_sys;
932 void **pa_context;
933 krb5_data *pa_e_data = NULL, *tmp_e_data = NULL;
934 int pa_ok = 0, pa_found = 0;
935 krb5_error_code saved_retval = 0;
936 int use_saved_retval = 0;
937 const char *emsg;
938 krb5_authdata **tmp_authz_data = NULL;
939
940 if (request->padata == 0)
941 return 0;
942
943 if (make_padata_context(context, padata_context) != 0) {
944 return KRB5KRB_ERR_GENERIC;
945 }
946
947 #ifdef DEBUG
948 krb5_klog_syslog (LOG_DEBUG, "checking padata");
949 #endif
950 for (padata = request->padata; *padata; padata++) {
951 #ifdef DEBUG
952 krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*padata)->pa_type);
953 #endif
954 if (find_pa_system((*padata)->pa_type, &pa_sys))
955 continue;
956 if (find_pa_context(pa_sys, *padata_context, &pa_context))
957 continue;
958 #ifdef DEBUG
959 krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", pa_sys->name);
960 #endif
961 if (pa_sys->verify_padata == 0)
962 continue;
963 pa_found++;
964 retval = pa_sys->verify_padata(context, client, req_pkt, request,
965 enc_tkt_reply, *padata,
966 get_entry_data, pa_sys->plugin_context,
967 pa_context, &tmp_e_data, &tmp_authz_data);
968 if (retval) {
969 emsg = krb5_get_error_message (context, retval);
970 krb5_klog_syslog (LOG_INFO, "preauth (%s) verify failure: %s",
971 pa_sys->name, emsg);
972 krb5_free_error_message (context, emsg);
973 /* Ignore authorization data returned from modules that fail */
974 if (tmp_authz_data != NULL) {
975 krb5_free_authdata(context, tmp_authz_data);
976 tmp_authz_data = NULL;
977 }
978 if (pa_sys->flags & PA_REQUIRED) {
979 /* free up any previous edata we might have been saving */
980 if (pa_e_data != NULL)
981 krb5_free_data(context, pa_e_data);
982 pa_e_data = tmp_e_data;
983 tmp_e_data = NULL;
984 use_saved_retval = 0; /* Make sure we use the current retval */
985 pa_ok = 0;
986 break;
987 }
988 /*
989 * We'll return edata from either the first PA_REQUIRED module
990 * that fails, or the first non-PA_REQUIRED module that fails.
991 * Hang on to edata from the first non-PA_REQUIRED module.
992 * If we've already got one saved, simply discard this one.
993 */
994 if (tmp_e_data != NULL) {
995 if (pa_e_data == NULL) {
996 /* save the first error code and e-data */
997 pa_e_data = tmp_e_data;
998 tmp_e_data = NULL;
999 saved_retval = retval;
1000 use_saved_retval = 1;
1001 } else {
1002 /* discard this extra e-data from non-PA_REQUIRED module */
1003 krb5_free_data(context, tmp_e_data);
1004 tmp_e_data = NULL;
1005 }
1006 }
1007 } else {
1008 #ifdef DEBUG
1009 krb5_klog_syslog (LOG_DEBUG, ".. .. ok");
1010 #endif
1011 /* Ignore any edata returned on success */
1012 if (tmp_e_data != NULL) {
1013 krb5_free_data(context, tmp_e_data);
1014 tmp_e_data = NULL;
1015 }
1016 /* Add any authorization data to the ticket */
1017 if (tmp_authz_data != NULL) {
1018 add_authorization_data(enc_tkt_reply, tmp_authz_data);
1019 free(tmp_authz_data);
1020 tmp_authz_data = NULL;
1021 }
1022 pa_ok = 1;
1023 if (pa_sys->flags & PA_SUFFICIENT)
1024 break;
1025 }
1026 }
1027
1028 /* Don't bother copying and returning e-data on success */
1029 if (pa_ok && pa_e_data != NULL) {
1030 krb5_free_data(context, pa_e_data);
1031 pa_e_data = NULL;
1032 }
1033 /* Return any e-data from the preauth that caused us to exit the loop */
1034 if (pa_e_data != NULL) {
1035 e_data->data = malloc(pa_e_data->length);
1036 if (e_data->data == NULL) {
1037 krb5_free_data(context, pa_e_data);
1038 /* Solaris Kerberos */
1039 return ENOMEM;
1040 }
1041 memcpy(e_data->data, pa_e_data->data, pa_e_data->length);
1042 e_data->length = pa_e_data->length;
1043 krb5_free_data(context, pa_e_data);
1044 pa_e_data = NULL;
1045 if (use_saved_retval != 0)
1046 retval = saved_retval;
1047 }
1048
1049 if (pa_ok)
1050 return 0;
1051
1052 /* pa system was not found, but principal doesn't require preauth */
1053 if (!pa_found &&
1054 !isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) &&
1055 !isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH))
1056 return 0;
1057
1058 if (!pa_found) {
1059 emsg = krb5_get_error_message(context, retval);
1060 krb5_klog_syslog (LOG_INFO, "no valid preauth type found: %s", emsg);
1061 krb5_free_error_message(context, emsg);
1062 }
1063 /* The following switch statement allows us
1064 * to return some preauth system errors back to the client.
1065 */
1066 switch(retval) {
1067 case KRB5KRB_AP_ERR_BAD_INTEGRITY:
1068 case KRB5KRB_AP_ERR_SKEW:
1069 case KRB5KDC_ERR_ETYPE_NOSUPP:
1070 /* rfc 4556 */
1071 case KRB5KDC_ERR_CLIENT_NOT_TRUSTED:
1072 case KRB5KDC_ERR_INVALID_SIG:
1073 case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED:
1074 case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE:
1075 case KRB5KDC_ERR_INVALID_CERTIFICATE:
1076 case KRB5KDC_ERR_REVOKED_CERTIFICATE:
1077 case KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN:
1078 case KRB5KDC_ERR_CLIENT_NAME_MISMATCH:
1079 case KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE:
1080 case KRB5KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED:
1081 case KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED:
1082 case KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED:
1083 case KRB5KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED:
1084 /* earlier drafts of what became rfc 4556 */
1085 case KRB5KDC_ERR_CERTIFICATE_MISMATCH:
1086 case KRB5KDC_ERR_KDC_NOT_TRUSTED:
1087 case KRB5KDC_ERR_REVOCATION_STATUS_UNAVAILABLE:
1088 /* This value is shared with KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */
1089 /* case KRB5KDC_ERR_KEY_TOO_WEAK: */
1090 return retval;
1091 default:
1092 return KRB5KDC_ERR_PREAUTH_FAILED;
1093 }
1094 }
1095
1096 /*
1097 * return_padata creates any necessary preauthentication
1098 * structures which should be returned by the KDC to the client
1099 */
1100 krb5_error_code
return_padata(krb5_context context,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,void ** padata_context)1101 return_padata(krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
1102 krb5_kdc_req *request, krb5_kdc_rep *reply,
1103 krb5_key_data *client_key, krb5_keyblock *encrypting_key,
1104 void **padata_context)
1105 {
1106 krb5_error_code retval;
1107 krb5_pa_data ** padata;
1108 krb5_pa_data ** send_pa_list;
1109 krb5_pa_data ** send_pa;
1110 krb5_pa_data * pa = 0;
1111 krb5_preauth_systems * ap;
1112 int * pa_order;
1113 int * pa_type;
1114 int size = 0;
1115 void ** pa_context;
1116 krb5_boolean key_modified;
1117 krb5_keyblock original_key;
1118 if ((!*padata_context)&& (make_padata_context(context, padata_context) != 0)) {
1119 return KRB5KRB_ERR_GENERIC;
1120 }
1121
1122 for (ap = preauth_systems; ap->type != -1; ap++) {
1123 if (ap->return_padata)
1124 size++;
1125 }
1126
1127 if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL)
1128 return ENOMEM;
1129 if ((pa_order = malloc((size+1) * sizeof(int))) == NULL) {
1130 free(send_pa_list);
1131 return ENOMEM;
1132 }
1133 sort_pa_order(context, request, pa_order);
1134
1135 retval = krb5_copy_keyblock_contents(context, encrypting_key,
1136 &original_key);
1137 if (retval) {
1138 free(send_pa_list);
1139 free(pa_order);
1140 return retval;
1141 }
1142 key_modified = FALSE;
1143
1144 send_pa = send_pa_list;
1145 *send_pa = 0;
1146
1147 for (pa_type = pa_order; *pa_type != -1; pa_type++) {
1148 ap = &preauth_systems[*pa_type];
1149 if (!key_modified)
1150 if (original_key.enctype != encrypting_key->enctype)
1151 key_modified = TRUE;
1152 if (!key_modified)
1153 if (original_key.length != encrypting_key->length)
1154 key_modified = TRUE;
1155 if (!key_modified)
1156 if (memcmp(original_key.contents, encrypting_key->contents,
1157 original_key.length) != 0)
1158 key_modified = TRUE;
1159 if (key_modified && (ap->flags & PA_REPLACES_KEY))
1160 continue;
1161 if (ap->return_padata == 0)
1162 continue;
1163 if (find_pa_context(ap, *padata_context, &pa_context))
1164 continue;
1165 pa = 0;
1166 if (request->padata) {
1167 for (padata = request->padata; *padata; padata++) {
1168 if ((*padata)->pa_type == ap->type) {
1169 pa = *padata;
1170 break;
1171 }
1172 }
1173 }
1174 if ((retval = ap->return_padata(context, pa, client, req_pkt, request, reply,
1175 client_key, encrypting_key, send_pa,
1176 get_entry_data, ap->plugin_context,
1177 pa_context))) {
1178 goto cleanup;
1179 }
1180
1181 if (*send_pa)
1182 send_pa++;
1183 *send_pa = 0;
1184 }
1185
1186 retval = 0;
1187
1188 if (send_pa_list[0]) {
1189 reply->padata = send_pa_list;
1190 send_pa_list = 0;
1191 }
1192
1193 cleanup:
1194 if (send_pa_list)
1195 krb5_free_pa_data(context, send_pa_list);
1196
1197 /* Solaris Kerberos */
1198 krb5_free_keyblock_contents(context, &original_key);
1199 free(pa_order);
1200
1201 return (retval);
1202 }
1203
1204 static krb5_boolean
enctype_requires_etype_info_2(krb5_enctype enctype)1205 enctype_requires_etype_info_2(krb5_enctype enctype)
1206 {
1207 switch(enctype) {
1208 case ENCTYPE_DES_CBC_CRC:
1209 case ENCTYPE_DES_CBC_MD4:
1210 case ENCTYPE_DES_CBC_MD5:
1211 case ENCTYPE_DES3_CBC_SHA1:
1212 case ENCTYPE_DES3_CBC_RAW:
1213 case ENCTYPE_ARCFOUR_HMAC:
1214 case ENCTYPE_ARCFOUR_HMAC_EXP :
1215 return 0;
1216 default:
1217 if (krb5_c_valid_enctype(enctype))
1218 return 1;
1219 else return 0;
1220 }
1221 }
1222
1223 static krb5_boolean
request_contains_enctype(krb5_context context,const krb5_kdc_req * request,krb5_enctype enctype)1224 request_contains_enctype (krb5_context context, const krb5_kdc_req *request,
1225 krb5_enctype enctype)
1226 {
1227 int i;
1228 for (i =0; i < request->nktypes; i++)
1229 if (request->ktype[i] == enctype)
1230 return 1;
1231 return 0;
1232 }
1233
1234
1235 static krb5_error_code
verify_enc_timestamp(krb5_context context,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_enc_tkt_part * enc_tkt_reply,krb5_pa_data * pa,preauth_get_entry_data_proc ets_get_entry_data,void * pa_system_context,void ** pa_request_context,krb5_data ** e_data,krb5_authdata *** authz_data)1236 verify_enc_timestamp(krb5_context context, krb5_db_entry *client,
1237 krb5_data *req_pkt,
1238 krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
1239 krb5_pa_data *pa,
1240 preauth_get_entry_data_proc ets_get_entry_data,
1241 void *pa_system_context,
1242 void **pa_request_context,
1243 krb5_data **e_data,
1244 krb5_authdata ***authz_data)
1245 {
1246 krb5_pa_enc_ts * pa_enc = 0;
1247 krb5_error_code retval;
1248 krb5_data scratch;
1249 krb5_data enc_ts_data;
1250 krb5_enc_data *enc_data = 0;
1251 krb5_keyblock key;
1252 krb5_key_data * client_key;
1253 krb5_int32 start;
1254 krb5_timestamp timenow;
1255 krb5_error_code decrypt_err = 0;
1256
1257 (void) memset(&key, 0, sizeof(krb5_keyblock));
1258 scratch.data = (char *) pa->contents;
1259 scratch.length = pa->length;
1260
1261 enc_ts_data.data = 0;
1262
1263 if ((retval = decode_krb5_enc_data(&scratch, &enc_data)) != 0)
1264 goto cleanup;
1265
1266 enc_ts_data.length = enc_data->ciphertext.length;
1267 if ((enc_ts_data.data = (char *) malloc(enc_ts_data.length)) == NULL)
1268 goto cleanup;
1269
1270 start = 0;
1271 decrypt_err = 0;
1272 while (1) {
1273 if ((retval = krb5_dbe_search_enctype(context, client,
1274 &start, enc_data->enctype,
1275 -1, 0, &client_key)))
1276 goto cleanup;
1277
1278 if ((retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock,
1279 client_key, &key, NULL)))
1280 goto cleanup;
1281
1282 key.enctype = enc_data->enctype;
1283
1284 retval = krb5_c_decrypt(context, &key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
1285 0, enc_data, &enc_ts_data);
1286 krb5_free_keyblock_contents(context, &key);
1287 if (retval == 0)
1288 break;
1289 else
1290 decrypt_err = retval;
1291 }
1292
1293 if ((retval = decode_krb5_pa_enc_ts(&enc_ts_data, &pa_enc)) != 0)
1294 goto cleanup;
1295
1296 if ((retval = krb5_timeofday(context, &timenow)) != 0)
1297 goto cleanup;
1298
1299 if (labs(timenow - pa_enc->patimestamp) > context->clockskew) {
1300 retval = KRB5KRB_AP_ERR_SKEW;
1301 goto cleanup;
1302 }
1303
1304 setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH);
1305
1306 retval = 0;
1307
1308 cleanup:
1309 if (enc_data) {
1310 krb5_free_data_contents(context, &enc_data->ciphertext);
1311 free(enc_data);
1312 }
1313 krb5_free_data_contents(context, &enc_ts_data);
1314 if (pa_enc)
1315 free(pa_enc);
1316 /*
1317 * If we get NO_MATCHING_KEY and decryption previously failed, and
1318 * we failed to find any other keys of the correct enctype after
1319 * that failed decryption, it probably means that the password was
1320 * incorrect.
1321 */
1322 if (retval == KRB5_KDB_NO_MATCHING_KEY && decrypt_err != 0)
1323 retval = decrypt_err;
1324 return retval;
1325 }
1326
1327 static krb5_error_code
_make_etype_info_entry(krb5_context context,krb5_kdc_req * request,krb5_key_data * client_key,krb5_enctype etype,krb5_etype_info_entry ** entry,int etype_info2)1328 _make_etype_info_entry(krb5_context context,
1329 krb5_kdc_req *request, krb5_key_data *client_key,
1330 krb5_enctype etype, krb5_etype_info_entry **entry,
1331 int etype_info2)
1332 {
1333 krb5_data salt;
1334 krb5_etype_info_entry * tmp_entry;
1335 krb5_error_code retval;
1336
1337 if ((tmp_entry = malloc(sizeof(krb5_etype_info_entry))) == NULL)
1338 return ENOMEM;
1339
1340 salt.data = 0;
1341
1342 tmp_entry->magic = KV5M_ETYPE_INFO_ENTRY;
1343 tmp_entry->etype = etype;
1344 tmp_entry->length = KRB5_ETYPE_NO_SALT;
1345 tmp_entry->salt = 0;
1346 tmp_entry->s2kparams.data = NULL;
1347 tmp_entry->s2kparams.length = 0;
1348 retval = get_salt_from_key(context, request->client,
1349 client_key, &salt);
1350 if (retval)
1351 goto fail;
1352 if (etype_info2 && client_key->key_data_ver > 1 &&
1353 client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_AFS3) {
1354 switch (etype) {
1355 case ENCTYPE_DES_CBC_CRC:
1356 case ENCTYPE_DES_CBC_MD4:
1357 case ENCTYPE_DES_CBC_MD5:
1358 tmp_entry->s2kparams.data = malloc(1);
1359 if (tmp_entry->s2kparams.data == NULL) {
1360 retval = ENOMEM;
1361 goto fail;
1362 }
1363 tmp_entry->s2kparams.length = 1;
1364 tmp_entry->s2kparams.data[0] = 1;
1365 break;
1366 default:
1367 break;
1368 }
1369 }
1370
1371 if (salt.length >= 0) {
1372 tmp_entry->length = salt.length;
1373 tmp_entry->salt = (unsigned char *) salt.data;
1374 salt.data = 0;
1375 }
1376 *entry = tmp_entry;
1377 return 0;
1378
1379 fail:
1380 if (tmp_entry) {
1381 if (tmp_entry->s2kparams.data)
1382 free(tmp_entry->s2kparams.data);
1383 free(tmp_entry);
1384 }
1385 if (salt.data)
1386 free(salt.data);
1387 return retval;
1388 }
1389 /*
1390 * This function returns the etype information for a particular
1391 * client, to be passed back in the preauth list in the KRB_ERROR
1392 * message. It supports generating both etype_info and etype_info2
1393 * as most of the work is the same.
1394 */
1395 static krb5_error_code
etype_info_helper(krb5_context context,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,krb5_pa_data * pa_data,int etype_info2)1396 etype_info_helper(krb5_context context, krb5_kdc_req *request,
1397 krb5_db_entry *client, krb5_db_entry *server,
1398 krb5_pa_data *pa_data, int etype_info2)
1399 {
1400 krb5_etype_info_entry ** entry = 0;
1401 krb5_key_data *client_key;
1402 krb5_error_code retval;
1403 krb5_data * scratch;
1404 krb5_enctype db_etype;
1405 int i = 0;
1406 int start = 0;
1407 int seen_des = 0;
1408
1409 entry = malloc((client->n_key_data * 2 + 1) * sizeof(krb5_etype_info_entry *));
1410 if (entry == NULL)
1411 return ENOMEM;
1412 entry[0] = NULL;
1413
1414 while (1) {
1415 retval = krb5_dbe_search_enctype(context, client, &start, -1,
1416 -1, 0, &client_key);
1417 if (retval == KRB5_KDB_NO_MATCHING_KEY)
1418 break;
1419 if (retval)
1420 goto cleanup;
1421 db_etype = client_key->key_data_type[0];
1422 if (db_etype == ENCTYPE_DES_CBC_MD4)
1423 db_etype = ENCTYPE_DES_CBC_MD5;
1424
1425 if (request_contains_enctype(context, request, db_etype)) {
1426 assert(etype_info2 ||
1427 !enctype_requires_etype_info_2(db_etype));
1428 if ((retval = _make_etype_info_entry(context, request, client_key,
1429 db_etype, &entry[i], etype_info2)) != 0) {
1430 goto cleanup;
1431 }
1432 entry[i+1] = 0;
1433 i++;
1434 }
1435
1436 /*
1437 * If there is a des key in the kdb, try the "similar" enctypes,
1438 * avoid duplicate entries.
1439 */
1440 if (!seen_des) {
1441 switch (db_etype) {
1442 case ENCTYPE_DES_CBC_MD5:
1443 db_etype = ENCTYPE_DES_CBC_CRC;
1444 break;
1445 case ENCTYPE_DES_CBC_CRC:
1446 db_etype = ENCTYPE_DES_CBC_MD5;
1447 break;
1448 default:
1449 continue;
1450
1451 }
1452 if (request_contains_enctype(context, request, db_etype)) {
1453 if ((retval = _make_etype_info_entry(context, request,
1454 client_key, db_etype, &entry[i], etype_info2)) != 0) {
1455 goto cleanup;
1456 }
1457 entry[i+1] = 0;
1458 i++;
1459 }
1460 seen_des++;
1461 }
1462 }
1463 if (etype_info2)
1464 retval = encode_krb5_etype_info2((krb5_etype_info_entry * const*) entry,
1465 &scratch);
1466 else retval = encode_krb5_etype_info((krb5_etype_info_entry * const*) entry,
1467 &scratch);
1468 if (retval)
1469 goto cleanup;
1470 pa_data->contents = (unsigned char *)scratch->data;
1471 pa_data->length = scratch->length;
1472 free(scratch);
1473
1474 retval = 0;
1475
1476 cleanup:
1477 if (entry)
1478 krb5_free_etype_info(context, entry);
1479 return retval;
1480 }
1481
1482 static krb5_error_code
get_etype_info(krb5_context context,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,preauth_get_entry_data_proc etype_get_entry_data,void * pa_system_context,krb5_pa_data * pa_data)1483 get_etype_info(krb5_context context, krb5_kdc_req *request,
1484 krb5_db_entry *client, krb5_db_entry *server,
1485 preauth_get_entry_data_proc etype_get_entry_data,
1486 void *pa_system_context,
1487 krb5_pa_data *pa_data)
1488 {
1489 int i;
1490 for (i=0; i < request->nktypes; i++) {
1491 if (enctype_requires_etype_info_2(request->ktype[i]))
1492 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP ;;;; /*Caller will
1493 * skip this
1494 * type*/
1495 }
1496 return etype_info_helper(context, request, client, server, pa_data, 0);
1497 }
1498
1499 static krb5_error_code
get_etype_info2(krb5_context context,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,preauth_get_entry_data_proc etype_get_entry_data,void * pa_system_context,krb5_pa_data * pa_data)1500 get_etype_info2(krb5_context context, krb5_kdc_req *request,
1501 krb5_db_entry *client, krb5_db_entry *server,
1502 preauth_get_entry_data_proc etype_get_entry_data,
1503 void *pa_system_context,
1504 krb5_pa_data *pa_data)
1505 {
1506 return etype_info_helper( context, request, client, server, pa_data, 1);
1507 }
1508
1509 static krb5_error_code
etype_info_as_rep_helper(krb5_context context,krb5_pa_data * padata,krb5_db_entry * client,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,int etype_info2)1510 etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata,
1511 krb5_db_entry *client,
1512 krb5_kdc_req *request, krb5_kdc_rep *reply,
1513 krb5_key_data *client_key,
1514 krb5_keyblock *encrypting_key,
1515 krb5_pa_data **send_pa,
1516 int etype_info2)
1517 {
1518 int i;
1519 krb5_error_code retval;
1520 krb5_pa_data *tmp_padata;
1521 krb5_etype_info_entry **entry = NULL;
1522 krb5_data *scratch = NULL;
1523
1524 /*
1525 * Skip PA-ETYPE-INFO completely if AS-REQ lists any "newer"
1526 * enctypes.
1527 */
1528 if (!etype_info2) {
1529 for (i = 0; i < request->nktypes; i++) {
1530 if (enctype_requires_etype_info_2(request->ktype[i])) {
1531 *send_pa = NULL;
1532 return 0;
1533 }
1534 }
1535 }
1536
1537 tmp_padata = malloc( sizeof(krb5_pa_data));
1538 if (tmp_padata == NULL)
1539 return ENOMEM;
1540 if (etype_info2)
1541 tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO2;
1542 else
1543 tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO;
1544
1545 entry = malloc(2 * sizeof(krb5_etype_info_entry *));
1546 if (entry == NULL) {
1547 retval = ENOMEM;
1548 goto cleanup;
1549 }
1550 entry[0] = NULL;
1551 entry[1] = NULL;
1552 retval = _make_etype_info_entry(context, request,
1553 client_key, encrypting_key->enctype,
1554 entry, etype_info2);
1555 if (retval)
1556 goto cleanup;
1557
1558 if (etype_info2)
1559 retval = encode_krb5_etype_info2((krb5_etype_info_entry * const*) entry, &scratch);
1560 else
1561 retval = encode_krb5_etype_info((krb5_etype_info_entry * const*) entry, &scratch);
1562
1563 if (retval)
1564 goto cleanup;
1565 tmp_padata->contents = (uchar_t *)scratch->data;
1566 tmp_padata->length = scratch->length;
1567 *send_pa = tmp_padata;
1568
1569 /* For cleanup - we no longer own the contents of the krb5_data
1570 * only to pointer to the krb5_data
1571 */
1572 scratch->data = 0;
1573
1574 cleanup:
1575 if (entry)
1576 krb5_free_etype_info(context, entry);
1577 if (retval) {
1578 if (tmp_padata)
1579 free(tmp_padata);
1580 }
1581 if (scratch)
1582 krb5_free_data(context, scratch);
1583 return retval;
1584 }
1585
1586 static krb5_error_code
return_etype_info2(krb5_context context,krb5_pa_data * padata,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,preauth_get_entry_data_proc etype_get_entry_data,void * pa_system_context,void ** pa_request_context)1587 return_etype_info2(krb5_context context, krb5_pa_data * padata,
1588 krb5_db_entry *client,
1589 krb5_data *req_pkt,
1590 krb5_kdc_req *request, krb5_kdc_rep *reply,
1591 krb5_key_data *client_key,
1592 krb5_keyblock *encrypting_key,
1593 krb5_pa_data **send_pa,
1594 preauth_get_entry_data_proc etype_get_entry_data,
1595 void *pa_system_context,
1596 void **pa_request_context)
1597 {
1598 return etype_info_as_rep_helper(context, padata, client, request, reply,
1599 client_key, encrypting_key, send_pa, 1);
1600 }
1601
1602
1603 static krb5_error_code
return_etype_info(krb5_context context,krb5_pa_data * padata,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,preauth_get_entry_data_proc etypeget_entry_data,void * pa_system_context,void ** pa_request_context)1604 return_etype_info(krb5_context context, krb5_pa_data * padata,
1605 krb5_db_entry *client,
1606 krb5_data *req_pkt,
1607 krb5_kdc_req *request, krb5_kdc_rep *reply,
1608 krb5_key_data *client_key,
1609 krb5_keyblock *encrypting_key,
1610 krb5_pa_data **send_pa,
1611 preauth_get_entry_data_proc etypeget_entry_data,
1612 void *pa_system_context,
1613 void **pa_request_context)
1614 {
1615 return etype_info_as_rep_helper(context, padata, client, request, reply,
1616 client_key, encrypting_key, send_pa, 0);
1617 }
1618
1619 static krb5_error_code
return_pw_salt(krb5_context context,krb5_pa_data * in_padata,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,preauth_get_entry_data_proc etype_get_entry_data,void * pa_system_context,void ** pa_request_context)1620 return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
1621 krb5_db_entry *client, krb5_data *req_pkt, krb5_kdc_req *request,
1622 krb5_kdc_rep *reply, krb5_key_data *client_key,
1623 krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
1624 preauth_get_entry_data_proc etype_get_entry_data,
1625 void *pa_system_context,
1626 void **pa_request_context)
1627 {
1628 krb5_error_code retval;
1629 krb5_pa_data * padata;
1630 krb5_data * scratch;
1631 krb5_data salt_data;
1632 int i;
1633
1634 for (i = 0; i < request->nktypes; i++) {
1635 if (enctype_requires_etype_info_2(request->ktype[i]))
1636 return 0;
1637 }
1638 if (client_key->key_data_ver == 1 ||
1639 client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)
1640 return 0;
1641
1642 if ((padata = malloc(sizeof(krb5_pa_data))) == NULL)
1643 return ENOMEM;
1644 padata->magic = KV5M_PA_DATA;
1645 padata->pa_type = KRB5_PADATA_PW_SALT;
1646
1647 switch (client_key->key_data_type[1]) {
1648 case KRB5_KDB_SALTTYPE_V4:
1649 /* send an empty (V4) salt */
1650 padata->contents = 0;
1651 padata->length = 0;
1652 break;
1653 case KRB5_KDB_SALTTYPE_NOREALM:
1654 if ((retval = krb5_principal2salt_norealm(kdc_context,
1655 request->client,
1656 &salt_data)))
1657 goto cleanup;
1658 padata->contents = (krb5_octet *)salt_data.data;
1659 padata->length = salt_data.length;
1660 break;
1661 case KRB5_KDB_SALTTYPE_AFS3:
1662 /* send an AFS style realm-based salt */
1663 /* for now, just pass the realm back and let the client
1664 do the work. In the future, add a kdc configuration
1665 variable that specifies the old cell name. */
1666 padata->pa_type = KRB5_PADATA_AFS3_SALT;
1667 /* it would be just like ONLYREALM, but we need to pass the 0 */
1668 scratch = krb5_princ_realm(kdc_context, request->client);
1669 if ((padata->contents = malloc(scratch->length+1)) == NULL) {
1670 retval = ENOMEM;
1671 goto cleanup;
1672 }
1673 memcpy(padata->contents, scratch->data, scratch->length);
1674 padata->length = scratch->length+1;
1675 padata->contents[scratch->length] = 0;
1676 break;
1677 case KRB5_KDB_SALTTYPE_ONLYREALM:
1678 scratch = krb5_princ_realm(kdc_context, request->client);
1679 if ((padata->contents = malloc(scratch->length)) == NULL) {
1680 retval = ENOMEM;
1681 goto cleanup;
1682 }
1683 memcpy(padata->contents, scratch->data, scratch->length);
1684 padata->length = scratch->length;
1685 break;
1686 case KRB5_KDB_SALTTYPE_SPECIAL:
1687 if ((padata->contents = malloc(client_key->key_data_length[1]))
1688 == NULL) {
1689 retval = ENOMEM;
1690 goto cleanup;
1691 }
1692 memcpy(padata->contents, client_key->key_data_contents[1],
1693 client_key->key_data_length[1]);
1694 padata->length = client_key->key_data_length[1];
1695 break;
1696 default:
1697 free(padata);
1698 return 0;
1699 }
1700
1701 *send_pa = padata;
1702 return 0;
1703
1704 cleanup:
1705 free(padata);
1706 return retval;
1707 }
1708
1709 static krb5_error_code
return_sam_data(krb5_context context,krb5_pa_data * in_padata,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_key_data * client_key,krb5_keyblock * encrypting_key,krb5_pa_data ** send_pa,preauth_get_entry_data_proc sam_get_entry_data,void * pa_system_context,void ** pa_request_context)1710 return_sam_data(krb5_context context, krb5_pa_data *in_padata,
1711 krb5_db_entry *client, krb5_data *req_pkt, krb5_kdc_req *request,
1712 krb5_kdc_rep *reply, krb5_key_data *client_key,
1713 krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
1714 preauth_get_entry_data_proc sam_get_entry_data,
1715 void *pa_system_context,
1716 void **pa_request_context)
1717 {
1718 krb5_error_code retval;
1719 krb5_data scratch;
1720 int i;
1721
1722 krb5_sam_response *sr = 0;
1723 krb5_predicted_sam_response *psr = 0;
1724
1725 if (in_padata == 0)
1726 return 0;
1727
1728 /*
1729 * We start by doing the same thing verify_sam_response() does:
1730 * extract the psr from the padata (which is an sr). Nothing
1731 * here should generate errors! We've already successfully done
1732 * all this once.
1733 */
1734
1735 scratch.data = (char *) in_padata->contents; /* SUNWresync121 XXX */
1736 scratch.length = in_padata->length;
1737
1738 if ((retval = decode_krb5_sam_response(&scratch, &sr))) {
1739 com_err("krb5kdc", retval,
1740 gettext("return_sam_data(): decode_krb5_sam_response failed"));
1741 goto cleanup;
1742 }
1743
1744 {
1745 krb5_enc_data tmpdata;
1746
1747 tmpdata.enctype = ENCTYPE_UNKNOWN;
1748 tmpdata.ciphertext = sr->sam_track_id;
1749
1750 scratch.length = tmpdata.ciphertext.length;
1751 if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
1752 retval = ENOMEM;
1753 goto cleanup;
1754 }
1755
1756 if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
1757 &tmpdata, &scratch))) {
1758 com_err("krb5kdc", retval,
1759 gettext("return_sam_data(): decrypt track_id failed"));
1760 free(scratch.data);
1761 goto cleanup;
1762 }
1763 }
1764
1765 if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) {
1766 com_err("krb5kdc", retval,
1767 gettext(
1768 "return_sam_data(): decode_krb5_predicted_sam_response failed"));
1769 free(scratch.data);
1770 goto cleanup;
1771 }
1772
1773 /* We could use sr->sam_flags, but it may be absent or altered. */
1774 if (psr->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
1775 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
1776 gettext("Unsupported SAM flag must-pk-encrypt-sad"));
1777 goto cleanup;
1778 }
1779 if (psr->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
1780 /* No key munging */
1781 goto cleanup;
1782 }
1783 if (psr->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
1784 /* Use sam_key instead of client key */
1785 krb5_free_keyblock_contents(context, encrypting_key);
1786 krb5_copy_keyblock_contents(context, &psr->sam_key, encrypting_key);
1787 /* XXX Attach a useful pa_data */
1788 goto cleanup;
1789 }
1790
1791 /* Otherwise (no flags set), we XOR the keys */
1792 /* XXX The passwords-04 draft is underspecified here wrt different
1793 key types. We will do what I hope to get into the -05 draft. */
1794 {
1795 krb5_octet *p = encrypting_key->contents;
1796 krb5_octet *q = psr->sam_key.contents;
1797 int length = ((encrypting_key->length < psr->sam_key.length)
1798 ? encrypting_key->length
1799 : psr->sam_key.length);
1800
1801 for (i = 0; i < length; i++)
1802 p[i] ^= q[i];
1803 }
1804
1805 /* Post-mixing key correction */
1806 switch (encrypting_key->enctype) {
1807 case ENCTYPE_DES_CBC_CRC:
1808 case ENCTYPE_DES_CBC_MD4:
1809 case ENCTYPE_DES_CBC_MD5:
1810 case ENCTYPE_DES_CBC_RAW:
1811 mit_des_fixup_key_parity(encrypting_key->contents);
1812 if (mit_des_is_weak_key(encrypting_key->contents))
1813 ((krb5_octet *) encrypting_key->contents)[7] ^= 0xf0;
1814 break;
1815
1816 /* XXX case ENCTYPE_DES3_CBC_MD5: listed in 1510bis-04 draft */
1817 case ENCTYPE_DES3_CBC_SHA: /* XXX deprecated? */
1818 case ENCTYPE_DES3_CBC_RAW:
1819 case ENCTYPE_DES3_CBC_SHA1:
1820 for (i = 0; i < 3; i++) {
1821 mit_des_fixup_key_parity(encrypting_key->contents + i * 8);
1822 if (mit_des_is_weak_key(encrypting_key->contents + i * 8))
1823 ((krb5_octet *) encrypting_key->contents)[7 + i * 8] ^= 0xf0;
1824 }
1825 break;
1826
1827 default:
1828 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
1829 gettext("Unimplemented keytype for SAM key mixing"));
1830 goto cleanup;
1831 }
1832
1833 /* XXX Attach a useful pa_data */
1834 cleanup:
1835 if (sr)
1836 krb5_free_sam_response(context, sr);
1837 if (psr)
1838 krb5_free_predicted_sam_response(context, psr);
1839
1840 return retval;
1841 }
1842
1843 static struct {
1844 char* name;
1845 int sam_type;
1846 } *sam_ptr, sam_inst_map[] = {
1847 #if 0 /* SUNWresync121 - unsupported hardware and kdc.log annoyance */
1848 { "SNK4", PA_SAM_TYPE_DIGI_PATH, },
1849 { "SECURID", PA_SAM_TYPE_SECURID, },
1850 { "GRAIL", PA_SAM_TYPE_GRAIL, },
1851 #endif
1852 { 0, 0 },
1853 };
1854
1855 static krb5_error_code
get_sam_edata(krb5_context context,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,preauth_get_entry_data_proc sam_get_entry_data,void * pa_system_context,krb5_pa_data * pa_data)1856 get_sam_edata(krb5_context context, krb5_kdc_req *request,
1857 krb5_db_entry *client, krb5_db_entry *server,
1858 preauth_get_entry_data_proc sam_get_entry_data,
1859 void *pa_system_context, krb5_pa_data *pa_data)
1860 {
1861 krb5_error_code retval;
1862 krb5_sam_challenge sc;
1863 krb5_predicted_sam_response psr;
1864 krb5_data * scratch;
1865 krb5_keyblock encrypting_key;
1866 char response[9];
1867 char inputblock[8];
1868 krb5_data predict_response;
1869
1870 (void) memset(&encrypting_key, 0, sizeof(krb5_keyblock));
1871 (void) memset(&sc, 0, sizeof(sc));
1872 (void) memset(&psr, 0, sizeof(psr));
1873
1874 /* Given the client name we can figure out what type of preauth
1875 they need. The spec is currently for querying the database for
1876 names that match the types of preauth used. Later we should
1877 make this mapping show up in kdc.conf. In the meantime, we
1878 hardcode the following:
1879 /SNK4 -- Digital Pathways SNK/4 preauth.
1880 /GRAIL -- experimental preauth
1881 The first one found is used. See sam_inst_map above.
1882
1883 For SNK4 in particular, the key in the database is the key for
1884 the device; kadmin needs a special interface for it.
1885 */
1886
1887 {
1888 int npr = 1;
1889 krb5_boolean more;
1890 krb5_db_entry assoc;
1891 krb5_key_data *assoc_key;
1892 krb5_principal newp;
1893 int probeslot;
1894
1895 sc.sam_type = 0;
1896
1897 retval = krb5_copy_principal(kdc_context, request->client, &newp);
1898 if (retval) {
1899 com_err(gettext("krb5kdc"),
1900 retval,
1901 gettext("copying client name for preauth probe"));
1902 return retval;
1903 }
1904
1905 probeslot = krb5_princ_size(context, newp)++;
1906 krb5_princ_name(kdc_context, newp) =
1907 realloc(krb5_princ_name(kdc_context, newp),
1908 krb5_princ_size(context, newp) * sizeof(krb5_data));
1909
1910 for(sam_ptr = sam_inst_map; sam_ptr->name; sam_ptr++) {
1911 krb5_princ_component(kdc_context,newp,probeslot)->data = sam_ptr->name;
1912 krb5_princ_component(kdc_context,newp,probeslot)->length =
1913 strlen(sam_ptr->name);
1914 npr = 1;
1915 retval = krb5_db_get_principal(kdc_context, newp, &assoc, &npr, (uint *)&more);
1916 if(!retval && npr) {
1917 sc.sam_type = sam_ptr->sam_type;
1918 break;
1919 }
1920 }
1921
1922 krb5_princ_component(kdc_context,newp,probeslot)->data = 0;
1923 krb5_princ_component(kdc_context,newp,probeslot)->length = 0;
1924 krb5_princ_size(context, newp)--;
1925
1926 krb5_free_principal(kdc_context, newp);
1927
1928 /* if sc.sam_type is set, it worked */
1929 if (sc.sam_type) {
1930 /* so use assoc to get the key out! */
1931 {
1932 /* here's what do_tgs_req does */
1933 retval = krb5_dbe_find_enctype(kdc_context, &assoc,
1934 ENCTYPE_DES_CBC_RAW,
1935 KRB5_KDB_SALTTYPE_NORMAL,
1936 0, /* Get highest kvno */
1937 &assoc_key);
1938 if (retval) {
1939 char *sname;
1940 krb5_unparse_name(kdc_context, request->client, &sname);
1941 com_err(gettext("krb5kdc"),
1942 retval,
1943 gettext("snk4 finding the enctype and key <%s>"),
1944 sname);
1945 free(sname);
1946 return retval;
1947 }
1948 /* convert server.key into a real key */
1949 retval = krb5_dbekd_decrypt_key_data(kdc_context,
1950 &master_keyblock,
1951 assoc_key, &encrypting_key,
1952 NULL);
1953 if (retval) {
1954 com_err(gettext("krb5kdc"),
1955 retval,
1956 gettext("snk4 pulling out key entry"));
1957 return retval;
1958 }
1959 /* now we can use encrypting_key... */
1960 }
1961 } else {
1962 /* SAM is not an option - so don't return as hint */
1963 return KRB5_PREAUTH_BAD_TYPE;
1964 }
1965 }
1966 sc.magic = KV5M_SAM_CHALLENGE;
1967 psr.sam_flags = sc.sam_flags = KRB5_SAM_USE_SAD_AS_KEY;
1968
1969 /* Replay prevention */
1970 if ((retval = krb5_copy_principal(context, request->client, &psr.client)))
1971 return retval;
1972 #ifdef USE_RCACHE
1973 if ((retval = krb5_us_timeofday(context, &psr.stime, &psr.susec)))
1974 return retval;
1975 #endif /* USE_RCACHE */
1976
1977 switch (sc.sam_type) {
1978 case PA_SAM_TYPE_GRAIL:
1979 sc.sam_type_name.data = "Experimental System";
1980 sc.sam_type_name.length = strlen(sc.sam_type_name.data);
1981 sc.sam_challenge_label.data = "experimental challenge label";
1982 sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
1983 sc.sam_challenge.data = "12345";
1984 sc.sam_challenge.length = strlen(sc.sam_challenge.data);
1985
1986 #if 0 /* Enable this to test "normal" (no flags set) mode. */
1987 psr.sam_flags = sc.sam_flags = 0;
1988 #endif
1989
1990 psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
1991 /* string2key on sc.sam_challenge goes in here */
1992 /* eblock is just to set the enctype */
1993 {
1994 const krb5_enctype type = ENCTYPE_DES_CBC_MD5;
1995
1996 if ((retval = krb5_c_string_to_key(context, type, &sc.sam_challenge,
1997 0 /* salt */, &psr.sam_key)))
1998 goto cleanup;
1999
2000 if ((retval = encode_krb5_predicted_sam_response(&psr, &scratch)))
2001 goto cleanup;
2002
2003 {
2004 size_t enclen;
2005 krb5_enc_data tmpdata;
2006
2007 if ((retval = krb5_c_encrypt_length(context,
2008 psr_key.enctype,
2009 scratch->length, &enclen)))
2010 goto cleanup;
2011
2012 if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) {
2013 retval = ENOMEM;
2014 goto cleanup;
2015 }
2016 tmpdata.ciphertext.length = enclen;
2017
2018 if ((retval = krb5_c_encrypt(context, &psr_key,
2019 /* XXX */ 0, 0, scratch, &tmpdata)))
2020 goto cleanup;
2021
2022 sc.sam_track_id = tmpdata.ciphertext;
2023 }
2024 }
2025
2026 sc.sam_response_prompt.data = "response prompt";
2027 sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data);
2028 sc.sam_pk_for_sad.length = 0;
2029 sc.sam_nonce = 0;
2030 /* Generate checksum */
2031 /*krb5_checksum_size(context, ctype)*/
2032 /*krb5_calculate_checksum(context,ctype,in,in_length,seed,
2033 seed_length,outcksum) */
2034 /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed,
2035 seed_length) */
2036 #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */
2037 sc.sam_cksum.contents = (krb5_octet *)
2038 malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES));
2039 if (sc.sam_cksum.contents == NULL) return(ENOMEM);
2040
2041 retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES,
2042 sc.sam_challenge.data,
2043 sc.sam_challenge.length,
2044 psr.sam_key.contents, /* key */
2045 psr.sam_key.length, /* key length */
2046 &sc.sam_cksum);
2047 if (retval) { free(sc.sam_cksum.contents); return(retval); }
2048 #endif /* 0 */
2049
2050 retval = encode_krb5_sam_challenge(&sc, &scratch);
2051 if (retval) goto cleanup;
2052 pa_data->magic = KV5M_PA_DATA;
2053 pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE;
2054 pa_data->contents = (unsigned char *) scratch->data;
2055 pa_data->length = scratch->length;
2056
2057 retval = 0;
2058 break;
2059 case PA_SAM_TYPE_DIGI_PATH:
2060 sc.sam_type_name.data = "Digital Pathways";
2061 sc.sam_type_name.length = strlen(sc.sam_type_name.data);
2062 #if 1
2063 sc.sam_challenge_label.data = "Enter the following on your keypad";
2064 sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
2065 #endif
2066 /* generate digit string, take it mod 1000000 (six digits.) */
2067 {
2068 int j;
2069 krb5_keyblock session_key;
2070 char outputblock[8];
2071 int i;
2072
2073 (void) memset(&session_key, 0, sizeof(krb5_keyblock));
2074
2075 (void) memset(inputblock, 0, 8);
2076
2077 retval = krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_CRC,
2078 &session_key);
2079
2080 if (retval) {
2081 /* random key failed */
2082 com_err(gettext("krb5kdc"),
2083 retval,
2084 gettext("generating random challenge for preauth"));
2085 return retval;
2086 }
2087 /* now session_key has a key which we can pick bits out of */
2088 /* we need six decimal digits. Grab 6 bytes, div 2, mod 10 each. */
2089 if (session_key.length != 8) {
2090 retval = KRB5KDC_ERR_ETYPE_NOSUPP,
2091 com_err(gettext("krb5kdc"),
2092 retval = KRB5KDC_ERR_ETYPE_NOSUPP,
2093 gettext("keytype didn't match code expectations"));
2094 return retval;
2095 }
2096 for(i = 0; i<6; i++) {
2097 inputblock[i] = '0' + ((session_key.contents[i]/2) % 10);
2098 }
2099 if (session_key.contents)
2100 krb5_free_keyblock_contents(kdc_context, &session_key);
2101
2102 /* retval = krb5_finish_key(kdc_context, &eblock); */
2103 /* now we have inputblock containing the 8 byte input to DES... */
2104 sc.sam_challenge.data = inputblock;
2105 sc.sam_challenge.length = 6;
2106
2107 encrypting_key.enctype = ENCTYPE_DES_CBC_RAW;
2108
2109 if (retval) {
2110 com_err(gettext("krb5kdc"),
2111 retval,
2112 gettext("snk4 processing key"));
2113 }
2114
2115 {
2116 krb5_data plain;
2117 krb5_enc_data cipher;
2118
2119 plain.length = 8;
2120 plain.data = inputblock;
2121
2122 /* XXX I know this is enough because of the fixed raw enctype.
2123 if it's not, the underlying code will return a reasonable
2124 error, which should never happen */
2125 cipher.ciphertext.length = 8;
2126 cipher.ciphertext.data = outputblock;
2127
2128 if ((retval = krb5_c_encrypt(kdc_context, &encrypting_key,
2129 /* XXX */ 0, 0, &plain, &cipher))) {
2130 com_err(gettext("krb5kdc"),
2131 retval,
2132 gettext("snk4 response generation failed"));
2133 return retval;
2134 }
2135 }
2136
2137 /* now output block is the raw bits of the response; convert it
2138 to display form */
2139 for (j=0; j<4; j++) {
2140 char n[2];
2141 int k;
2142 n[0] = outputblock[j] & 0xf;
2143 n[1] = (outputblock[j]>>4) & 0xf;
2144 for (k=0; k<2; k++) {
2145 if(n[k] > 9) n[k] = ((n[k]-1)>>2);
2146 /* This is equivalent to:
2147 if(n[k]>=0xa && n[k]<=0xc) n[k] = 2;
2148 if(n[k]>=0xd && n[k]<=0xf) n[k] = 3;
2149 */
2150 }
2151 /* for v4, we keygen: *(j+(char*)&key1) = (n[1]<<4) | n[0]; */
2152 /* for v5, we just generate a string */
2153 response[2*j+0] = '0' + n[1];
2154 response[2*j+1] = '0' + n[0];
2155 /* and now, response has what we work with. */
2156 }
2157 response[8] = 0;
2158 predict_response.data = response;
2159 predict_response.length = 8;
2160 #if 0 /* for debugging, hack the output too! */
2161 sc.sam_challenge_label.data = response;
2162 sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
2163 #endif
2164 }
2165
2166 psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
2167 /* string2key on sc.sam_challenge goes in here */
2168 /* eblock is just to set the enctype */
2169 {
2170 retval = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
2171 &predict_response, 0 /* salt */,
2172 &psr.sam_key);
2173 if (retval) goto cleanup;
2174
2175 retval = encode_krb5_predicted_sam_response(&psr, &scratch);
2176 if (retval) goto cleanup;
2177
2178 {
2179 size_t enclen;
2180 krb5_enc_data tmpdata;
2181
2182 if ((retval = krb5_c_encrypt_length(context,
2183 psr_key.enctype,
2184 scratch->length, &enclen)))
2185 goto cleanup;
2186
2187 if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) {
2188 retval = ENOMEM;
2189 goto cleanup;
2190 }
2191 tmpdata.ciphertext.length = enclen;
2192
2193 if ((retval = krb5_c_encrypt(context, &psr_key,
2194 /* XXX */ 0, 0, scratch, &tmpdata)))
2195 goto cleanup;
2196
2197 sc.sam_track_id = tmpdata.ciphertext;
2198 }
2199 if (retval) goto cleanup;
2200 }
2201
2202 sc.sam_response_prompt.data = "Enter the displayed response";
2203 sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data);
2204 sc.sam_pk_for_sad.length = 0;
2205 sc.sam_nonce = 0;
2206 /* Generate checksum */
2207 /*krb5_checksum_size(context, ctype)*/
2208 /*krb5_calculate_checksum(context,ctype,in,in_length,seed,
2209 seed_length,outcksum) */
2210 /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed,
2211 seed_length) */
2212 #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */
2213 sc.sam_cksum.contents = (krb5_octet *)
2214 malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES));
2215 if (sc.sam_cksum.contents == NULL) return(ENOMEM);
2216
2217 retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES,
2218 sc.sam_challenge.data,
2219 sc.sam_challenge.length,
2220 psr.sam_key.contents, /* key */
2221 psr.sam_key.length, /* key length */
2222 &sc.sam_cksum);
2223 if (retval) { free(sc.sam_cksum.contents); return(retval); }
2224 #endif /* 0 */
2225
2226 retval = encode_krb5_sam_challenge(&sc, &scratch);
2227 if (retval) goto cleanup;
2228 pa_data->magic = KV5M_PA_DATA;
2229 pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE;
2230 pa_data->contents = (unsigned char *) scratch->data;
2231 pa_data->length = scratch->length;
2232
2233 retval = 0;
2234 break;
2235 }
2236
2237 cleanup:
2238 krb5_free_keyblock_contents(context, &encrypting_key);
2239 return retval;
2240 }
2241
2242 static krb5_error_code
verify_sam_response(krb5_context context,krb5_db_entry * client,krb5_data * req_pkt,krb5_kdc_req * request,krb5_enc_tkt_part * enc_tkt_reply,krb5_pa_data * pa,preauth_get_entry_data_proc sam_get_entry_data,void * pa_system_context,void ** pa_request_context,krb5_data ** e_data,krb5_authdata *** authz_data)2243 verify_sam_response(krb5_context context, krb5_db_entry *client,
2244 krb5_data *req_pkt,
2245 krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
2246 krb5_pa_data *pa,
2247 preauth_get_entry_data_proc sam_get_entry_data,
2248 void *pa_system_context,
2249 void **pa_request_context,
2250 krb5_data **e_data,
2251 krb5_authdata ***authz_data)
2252 {
2253 krb5_error_code retval;
2254 krb5_data scratch;
2255 krb5_sam_response *sr = 0;
2256 krb5_predicted_sam_response *psr = 0;
2257 krb5_enc_sam_response_enc *esre = 0;
2258 krb5_timestamp timenow;
2259 char *princ_req = 0, *princ_psr = 0;
2260
2261 scratch.data = (char *) pa->contents;
2262 scratch.length = pa->length;
2263
2264 if ((retval = decode_krb5_sam_response(&scratch, &sr))) {
2265 scratch.data = 0;
2266 com_err("krb5kdc", retval, gettext("decode_krb5_sam_response failed"));
2267 goto cleanup;
2268 }
2269
2270 /* XXX We can only handle the challenge/response model of SAM.
2271 See passwords-04, par 4.1, 4.2 */
2272 {
2273 krb5_enc_data tmpdata;
2274
2275 tmpdata.enctype = ENCTYPE_UNKNOWN;
2276 tmpdata.ciphertext = sr->sam_track_id;
2277
2278 scratch.length = tmpdata.ciphertext.length;
2279 if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
2280 retval = ENOMEM;
2281 goto cleanup;
2282 }
2283
2284 if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
2285 &tmpdata, &scratch))) {
2286 com_err(gettext("krb5kdc"),
2287 retval,
2288 gettext("decrypt track_id failed"));
2289 goto cleanup;
2290 }
2291 }
2292
2293 if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) {
2294 com_err(gettext("krb5kdc"), retval,
2295 gettext("decode_krb5_predicted_sam_response failed -- replay attack?"));
2296 goto cleanup;
2297 }
2298
2299 /* Replay detection */
2300 if ((retval = krb5_unparse_name(context, request->client, &princ_req)))
2301 goto cleanup;
2302 if ((retval = krb5_unparse_name(context, psr->client, &princ_psr)))
2303 goto cleanup;
2304 if (strcmp(princ_req, princ_psr) != 0) {
2305 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
2306 gettext("Principal mismatch in SAM psr! -- replay attack?"));
2307 goto cleanup;
2308 }
2309
2310 if ((retval = krb5_timeofday(context, &timenow)))
2311 goto cleanup;
2312
2313 #ifdef USE_RCACHE
2314 {
2315 krb5_donot_replay rep;
2316 extern krb5_deltat rc_lifetime;
2317 /*
2318 * Verify this response came back in a timely manner.
2319 * We do this b/c otherwise very old (expunged from the rcache)
2320 * psr's would be able to be replayed.
2321 */
2322 if (timenow - psr->stime > rc_lifetime) {
2323 com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
2324 gettext("SAM psr came back too late! -- replay attack?"));
2325 goto cleanup;
2326 }
2327
2328 /* Now check the replay cache. */
2329 rep.client = princ_psr;
2330 rep.server = "SAM/rc"; /* Should not match any principal name. */
2331 rep.ctime = psr->stime;
2332 rep.cusec = psr->susec;
2333 retval = krb5_rc_store(kdc_context, kdc_rcache, &rep);
2334 if (retval) {
2335 com_err("krb5kdc", retval, gettext("SAM psr replay attack!"));
2336 goto cleanup;
2337 }
2338 }
2339 #endif /* USE_RCACHE */
2340
2341
2342 {
2343 free(scratch.data);
2344 scratch.length = sr->sam_enc_nonce_or_ts.ciphertext.length;
2345 if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
2346 retval = ENOMEM;
2347 goto cleanup;
2348 }
2349
2350 if ((retval = krb5_c_decrypt(context, &psr->sam_key, /* XXX */ 0,
2351 0, &sr->sam_enc_nonce_or_ts, &scratch))) {
2352 com_err("krb5kdc", retval, gettext("decrypt nonce_or_ts failed"));
2353 goto cleanup;
2354 }
2355 }
2356
2357 if ((retval = decode_krb5_enc_sam_response_enc(&scratch, &esre))) {
2358 com_err("krb5kdc", retval, gettext("decode_krb5_enc_sam_response_enc failed"));
2359 goto cleanup;
2360 }
2361
2362 if (esre->sam_timestamp != sr->sam_patimestamp) {
2363 retval = KRB5KDC_ERR_PREAUTH_FAILED;
2364 goto cleanup;
2365 }
2366
2367 if (labs(timenow - sr->sam_patimestamp) > context->clockskew) {
2368 retval = KRB5KRB_AP_ERR_SKEW;
2369 goto cleanup;
2370 }
2371
2372 setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
2373
2374 cleanup:
2375 if (retval) com_err(gettext("krb5kdc"),
2376 retval,
2377 gettext("sam verify failure"));
2378 if (scratch.data) free(scratch.data);
2379 if (sr) free(sr);
2380 if (psr) free(psr);
2381 if (esre) free(esre);
2382 if (princ_psr) free(princ_psr);
2383 if (princ_req) free(princ_req);
2384
2385 return retval;
2386 }
2387