2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
10 * Copyright 1995, 2003 by the Massachusetts Institute of Technology.
11 * All Rights Reserved.
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.
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.
32 * Preauthentication routines for the KDC.
36 * Copyright (C) 1998 by the FundsXpress, INC.
38 * All rights reserved.
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.
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.
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.
67 #include "adm_proto.h"
72 #include "preauth_plugin.h"
75 static const char *objdirs
[] = { KRB5_PLUGIN_BUNDLE_DIR
, LIBDIR
"/krb5/plugins/preauth", NULL
}; /* should be a list */
77 static const char *objdirs
[] = { LIBDIR
"/krb5/plugins/preauth", NULL
};
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 */
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
);
89 typedef struct _krb5_preauth_systems
{
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
;
102 static krb5_error_code verify_enc_timestamp
103 (krb5_context
, krb5_db_entry
*client
,
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
,
111 krb5_authdata
***authz_data
);
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
,
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
,
134 static krb5_error_code
135 return_etype_info(krb5_context
, krb5_pa_data
* padata
,
136 krb5_db_entry
*client
,
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
);
146 static krb5_error_code
147 return_etype_info2(krb5_context
, krb5_pa_data
* padata
,
148 krb5_db_entry
*client
,
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
);
158 static krb5_error_code return_pw_salt
159 (krb5_context
, krb5_pa_data
* padata
,
160 krb5_db_entry
*client
,
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
);
170 /* SAM preauth support */
171 static krb5_error_code verify_sam_response
172 (krb5_context
, krb5_db_entry
*client
,
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
,
180 krb5_authdata
***authz_data
);
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
,
188 static krb5_error_code return_sam_data
189 (krb5_context
, krb5_pa_data
* padata
,
190 krb5_db_entry
*client
,
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
);
200 static krb5_preauth_systems static_preauth_systems
[] = {
203 KRB5_PADATA_ENC_TIMESTAMP
,
209 verify_enc_timestamp
,
214 KRB5_PADATA_ETYPE_INFO
,
225 KRB5_PADATA_ETYPE_INFO2
,
237 PA_PSEUDO
, /* Don't include this in the error list */
247 KRB5_PADATA_SAM_RESPONSE
,
258 KRB5_PADATA_SAM_CHALLENGE
,
259 PA_HARDWARE
, /* causes get_preauth_hint_list to use this */
270 static krb5_preauth_systems
*preauth_systems
;
271 static int n_preauth_systems
;
272 static struct plugin_dir_handle preauth_plugins
;
275 load_preauth_plugins(krb5_context context
)
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
;
285 memset(&err
, 0, sizeof(err
));
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
;
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
;
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
)) {
317 ftable
->pa_type_list
!= NULL
&&
318 ftable
->pa_type_list
[j
] > 0;
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
);
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
);
340 for (i
= 0; i
< kdc_numrealms
; i
++) {
341 kdc_realm_names
[i
] = kdc_realmlist
[i
]->realm_name
;
343 kdc_realm_names
[i
] = NULL
;
345 /* Add the locally-supplied mechanisms to the dynamic list first. */
347 i
< sizeof(static_preauth_systems
) / sizeof(static_preauth_systems
[0]);
349 if (static_preauth_systems
[i
].type
== -1)
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
]));
361 preauth_systems
[k
].plugin_context
= plugin_context
;
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
)) {
375 plugin_context
= NULL
;
377 ftable
->pa_type_list
!= NULL
&&
378 ftable
->pa_type_list
[j
] > 0;
380 /* Try to initialize the plugin. If it fails, we'll remove it
381 * from the list of modules we'll be using. */
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
);
389 emsg
= krb5_get_error_message(context
, initerr
);
391 krb5_klog_syslog(LOG_ERR
,
392 "preauth %s failed to initialize: %s",
394 krb5_free_error_message(context
, emsg
);
396 memset(&preauth_systems
[k
], 0, sizeof(preauth_systems
[k
]));
398 break; /* skip all modules in this plugin */
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
);
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 */
412 preauth_systems
[k
].fini
= ftable
->fini_proc
;
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
;
423 krb5int_free_plugin_dir_data(preauth_plugins_ftables
);
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;
434 unload_preauth_plugins(krb5_context context
)
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
);
443 memset(&preauth_systems
[i
], 0, sizeof(preauth_systems
[i
]));
445 free(preauth_systems
);
446 preauth_systems
= NULL
;
447 n_preauth_systems
= 0;
448 krb5int_close_plugin_dirs(&preauth_plugins
);
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.
458 struct request_pa_context
{
461 krb5_preauth_systems
*pa_system
;
466 static krb5_error_code
467 make_padata_context(krb5_context context
, void **padata_context
)
470 struct request_pa_context
*ret
;
472 ret
= malloc(sizeof(*ret
));
477 ret
->n_contexts
= n_preauth_systems
;
478 ret
->contexts
= malloc(sizeof(ret
->contexts
[0]) * ret
->n_contexts
);
479 if (ret
->contexts
== NULL
) {
484 memset(ret
->contexts
, 0, sizeof(ret
->contexts
[0]) * ret
->n_contexts
);
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
;
491 *padata_context
= ret
;
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().
502 free_padata_context(krb5_context kcontext
, void **padata_context
)
504 struct request_pa_context
*context
;
505 krb5_preauth_systems
*preauth_system
;
509 if (padata_context
== NULL
)
512 context
= *padata_context
;
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
);
522 context
->contexts
[i
].pa_context
= NULL
;
526 free(context
->contexts
);
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
535 get_entry_tl_data(krb5_context context
, krb5_db_entry
*entry
,
536 krb5_int16 tl_data_type
, krb5_data
**result
)
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
) {
545 (*result
)->magic
= KV5M_DATA
;
546 (*result
)->data
= malloc(tl
->tl_data_length
);
547 if ((*result
)->data
== NULL
) {
552 memcpy((*result
)->data
, tl
->tl_data_contents
, tl
->tl_data_length
);
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.
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
567 static krb5_error_code
568 get_entry_data(krb5_context context
,
569 krb5_kdc_req
*request
, krb5_db_entry
*entry
,
577 krb5_key_data
*entry_key
;
580 case krb5plugin_preauth_entry_request_certificate
:
581 return get_entry_tl_data(context
, entry
,
582 KRB5_TL_USER_CERTIFICATE
, result
);
584 case krb5plugin_preauth_entry_max_time_skew
:
585 ret
= malloc(sizeof(krb5_data
));
588 delta
= malloc(sizeof(krb5_deltat
));
593 *delta
= context
->clockskew
;
594 ret
->data
= (char *) delta
;
595 ret
->length
= sizeof(*delta
);
599 case krb5plugin_preauth_keys
:
600 ret
= malloc(sizeof(krb5_data
));
603 keys
= malloc(sizeof(krb5_keyblock
) * (request
->nktypes
+ 1));
608 ret
->data
= (char *) keys
;
609 ret
->length
= sizeof(krb5_keyblock
) * (request
->nktypes
+ 1);
610 memset(ret
->data
, 0, ret
->length
);
612 for (i
= 0; i
< request
->nktypes
; i
++) {
614 if (krb5_dbe_find_enctype(context
, entry
, request
->ktype
[i
],
615 -1, 0, &entry_key
) != 0)
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
]));
634 case krb5plugin_preauth_request_body
:
636 encode_krb5_kdc_req_body(request
, &ret
);
641 return ASN1_PARSE_ERROR
;
649 static krb5_error_code
650 find_pa_system(int type
, krb5_preauth_systems
**preauth
)
652 krb5_preauth_systems
*ap
;
654 ap
= preauth_systems
? preauth_systems
: static_preauth_systems
;
655 while ((ap
->type
!= -1) && (ap
->type
!= type
))
658 return(KRB5_PREAUTH_BAD_TYPE
);
663 static krb5_error_code
664 find_pa_context(krb5_preauth_systems
*pa_sys
,
665 struct request_pa_context
*context
,
673 return KRB5KRB_ERR_GENERIC
;
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
;
682 return KRB5KRB_ERR_GENERIC
;
686 * Create a list of indices into the preauth_systems array, sorted by order of
690 pa_list_includes(krb5_pa_data
**pa_data
, krb5_preauthtype pa_type
)
692 while (*pa_data
!= NULL
) {
693 if ((*pa_data
)->pa_type
== pa_type
)
700 sort_pa_order(krb5_context context
, krb5_kdc_req
*request
, int *pa_order
)
702 int i
, j
, k
, n_repliers
, n_key_replacers
;
704 /* First, set up the default order. */
706 for (j
= 0; j
< n_preauth_systems
; j
++) {
707 if (preauth_systems
[j
].return_padata
!= NULL
)
711 pa_order
[n_repliers
] = -1;
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
)
719 /* If not, search for a module which does, and swap in the first one we
721 for (j
= i
+ 1; j
< n_repliers
; j
++) {
722 if (preauth_systems
[pa_order
[j
]].flags
& PA_REPLACES_KEY
) {
724 pa_order
[j
] = pa_order
[i
];
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
++) {
739 for (i
= 0; i
< n_key_replacers
; i
++) {
740 if (pa_list_includes(request
->padata
,
741 preauth_systems
[pa_order
[i
]].type
))
743 for (j
= i
+ 1; j
< n_key_replacers
; j
++) {
744 if (pa_list_includes(request
->padata
,
745 preauth_systems
[pa_order
[j
]].type
)) {
747 pa_order
[j
] = pa_order
[i
];
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
);
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
);
770 const char *missing_required_preauth(krb5_db_entry
*client
,
771 krb5_db_entry
*server
,
772 krb5_enc_tkt_part
*enc_tkt_reply
)
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.
779 * Sandia national labs wanted this for some strange reason... we
780 * leave it disabled normally.
782 if (isflagset(server
->attributes
, KRB5_KDB_PWCHANGE_SERVICE
) &&
783 isflagset(enc_tkt_reply
->flags
, TKT_FLG_PRE_AUTH
))
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 ");
796 if (isflagset(client
->attributes
, KRB5_KDB_REQUIRES_PRE_AUTH
) &&
797 !isflagset(enc_tkt_reply
->flags
, TKT_FLG_PRE_AUTH
))
798 return "NEEDED_PREAUTH";
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";
807 void get_preauth_hint_list(krb5_kdc_req
*request
, krb5_db_entry
*client
,
808 krb5_db_entry
*server
, krb5_data
*e_data
)
811 krb5_preauth_systems
*ap
;
812 krb5_pa_data
**pa_data
, **pa
;
814 krb5_error_code retval
;
816 /* Zero these out in case we need to abort */
820 hw_only
= isflagset(client
->attributes
, KRB5_KDB_REQUIRES_HW_AUTH
);
821 pa_data
= malloc(sizeof(krb5_pa_data
*) * (n_preauth_systems
+1));
824 memset(pa_data
, 0, sizeof(krb5_pa_data
*) * (n_preauth_systems
+1));
827 for (ap
= preauth_systems
; ap
->type
!= -1; ap
++) {
828 if (hw_only
&& !(ap
->flags
& PA_HARDWARE
))
830 if (ap
->flags
& PA_PSEUDO
)
832 *pa
= malloc(sizeof(krb5_pa_data
));
835 memset(*pa
, 0, sizeof(krb5_pa_data
));
836 (*pa
)->magic
= KV5M_PA_DATA
;
837 (*pa
)->pa_type
= ap
->type
;
839 retval
= (ap
->get_edata
)(kdc_context
, request
, client
, server
,
840 get_entry_data
, ap
->plugin_context
, *pa
);
842 /* just failed on this type, continue */
850 if (pa_data
[0] == 0) {
851 krb5_klog_syslog (LOG_INFO
,
852 "%spreauth required but hint list is empty",
853 hw_only
? "hw" : "");
855 retval
= encode_krb5_padata_sequence((krb5_pa_data
* const *) pa_data
,
863 krb5_free_pa_data(kdc_context
, pa_data
);
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
871 static krb5_error_code
872 add_authorization_data(krb5_enc_tkt_part
*enc_tkt_part
, krb5_authdata
**ad
)
874 krb5_authdata
**newad
;
875 int oldones
, newones
;
878 if (enc_tkt_part
== NULL
|| ad
== NULL
)
881 for (newones
= 0; ad
[newones
] != NULL
; newones
++);
883 return 0; /* nothing to add */
885 if (enc_tkt_part
->authorization_data
== NULL
)
889 enc_tkt_part
->authorization_data
[oldones
] != NULL
; oldones
++);
891 newad
= malloc((oldones
+ newones
+ 1) * sizeof(krb5_authdata
*));
895 /* Copy any existing pointers */
896 for (i
= 0; i
< oldones
; i
++)
897 newad
[i
] = enc_tkt_part
->authorization_data
[i
];
899 /* Add the new ones */
900 for (i
= 0; i
< newones
; i
++)
901 newad
[oldones
+i
] = ad
[i
];
903 /* Terminate the new list */
904 newad
[oldones
+i
] = NULL
;
906 /* Free any existing list */
907 free(enc_tkt_part
->authorization_data
);
909 /* Install our new list */
910 enc_tkt_part
->authorization_data
= newad
;
916 * This routine is called to verify the preauthentication information
919 * Returns 0 if the pre-authentication is valid, non-zero to indicate
920 * an error code of some sort.
924 check_padata (krb5_context context
, krb5_db_entry
*client
, krb5_data
*req_pkt
,
925 krb5_kdc_req
*request
, krb5_enc_tkt_part
*enc_tkt_reply
,
926 void **padata_context
, krb5_data
*e_data
)
928 krb5_error_code retval
= 0;
929 krb5_pa_data
**padata
;
930 krb5_preauth_systems
*pa_sys
;
932 krb5_data
*pa_e_data
= NULL
, *tmp_e_data
= NULL
;
933 int pa_ok
= 0, pa_found
= 0;
934 krb5_error_code saved_retval
= 0;
935 int use_saved_retval
= 0;
937 krb5_authdata
**tmp_authz_data
= NULL
;
939 if (request
->padata
== 0)
942 if (make_padata_context(context
, padata_context
) != 0) {
943 return KRB5KRB_ERR_GENERIC
;
947 krb5_klog_syslog (LOG_DEBUG
, "checking padata");
949 for (padata
= request
->padata
; *padata
; padata
++) {
951 krb5_klog_syslog (LOG_DEBUG
, ".. pa_type 0x%x", (*padata
)->pa_type
);
953 if (find_pa_system((*padata
)->pa_type
, &pa_sys
))
955 if (find_pa_context(pa_sys
, *padata_context
, &pa_context
))
958 krb5_klog_syslog (LOG_DEBUG
, ".. pa_type %s", pa_sys
->name
);
960 if (pa_sys
->verify_padata
== 0)
963 retval
= pa_sys
->verify_padata(context
, client
, req_pkt
, request
,
964 enc_tkt_reply
, *padata
,
965 get_entry_data
, pa_sys
->plugin_context
,
966 pa_context
, &tmp_e_data
, &tmp_authz_data
);
968 emsg
= krb5_get_error_message (context
, retval
);
969 krb5_klog_syslog (LOG_INFO
, "preauth (%s) verify failure: %s",
971 krb5_free_error_message (context
, emsg
);
972 /* Ignore authorization data returned from modules that fail */
973 if (tmp_authz_data
!= NULL
) {
974 krb5_free_authdata(context
, tmp_authz_data
);
975 tmp_authz_data
= NULL
;
977 if (pa_sys
->flags
& PA_REQUIRED
) {
978 /* free up any previous edata we might have been saving */
979 if (pa_e_data
!= NULL
)
980 krb5_free_data(context
, pa_e_data
);
981 pa_e_data
= tmp_e_data
;
983 use_saved_retval
= 0; /* Make sure we use the current retval */
988 * We'll return edata from either the first PA_REQUIRED module
989 * that fails, or the first non-PA_REQUIRED module that fails.
990 * Hang on to edata from the first non-PA_REQUIRED module.
991 * If we've already got one saved, simply discard this one.
993 if (tmp_e_data
!= NULL
) {
994 if (pa_e_data
== NULL
) {
995 /* save the first error code and e-data */
996 pa_e_data
= tmp_e_data
;
998 saved_retval
= retval
;
999 use_saved_retval
= 1;
1001 /* discard this extra e-data from non-PA_REQUIRED module */
1002 krb5_free_data(context
, tmp_e_data
);
1008 krb5_klog_syslog (LOG_DEBUG
, ".. .. ok");
1010 /* Ignore any edata returned on success */
1011 if (tmp_e_data
!= NULL
) {
1012 krb5_free_data(context
, tmp_e_data
);
1015 /* Add any authorization data to the ticket */
1016 if (tmp_authz_data
!= NULL
) {
1017 add_authorization_data(enc_tkt_reply
, tmp_authz_data
);
1018 free(tmp_authz_data
);
1019 tmp_authz_data
= NULL
;
1022 if (pa_sys
->flags
& PA_SUFFICIENT
)
1027 /* Don't bother copying and returning e-data on success */
1028 if (pa_ok
&& pa_e_data
!= NULL
) {
1029 krb5_free_data(context
, pa_e_data
);
1032 /* Return any e-data from the preauth that caused us to exit the loop */
1033 if (pa_e_data
!= NULL
) {
1034 e_data
->data
= malloc(pa_e_data
->length
);
1035 if (e_data
->data
== NULL
) {
1036 krb5_free_data(context
, pa_e_data
);
1037 /* Solaris Kerberos */
1040 memcpy(e_data
->data
, pa_e_data
->data
, pa_e_data
->length
);
1041 e_data
->length
= pa_e_data
->length
;
1042 krb5_free_data(context
, pa_e_data
);
1044 if (use_saved_retval
!= 0)
1045 retval
= saved_retval
;
1051 /* pa system was not found, but principal doesn't require preauth */
1053 !isflagset(client
->attributes
, KRB5_KDB_REQUIRES_PRE_AUTH
) &&
1054 !isflagset(client
->attributes
, KRB5_KDB_REQUIRES_HW_AUTH
))
1058 emsg
= krb5_get_error_message(context
, retval
);
1059 krb5_klog_syslog (LOG_INFO
, "no valid preauth type found: %s", emsg
);
1060 krb5_free_error_message(context
, emsg
);
1062 /* The following switch statement allows us
1063 * to return some preauth system errors back to the client.
1066 case KRB5KRB_AP_ERR_BAD_INTEGRITY
:
1067 case KRB5KRB_AP_ERR_SKEW
:
1068 case KRB5KDC_ERR_ETYPE_NOSUPP
:
1070 case KRB5KDC_ERR_CLIENT_NOT_TRUSTED
:
1071 case KRB5KDC_ERR_INVALID_SIG
:
1072 case KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
:
1073 case KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE
:
1074 case KRB5KDC_ERR_INVALID_CERTIFICATE
:
1075 case KRB5KDC_ERR_REVOKED_CERTIFICATE
:
1076 case KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN
:
1077 case KRB5KDC_ERR_CLIENT_NAME_MISMATCH
:
1078 case KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE
:
1079 case KRB5KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED
:
1080 case KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED
:
1081 case KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED
:
1082 case KRB5KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED
:
1083 /* earlier drafts of what became rfc 4556 */
1084 case KRB5KDC_ERR_CERTIFICATE_MISMATCH
:
1085 case KRB5KDC_ERR_KDC_NOT_TRUSTED
:
1086 case KRB5KDC_ERR_REVOCATION_STATUS_UNAVAILABLE
:
1087 /* This value is shared with KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */
1088 /* case KRB5KDC_ERR_KEY_TOO_WEAK: */
1091 return KRB5KDC_ERR_PREAUTH_FAILED
;
1096 * return_padata creates any necessary preauthentication
1097 * structures which should be returned by the KDC to the client
1100 return_padata(krb5_context context
, krb5_db_entry
*client
, krb5_data
*req_pkt
,
1101 krb5_kdc_req
*request
, krb5_kdc_rep
*reply
,
1102 krb5_key_data
*client_key
, krb5_keyblock
*encrypting_key
,
1103 void **padata_context
)
1105 krb5_error_code retval
;
1106 krb5_pa_data
** padata
;
1107 krb5_pa_data
** send_pa_list
;
1108 krb5_pa_data
** send_pa
;
1109 krb5_pa_data
* pa
= 0;
1110 krb5_preauth_systems
* ap
;
1115 krb5_boolean key_modified
;
1116 krb5_keyblock original_key
;
1117 if ((!*padata_context
)&& (make_padata_context(context
, padata_context
) != 0)) {
1118 return KRB5KRB_ERR_GENERIC
;
1121 for (ap
= preauth_systems
; ap
->type
!= -1; ap
++) {
1122 if (ap
->return_padata
)
1126 if ((send_pa_list
= malloc((size
+1) * sizeof(krb5_pa_data
*))) == NULL
)
1128 if ((pa_order
= malloc((size
+1) * sizeof(int))) == NULL
) {
1132 sort_pa_order(context
, request
, pa_order
);
1134 retval
= krb5_copy_keyblock_contents(context
, encrypting_key
,
1141 key_modified
= FALSE
;
1143 send_pa
= send_pa_list
;
1146 for (pa_type
= pa_order
; *pa_type
!= -1; pa_type
++) {
1147 ap
= &preauth_systems
[*pa_type
];
1149 if (original_key
.enctype
!= encrypting_key
->enctype
)
1150 key_modified
= TRUE
;
1152 if (original_key
.length
!= encrypting_key
->length
)
1153 key_modified
= TRUE
;
1155 if (memcmp(original_key
.contents
, encrypting_key
->contents
,
1156 original_key
.length
) != 0)
1157 key_modified
= TRUE
;
1158 if (key_modified
&& (ap
->flags
& PA_REPLACES_KEY
))
1160 if (ap
->return_padata
== 0)
1162 if (find_pa_context(ap
, *padata_context
, &pa_context
))
1165 if (request
->padata
) {
1166 for (padata
= request
->padata
; *padata
; padata
++) {
1167 if ((*padata
)->pa_type
== ap
->type
) {
1173 if ((retval
= ap
->return_padata(context
, pa
, client
, req_pkt
, request
, reply
,
1174 client_key
, encrypting_key
, send_pa
,
1175 get_entry_data
, ap
->plugin_context
,
1187 if (send_pa_list
[0]) {
1188 reply
->padata
= send_pa_list
;
1194 krb5_free_pa_data(context
, send_pa_list
);
1196 /* Solaris Kerberos */
1197 krb5_free_keyblock_contents(context
, &original_key
);
1204 enctype_requires_etype_info_2(krb5_enctype enctype
)
1207 case ENCTYPE_DES_CBC_CRC
:
1208 case ENCTYPE_DES_CBC_MD4
:
1209 case ENCTYPE_DES_CBC_MD5
:
1210 case ENCTYPE_DES3_CBC_SHA1
:
1211 case ENCTYPE_DES3_CBC_RAW
:
1212 case ENCTYPE_ARCFOUR_HMAC
:
1213 case ENCTYPE_ARCFOUR_HMAC_EXP
:
1216 if (krb5_c_valid_enctype(enctype
))
1223 request_contains_enctype (krb5_context context
, const krb5_kdc_req
*request
,
1224 krb5_enctype enctype
)
1227 for (i
=0; i
< request
->nktypes
; i
++)
1228 if (request
->ktype
[i
] == enctype
)
1234 static krb5_error_code
1235 verify_enc_timestamp(krb5_context context
, krb5_db_entry
*client
,
1237 krb5_kdc_req
*request
, krb5_enc_tkt_part
*enc_tkt_reply
,
1239 preauth_get_entry_data_proc ets_get_entry_data
,
1240 void *pa_system_context
,
1241 void **pa_request_context
,
1243 krb5_authdata
***authz_data
)
1245 krb5_pa_enc_ts
* pa_enc
= 0;
1246 krb5_error_code retval
;
1248 krb5_data enc_ts_data
;
1249 krb5_enc_data
*enc_data
= 0;
1251 krb5_key_data
* client_key
;
1253 krb5_timestamp timenow
;
1254 krb5_error_code decrypt_err
= 0;
1256 (void) memset(&key
, 0, sizeof(krb5_keyblock
));
1257 scratch
.data
= (char *) pa
->contents
;
1258 scratch
.length
= pa
->length
;
1260 enc_ts_data
.data
= 0;
1262 if ((retval
= decode_krb5_enc_data(&scratch
, &enc_data
)) != 0)
1265 enc_ts_data
.length
= enc_data
->ciphertext
.length
;
1266 if ((enc_ts_data
.data
= (char *) malloc(enc_ts_data
.length
)) == NULL
)
1272 if ((retval
= krb5_dbe_search_enctype(context
, client
,
1273 &start
, enc_data
->enctype
,
1274 -1, 0, &client_key
)))
1277 if ((retval
= krb5_dbekd_decrypt_key_data(context
, &master_keyblock
,
1278 client_key
, &key
, NULL
)))
1281 key
.enctype
= enc_data
->enctype
;
1283 retval
= krb5_c_decrypt(context
, &key
, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS
,
1284 0, enc_data
, &enc_ts_data
);
1285 krb5_free_keyblock_contents(context
, &key
);
1289 decrypt_err
= retval
;
1292 if ((retval
= decode_krb5_pa_enc_ts(&enc_ts_data
, &pa_enc
)) != 0)
1295 if ((retval
= krb5_timeofday(context
, &timenow
)) != 0)
1298 if (labs(timenow
- pa_enc
->patimestamp
) > context
->clockskew
) {
1299 retval
= KRB5KRB_AP_ERR_SKEW
;
1303 setflag(enc_tkt_reply
->flags
, TKT_FLG_PRE_AUTH
);
1309 krb5_free_data_contents(context
, &enc_data
->ciphertext
);
1312 krb5_free_data_contents(context
, &enc_ts_data
);
1315 * If we get NO_MATCHING_KEY and decryption previously failed, and
1316 * we failed to find any other keys of the correct enctype after
1317 * that failed decryption, it probably means that the password was
1320 if (retval
== KRB5_KDB_NO_MATCHING_KEY
&& decrypt_err
!= 0)
1321 retval
= decrypt_err
;
1325 static krb5_error_code
1326 _make_etype_info_entry(krb5_context context
,
1327 krb5_kdc_req
*request
, krb5_key_data
*client_key
,
1328 krb5_enctype etype
, krb5_etype_info_entry
**entry
,
1332 krb5_etype_info_entry
* tmp_entry
;
1333 krb5_error_code retval
;
1335 if ((tmp_entry
= malloc(sizeof(krb5_etype_info_entry
))) == NULL
)
1340 tmp_entry
->magic
= KV5M_ETYPE_INFO_ENTRY
;
1341 tmp_entry
->etype
= etype
;
1342 tmp_entry
->length
= KRB5_ETYPE_NO_SALT
;
1343 tmp_entry
->salt
= 0;
1344 tmp_entry
->s2kparams
.data
= NULL
;
1345 tmp_entry
->s2kparams
.length
= 0;
1346 retval
= get_salt_from_key(context
, request
->client
,
1350 if (etype_info2
&& client_key
->key_data_ver
> 1 &&
1351 client_key
->key_data_type
[1] == KRB5_KDB_SALTTYPE_AFS3
) {
1353 case ENCTYPE_DES_CBC_CRC
:
1354 case ENCTYPE_DES_CBC_MD4
:
1355 case ENCTYPE_DES_CBC_MD5
:
1356 tmp_entry
->s2kparams
.data
= malloc(1);
1357 if (tmp_entry
->s2kparams
.data
== NULL
) {
1361 tmp_entry
->s2kparams
.length
= 1;
1362 tmp_entry
->s2kparams
.data
[0] = 1;
1369 if (salt
.length
>= 0) {
1370 tmp_entry
->length
= salt
.length
;
1371 tmp_entry
->salt
= (unsigned char *) salt
.data
;
1379 free(tmp_entry
->s2kparams
.data
);
1386 * This function returns the etype information for a particular
1387 * client, to be passed back in the preauth list in the KRB_ERROR
1388 * message. It supports generating both etype_info and etype_info2
1389 * as most of the work is the same.
1391 static krb5_error_code
1392 etype_info_helper(krb5_context context
, krb5_kdc_req
*request
,
1393 krb5_db_entry
*client
, krb5_db_entry
*server
,
1394 krb5_pa_data
*pa_data
, int etype_info2
)
1396 krb5_etype_info_entry
** entry
= 0;
1397 krb5_key_data
*client_key
;
1398 krb5_error_code retval
;
1399 krb5_data
* scratch
;
1400 krb5_enctype db_etype
;
1405 entry
= malloc((client
->n_key_data
* 2 + 1) * sizeof(krb5_etype_info_entry
*));
1411 retval
= krb5_dbe_search_enctype(context
, client
, &start
, -1,
1412 -1, 0, &client_key
);
1413 if (retval
== KRB5_KDB_NO_MATCHING_KEY
)
1417 db_etype
= client_key
->key_data_type
[0];
1418 if (db_etype
== ENCTYPE_DES_CBC_MD4
)
1419 db_etype
= ENCTYPE_DES_CBC_MD5
;
1421 if (request_contains_enctype(context
, request
, db_etype
)) {
1422 assert(etype_info2
||
1423 !enctype_requires_etype_info_2(db_etype
));
1424 if ((retval
= _make_etype_info_entry(context
, request
, client_key
,
1425 db_etype
, &entry
[i
], etype_info2
)) != 0) {
1433 * If there is a des key in the kdb, try the "similar" enctypes,
1434 * avoid duplicate entries.
1438 case ENCTYPE_DES_CBC_MD5
:
1439 db_etype
= ENCTYPE_DES_CBC_CRC
;
1441 case ENCTYPE_DES_CBC_CRC
:
1442 db_etype
= ENCTYPE_DES_CBC_MD5
;
1448 if (request_contains_enctype(context
, request
, db_etype
)) {
1449 if ((retval
= _make_etype_info_entry(context
, request
,
1450 client_key
, db_etype
, &entry
[i
], etype_info2
)) != 0) {
1460 retval
= encode_krb5_etype_info2((krb5_etype_info_entry
* const*) entry
,
1462 else retval
= encode_krb5_etype_info((krb5_etype_info_entry
* const*) entry
,
1466 pa_data
->contents
= (unsigned char *)scratch
->data
;
1467 pa_data
->length
= scratch
->length
;
1474 krb5_free_etype_info(context
, entry
);
1478 static krb5_error_code
1479 get_etype_info(krb5_context context
, krb5_kdc_req
*request
,
1480 krb5_db_entry
*client
, krb5_db_entry
*server
,
1481 preauth_get_entry_data_proc etype_get_entry_data
,
1482 void *pa_system_context
,
1483 krb5_pa_data
*pa_data
)
1486 for (i
=0; i
< request
->nktypes
; i
++) {
1487 if (enctype_requires_etype_info_2(request
->ktype
[i
]))
1488 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;;;; /*Caller will
1492 return etype_info_helper(context
, request
, client
, server
, pa_data
, 0);
1495 static krb5_error_code
1496 get_etype_info2(krb5_context context
, krb5_kdc_req
*request
,
1497 krb5_db_entry
*client
, krb5_db_entry
*server
,
1498 preauth_get_entry_data_proc etype_get_entry_data
,
1499 void *pa_system_context
,
1500 krb5_pa_data
*pa_data
)
1502 return etype_info_helper( context
, request
, client
, server
, pa_data
, 1);
1505 static krb5_error_code
1506 etype_info_as_rep_helper(krb5_context context
, krb5_pa_data
* padata
,
1507 krb5_db_entry
*client
,
1508 krb5_kdc_req
*request
, krb5_kdc_rep
*reply
,
1509 krb5_key_data
*client_key
,
1510 krb5_keyblock
*encrypting_key
,
1511 krb5_pa_data
**send_pa
,
1515 krb5_error_code retval
;
1516 krb5_pa_data
*tmp_padata
;
1517 krb5_etype_info_entry
**entry
= NULL
;
1518 krb5_data
*scratch
= NULL
;
1521 * Skip PA-ETYPE-INFO completely if AS-REQ lists any "newer"
1525 for (i
= 0; i
< request
->nktypes
; i
++) {
1526 if (enctype_requires_etype_info_2(request
->ktype
[i
])) {
1533 tmp_padata
= malloc( sizeof(krb5_pa_data
));
1534 if (tmp_padata
== NULL
)
1537 tmp_padata
->pa_type
= KRB5_PADATA_ETYPE_INFO2
;
1539 tmp_padata
->pa_type
= KRB5_PADATA_ETYPE_INFO
;
1541 entry
= malloc(2 * sizeof(krb5_etype_info_entry
*));
1542 if (entry
== NULL
) {
1548 retval
= _make_etype_info_entry(context
, request
,
1549 client_key
, encrypting_key
->enctype
,
1550 entry
, etype_info2
);
1555 retval
= encode_krb5_etype_info2((krb5_etype_info_entry
* const*) entry
, &scratch
);
1557 retval
= encode_krb5_etype_info((krb5_etype_info_entry
* const*) entry
, &scratch
);
1561 tmp_padata
->contents
= (uchar_t
*)scratch
->data
;
1562 tmp_padata
->length
= scratch
->length
;
1563 *send_pa
= tmp_padata
;
1565 /* For cleanup - we no longer own the contents of the krb5_data
1566 * only to pointer to the krb5_data
1572 krb5_free_etype_info(context
, entry
);
1577 krb5_free_data(context
, scratch
);
1581 static krb5_error_code
1582 return_etype_info2(krb5_context context
, krb5_pa_data
* padata
,
1583 krb5_db_entry
*client
,
1585 krb5_kdc_req
*request
, krb5_kdc_rep
*reply
,
1586 krb5_key_data
*client_key
,
1587 krb5_keyblock
*encrypting_key
,
1588 krb5_pa_data
**send_pa
,
1589 preauth_get_entry_data_proc etype_get_entry_data
,
1590 void *pa_system_context
,
1591 void **pa_request_context
)
1593 return etype_info_as_rep_helper(context
, padata
, client
, request
, reply
,
1594 client_key
, encrypting_key
, send_pa
, 1);
1598 static krb5_error_code
1599 return_etype_info(krb5_context context
, krb5_pa_data
* padata
,
1600 krb5_db_entry
*client
,
1602 krb5_kdc_req
*request
, krb5_kdc_rep
*reply
,
1603 krb5_key_data
*client_key
,
1604 krb5_keyblock
*encrypting_key
,
1605 krb5_pa_data
**send_pa
,
1606 preauth_get_entry_data_proc etypeget_entry_data
,
1607 void *pa_system_context
,
1608 void **pa_request_context
)
1610 return etype_info_as_rep_helper(context
, padata
, client
, request
, reply
,
1611 client_key
, encrypting_key
, send_pa
, 0);
1614 static krb5_error_code
1615 return_pw_salt(krb5_context context
, krb5_pa_data
*in_padata
,
1616 krb5_db_entry
*client
, krb5_data
*req_pkt
, krb5_kdc_req
*request
,
1617 krb5_kdc_rep
*reply
, krb5_key_data
*client_key
,
1618 krb5_keyblock
*encrypting_key
, krb5_pa_data
**send_pa
,
1619 preauth_get_entry_data_proc etype_get_entry_data
,
1620 void *pa_system_context
,
1621 void **pa_request_context
)
1623 krb5_error_code retval
;
1624 krb5_pa_data
* padata
;
1625 krb5_data
* scratch
;
1626 krb5_data salt_data
;
1629 for (i
= 0; i
< request
->nktypes
; i
++) {
1630 if (enctype_requires_etype_info_2(request
->ktype
[i
]))
1633 if (client_key
->key_data_ver
== 1 ||
1634 client_key
->key_data_type
[1] == KRB5_KDB_SALTTYPE_NORMAL
)
1637 if ((padata
= malloc(sizeof(krb5_pa_data
))) == NULL
)
1639 padata
->magic
= KV5M_PA_DATA
;
1640 padata
->pa_type
= KRB5_PADATA_PW_SALT
;
1642 switch (client_key
->key_data_type
[1]) {
1643 case KRB5_KDB_SALTTYPE_V4
:
1644 /* send an empty (V4) salt */
1645 padata
->contents
= 0;
1648 case KRB5_KDB_SALTTYPE_NOREALM
:
1649 if ((retval
= krb5_principal2salt_norealm(kdc_context
,
1653 padata
->contents
= (krb5_octet
*)salt_data
.data
;
1654 padata
->length
= salt_data
.length
;
1656 case KRB5_KDB_SALTTYPE_AFS3
:
1657 /* send an AFS style realm-based salt */
1658 /* for now, just pass the realm back and let the client
1659 do the work. In the future, add a kdc configuration
1660 variable that specifies the old cell name. */
1661 padata
->pa_type
= KRB5_PADATA_AFS3_SALT
;
1662 /* it would be just like ONLYREALM, but we need to pass the 0 */
1663 scratch
= krb5_princ_realm(kdc_context
, request
->client
);
1664 if ((padata
->contents
= malloc(scratch
->length
+1)) == NULL
) {
1668 memcpy(padata
->contents
, scratch
->data
, scratch
->length
);
1669 padata
->length
= scratch
->length
+1;
1670 padata
->contents
[scratch
->length
] = 0;
1672 case KRB5_KDB_SALTTYPE_ONLYREALM
:
1673 scratch
= krb5_princ_realm(kdc_context
, request
->client
);
1674 if ((padata
->contents
= malloc(scratch
->length
)) == NULL
) {
1678 memcpy(padata
->contents
, scratch
->data
, scratch
->length
);
1679 padata
->length
= scratch
->length
;
1681 case KRB5_KDB_SALTTYPE_SPECIAL
:
1682 if ((padata
->contents
= malloc(client_key
->key_data_length
[1]))
1687 memcpy(padata
->contents
, client_key
->key_data_contents
[1],
1688 client_key
->key_data_length
[1]);
1689 padata
->length
= client_key
->key_data_length
[1];
1704 static krb5_error_code
1705 return_sam_data(krb5_context context
, krb5_pa_data
*in_padata
,
1706 krb5_db_entry
*client
, krb5_data
*req_pkt
, krb5_kdc_req
*request
,
1707 krb5_kdc_rep
*reply
, krb5_key_data
*client_key
,
1708 krb5_keyblock
*encrypting_key
, krb5_pa_data
**send_pa
,
1709 preauth_get_entry_data_proc sam_get_entry_data
,
1710 void *pa_system_context
,
1711 void **pa_request_context
)
1713 krb5_error_code retval
;
1717 krb5_sam_response
*sr
= 0;
1718 krb5_predicted_sam_response
*psr
= 0;
1724 * We start by doing the same thing verify_sam_response() does:
1725 * extract the psr from the padata (which is an sr). Nothing
1726 * here should generate errors! We've already successfully done
1730 scratch
.data
= (char *) in_padata
->contents
; /* SUNWresync121 XXX */
1731 scratch
.length
= in_padata
->length
;
1733 if ((retval
= decode_krb5_sam_response(&scratch
, &sr
))) {
1734 com_err("krb5kdc", retval
,
1735 gettext("return_sam_data(): decode_krb5_sam_response failed"));
1740 krb5_enc_data tmpdata
;
1742 tmpdata
.enctype
= ENCTYPE_UNKNOWN
;
1743 tmpdata
.ciphertext
= sr
->sam_track_id
;
1745 scratch
.length
= tmpdata
.ciphertext
.length
;
1746 if ((scratch
.data
= (char *) malloc(scratch
.length
)) == NULL
) {
1751 if ((retval
= krb5_c_decrypt(context
, &psr_key
, /* XXX */ 0, 0,
1752 &tmpdata
, &scratch
))) {
1753 com_err("krb5kdc", retval
,
1754 gettext("return_sam_data(): decrypt track_id failed"));
1760 if ((retval
= decode_krb5_predicted_sam_response(&scratch
, &psr
))) {
1761 com_err("krb5kdc", retval
,
1763 "return_sam_data(): decode_krb5_predicted_sam_response failed"));
1768 /* We could use sr->sam_flags, but it may be absent or altered. */
1769 if (psr
->sam_flags
& KRB5_SAM_MUST_PK_ENCRYPT_SAD
) {
1770 com_err("krb5kdc", retval
= KRB5KDC_ERR_PREAUTH_FAILED
,
1771 gettext("Unsupported SAM flag must-pk-encrypt-sad"));
1774 if (psr
->sam_flags
& KRB5_SAM_SEND_ENCRYPTED_SAD
) {
1775 /* No key munging */
1778 if (psr
->sam_flags
& KRB5_SAM_USE_SAD_AS_KEY
) {
1779 /* Use sam_key instead of client key */
1780 krb5_free_keyblock_contents(context
, encrypting_key
);
1781 krb5_copy_keyblock_contents(context
, &psr
->sam_key
, encrypting_key
);
1782 /* XXX Attach a useful pa_data */
1786 /* Otherwise (no flags set), we XOR the keys */
1787 /* XXX The passwords-04 draft is underspecified here wrt different
1788 key types. We will do what I hope to get into the -05 draft. */
1790 krb5_octet
*p
= encrypting_key
->contents
;
1791 krb5_octet
*q
= psr
->sam_key
.contents
;
1792 int length
= ((encrypting_key
->length
< psr
->sam_key
.length
)
1793 ? encrypting_key
->length
1794 : psr
->sam_key
.length
);
1796 for (i
= 0; i
< length
; i
++)
1800 /* Post-mixing key correction */
1801 switch (encrypting_key
->enctype
) {
1802 case ENCTYPE_DES_CBC_CRC
:
1803 case ENCTYPE_DES_CBC_MD4
:
1804 case ENCTYPE_DES_CBC_MD5
:
1805 case ENCTYPE_DES_CBC_RAW
:
1806 mit_des_fixup_key_parity(encrypting_key
->contents
);
1807 if (mit_des_is_weak_key(encrypting_key
->contents
))
1808 ((krb5_octet
*) encrypting_key
->contents
)[7] ^= 0xf0;
1811 /* XXX case ENCTYPE_DES3_CBC_MD5: listed in 1510bis-04 draft */
1812 case ENCTYPE_DES3_CBC_SHA
: /* XXX deprecated? */
1813 case ENCTYPE_DES3_CBC_RAW
:
1814 case ENCTYPE_DES3_CBC_SHA1
:
1815 for (i
= 0; i
< 3; i
++) {
1816 mit_des_fixup_key_parity(encrypting_key
->contents
+ i
* 8);
1817 if (mit_des_is_weak_key(encrypting_key
->contents
+ i
* 8))
1818 ((krb5_octet
*) encrypting_key
->contents
)[7 + i
* 8] ^= 0xf0;
1823 com_err("krb5kdc", retval
= KRB5KDC_ERR_PREAUTH_FAILED
,
1824 gettext("Unimplemented keytype for SAM key mixing"));
1828 /* XXX Attach a useful pa_data */
1831 krb5_free_sam_response(context
, sr
);
1833 krb5_free_predicted_sam_response(context
, psr
);
1841 } *sam_ptr
, sam_inst_map
[] = {
1842 #if 0 /* SUNWresync121 - unsupported hardware and kdc.log annoyance */
1843 { "SNK4", PA_SAM_TYPE_DIGI_PATH
, },
1844 { "SECURID", PA_SAM_TYPE_SECURID
, },
1845 { "GRAIL", PA_SAM_TYPE_GRAIL
, },
1850 static krb5_error_code
1851 get_sam_edata(krb5_context context
, krb5_kdc_req
*request
,
1852 krb5_db_entry
*client
, krb5_db_entry
*server
,
1853 preauth_get_entry_data_proc sam_get_entry_data
,
1854 void *pa_system_context
, krb5_pa_data
*pa_data
)
1856 krb5_error_code retval
;
1857 krb5_sam_challenge sc
;
1858 krb5_predicted_sam_response psr
;
1859 krb5_data
* scratch
;
1860 krb5_keyblock encrypting_key
;
1863 krb5_data predict_response
;
1865 (void) memset(&encrypting_key
, 0, sizeof(krb5_keyblock
));
1866 (void) memset(&sc
, 0, sizeof(sc
));
1867 (void) memset(&psr
, 0, sizeof(psr
));
1869 /* Given the client name we can figure out what type of preauth
1870 they need. The spec is currently for querying the database for
1871 names that match the types of preauth used. Later we should
1872 make this mapping show up in kdc.conf. In the meantime, we
1873 hardcode the following:
1874 /SNK4 -- Digital Pathways SNK/4 preauth.
1875 /GRAIL -- experimental preauth
1876 The first one found is used. See sam_inst_map above.
1878 For SNK4 in particular, the key in the database is the key for
1879 the device; kadmin needs a special interface for it.
1885 krb5_db_entry assoc
;
1886 krb5_key_data
*assoc_key
;
1887 krb5_principal newp
;
1892 retval
= krb5_copy_principal(kdc_context
, request
->client
, &newp
);
1894 com_err(gettext("krb5kdc"),
1896 gettext("copying client name for preauth probe"));
1900 probeslot
= krb5_princ_size(context
, newp
)++;
1901 krb5_princ_name(kdc_context
, newp
) =
1902 reallocarray(krb5_princ_name(kdc_context
, newp
),
1903 krb5_princ_size(context
, newp
), sizeof(krb5_data
));
1905 for(sam_ptr
= sam_inst_map
; sam_ptr
->name
; sam_ptr
++) {
1906 krb5_princ_component(kdc_context
,newp
,probeslot
)->data
= sam_ptr
->name
;
1907 krb5_princ_component(kdc_context
,newp
,probeslot
)->length
=
1908 strlen(sam_ptr
->name
);
1910 retval
= krb5_db_get_principal(kdc_context
, newp
, &assoc
, &npr
, (uint
*)&more
);
1911 if(!retval
&& npr
) {
1912 sc
.sam_type
= sam_ptr
->sam_type
;
1917 krb5_princ_component(kdc_context
,newp
,probeslot
)->data
= 0;
1918 krb5_princ_component(kdc_context
,newp
,probeslot
)->length
= 0;
1919 krb5_princ_size(context
, newp
)--;
1921 krb5_free_principal(kdc_context
, newp
);
1923 /* if sc.sam_type is set, it worked */
1925 /* so use assoc to get the key out! */
1927 /* here's what do_tgs_req does */
1928 retval
= krb5_dbe_find_enctype(kdc_context
, &assoc
,
1929 ENCTYPE_DES_CBC_RAW
,
1930 KRB5_KDB_SALTTYPE_NORMAL
,
1931 0, /* Get highest kvno */
1935 krb5_unparse_name(kdc_context
, request
->client
, &sname
);
1936 com_err(gettext("krb5kdc"),
1938 gettext("snk4 finding the enctype and key <%s>"),
1943 /* convert server.key into a real key */
1944 retval
= krb5_dbekd_decrypt_key_data(kdc_context
,
1946 assoc_key
, &encrypting_key
,
1949 com_err(gettext("krb5kdc"),
1951 gettext("snk4 pulling out key entry"));
1954 /* now we can use encrypting_key... */
1957 /* SAM is not an option - so don't return as hint */
1958 return KRB5_PREAUTH_BAD_TYPE
;
1961 sc
.magic
= KV5M_SAM_CHALLENGE
;
1962 psr
.sam_flags
= sc
.sam_flags
= KRB5_SAM_USE_SAD_AS_KEY
;
1964 /* Replay prevention */
1965 if ((retval
= krb5_copy_principal(context
, request
->client
, &psr
.client
)))
1968 if ((retval
= krb5_us_timeofday(context
, &psr
.stime
, &psr
.susec
)))
1970 #endif /* USE_RCACHE */
1972 switch (sc
.sam_type
) {
1973 case PA_SAM_TYPE_GRAIL
:
1974 sc
.sam_type_name
.data
= "Experimental System";
1975 sc
.sam_type_name
.length
= strlen(sc
.sam_type_name
.data
);
1976 sc
.sam_challenge_label
.data
= "experimental challenge label";
1977 sc
.sam_challenge_label
.length
= strlen(sc
.sam_challenge_label
.data
);
1978 sc
.sam_challenge
.data
= "12345";
1979 sc
.sam_challenge
.length
= strlen(sc
.sam_challenge
.data
);
1981 #if 0 /* Enable this to test "normal" (no flags set) mode. */
1982 psr
.sam_flags
= sc
.sam_flags
= 0;
1985 psr
.magic
= KV5M_PREDICTED_SAM_RESPONSE
;
1986 /* string2key on sc.sam_challenge goes in here */
1987 /* eblock is just to set the enctype */
1989 const krb5_enctype type
= ENCTYPE_DES_CBC_MD5
;
1991 if ((retval
= krb5_c_string_to_key(context
, type
, &sc
.sam_challenge
,
1992 0 /* salt */, &psr
.sam_key
)))
1995 if ((retval
= encode_krb5_predicted_sam_response(&psr
, &scratch
)))
2000 krb5_enc_data tmpdata
;
2002 if ((retval
= krb5_c_encrypt_length(context
,
2004 scratch
->length
, &enclen
)))
2007 if ((tmpdata
.ciphertext
.data
= (char *) malloc(enclen
)) == NULL
) {
2011 tmpdata
.ciphertext
.length
= enclen
;
2013 if ((retval
= krb5_c_encrypt(context
, &psr_key
,
2014 /* XXX */ 0, 0, scratch
, &tmpdata
)))
2017 sc
.sam_track_id
= tmpdata
.ciphertext
;
2021 sc
.sam_response_prompt
.data
= "response prompt";
2022 sc
.sam_response_prompt
.length
= strlen(sc
.sam_response_prompt
.data
);
2023 sc
.sam_pk_for_sad
.length
= 0;
2025 /* Generate checksum */
2026 /*krb5_checksum_size(context, ctype)*/
2027 /*krb5_calculate_checksum(context,ctype,in,in_length,seed,
2028 seed_length,outcksum) */
2029 /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed,
2031 #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */
2032 sc
.sam_cksum
.contents
= (krb5_octet
*)
2033 malloc(krb5_checksum_size(context
, CKSUMTYPE_RSA_MD5_DES
));
2034 if (sc
.sam_cksum
.contents
== NULL
) return(ENOMEM
);
2036 retval
= krb5_calculate_checksum(context
, CKSUMTYPE_RSA_MD5_DES
,
2037 sc
.sam_challenge
.data
,
2038 sc
.sam_challenge
.length
,
2039 psr
.sam_key
.contents
, /* key */
2040 psr
.sam_key
.length
, /* key length */
2042 if (retval
) { free(sc
.sam_cksum
.contents
); return(retval
); }
2045 retval
= encode_krb5_sam_challenge(&sc
, &scratch
);
2046 if (retval
) goto cleanup
;
2047 pa_data
->magic
= KV5M_PA_DATA
;
2048 pa_data
->pa_type
= KRB5_PADATA_SAM_CHALLENGE
;
2049 pa_data
->contents
= (unsigned char *) scratch
->data
;
2050 pa_data
->length
= scratch
->length
;
2054 case PA_SAM_TYPE_DIGI_PATH
:
2055 sc
.sam_type_name
.data
= "Digital Pathways";
2056 sc
.sam_type_name
.length
= strlen(sc
.sam_type_name
.data
);
2058 sc
.sam_challenge_label
.data
= "Enter the following on your keypad";
2059 sc
.sam_challenge_label
.length
= strlen(sc
.sam_challenge_label
.data
);
2061 /* generate digit string, take it mod 1000000 (six digits.) */
2064 krb5_keyblock session_key
;
2065 char outputblock
[8];
2068 (void) memset(&session_key
, 0, sizeof(krb5_keyblock
));
2070 (void) memset(inputblock
, 0, 8);
2072 retval
= krb5_c_make_random_key(kdc_context
, ENCTYPE_DES_CBC_CRC
,
2076 /* random key failed */
2077 com_err(gettext("krb5kdc"),
2079 gettext("generating random challenge for preauth"));
2082 /* now session_key has a key which we can pick bits out of */
2083 /* we need six decimal digits. Grab 6 bytes, div 2, mod 10 each. */
2084 if (session_key
.length
!= 8) {
2085 retval
= KRB5KDC_ERR_ETYPE_NOSUPP
,
2086 com_err(gettext("krb5kdc"),
2087 retval
= KRB5KDC_ERR_ETYPE_NOSUPP
,
2088 gettext("keytype didn't match code expectations"));
2091 for(i
= 0; i
<6; i
++) {
2092 inputblock
[i
] = '0' + ((session_key
.contents
[i
]/2) % 10);
2094 if (session_key
.contents
)
2095 krb5_free_keyblock_contents(kdc_context
, &session_key
);
2097 /* retval = krb5_finish_key(kdc_context, &eblock); */
2098 /* now we have inputblock containing the 8 byte input to DES... */
2099 sc
.sam_challenge
.data
= inputblock
;
2100 sc
.sam_challenge
.length
= 6;
2102 encrypting_key
.enctype
= ENCTYPE_DES_CBC_RAW
;
2105 com_err(gettext("krb5kdc"),
2107 gettext("snk4 processing key"));
2112 krb5_enc_data cipher
;
2115 plain
.data
= inputblock
;
2117 /* XXX I know this is enough because of the fixed raw enctype.
2118 if it's not, the underlying code will return a reasonable
2119 error, which should never happen */
2120 cipher
.ciphertext
.length
= 8;
2121 cipher
.ciphertext
.data
= outputblock
;
2123 if ((retval
= krb5_c_encrypt(kdc_context
, &encrypting_key
,
2124 /* XXX */ 0, 0, &plain
, &cipher
))) {
2125 com_err(gettext("krb5kdc"),
2127 gettext("snk4 response generation failed"));
2132 /* now output block is the raw bits of the response; convert it
2134 for (j
=0; j
<4; j
++) {
2137 n
[0] = outputblock
[j
] & 0xf;
2138 n
[1] = (outputblock
[j
]>>4) & 0xf;
2139 for (k
=0; k
<2; k
++) {
2140 if(n
[k
] > 9) n
[k
] = ((n
[k
]-1)>>2);
2141 /* This is equivalent to:
2142 if(n[k]>=0xa && n[k]<=0xc) n[k] = 2;
2143 if(n[k]>=0xd && n[k]<=0xf) n[k] = 3;
2146 /* for v4, we keygen: *(j+(char*)&key1) = (n[1]<<4) | n[0]; */
2147 /* for v5, we just generate a string */
2148 response
[2*j
+0] = '0' + n
[1];
2149 response
[2*j
+1] = '0' + n
[0];
2150 /* and now, response has what we work with. */
2153 predict_response
.data
= response
;
2154 predict_response
.length
= 8;
2155 #if 0 /* for debugging, hack the output too! */
2156 sc
.sam_challenge_label
.data
= response
;
2157 sc
.sam_challenge_label
.length
= strlen(sc
.sam_challenge_label
.data
);
2161 psr
.magic
= KV5M_PREDICTED_SAM_RESPONSE
;
2162 /* string2key on sc.sam_challenge goes in here */
2163 /* eblock is just to set the enctype */
2165 retval
= krb5_c_string_to_key(context
, ENCTYPE_DES_CBC_MD5
,
2166 &predict_response
, 0 /* salt */,
2168 if (retval
) goto cleanup
;
2170 retval
= encode_krb5_predicted_sam_response(&psr
, &scratch
);
2171 if (retval
) goto cleanup
;
2175 krb5_enc_data tmpdata
;
2177 if ((retval
= krb5_c_encrypt_length(context
,
2179 scratch
->length
, &enclen
)))
2182 if ((tmpdata
.ciphertext
.data
= (char *) malloc(enclen
)) == NULL
) {
2186 tmpdata
.ciphertext
.length
= enclen
;
2188 if ((retval
= krb5_c_encrypt(context
, &psr_key
,
2189 /* XXX */ 0, 0, scratch
, &tmpdata
)))
2192 sc
.sam_track_id
= tmpdata
.ciphertext
;
2194 if (retval
) goto cleanup
;
2197 sc
.sam_response_prompt
.data
= "Enter the displayed response";
2198 sc
.sam_response_prompt
.length
= strlen(sc
.sam_response_prompt
.data
);
2199 sc
.sam_pk_for_sad
.length
= 0;
2201 /* Generate checksum */
2202 /*krb5_checksum_size(context, ctype)*/
2203 /*krb5_calculate_checksum(context,ctype,in,in_length,seed,
2204 seed_length,outcksum) */
2205 /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed,
2207 #if 0 /* XXX a) glue appears broken; b) this gives up the SAD */
2208 sc
.sam_cksum
.contents
= (krb5_octet
*)
2209 malloc(krb5_checksum_size(context
, CKSUMTYPE_RSA_MD5_DES
));
2210 if (sc
.sam_cksum
.contents
== NULL
) return(ENOMEM
);
2212 retval
= krb5_calculate_checksum(context
, CKSUMTYPE_RSA_MD5_DES
,
2213 sc
.sam_challenge
.data
,
2214 sc
.sam_challenge
.length
,
2215 psr
.sam_key
.contents
, /* key */
2216 psr
.sam_key
.length
, /* key length */
2218 if (retval
) { free(sc
.sam_cksum
.contents
); return(retval
); }
2221 retval
= encode_krb5_sam_challenge(&sc
, &scratch
);
2222 if (retval
) goto cleanup
;
2223 pa_data
->magic
= KV5M_PA_DATA
;
2224 pa_data
->pa_type
= KRB5_PADATA_SAM_CHALLENGE
;
2225 pa_data
->contents
= (unsigned char *) scratch
->data
;
2226 pa_data
->length
= scratch
->length
;
2233 krb5_free_keyblock_contents(context
, &encrypting_key
);
2237 static krb5_error_code
2238 verify_sam_response(krb5_context context
, krb5_db_entry
*client
,
2240 krb5_kdc_req
*request
, krb5_enc_tkt_part
*enc_tkt_reply
,
2242 preauth_get_entry_data_proc sam_get_entry_data
,
2243 void *pa_system_context
,
2244 void **pa_request_context
,
2246 krb5_authdata
***authz_data
)
2248 krb5_error_code retval
;
2250 krb5_sam_response
*sr
= 0;
2251 krb5_predicted_sam_response
*psr
= 0;
2252 krb5_enc_sam_response_enc
*esre
= 0;
2253 krb5_timestamp timenow
;
2254 char *princ_req
= 0, *princ_psr
= 0;
2256 scratch
.data
= (char *) pa
->contents
;
2257 scratch
.length
= pa
->length
;
2259 if ((retval
= decode_krb5_sam_response(&scratch
, &sr
))) {
2261 com_err("krb5kdc", retval
, gettext("decode_krb5_sam_response failed"));
2265 /* XXX We can only handle the challenge/response model of SAM.
2266 See passwords-04, par 4.1, 4.2 */
2268 krb5_enc_data tmpdata
;
2270 tmpdata
.enctype
= ENCTYPE_UNKNOWN
;
2271 tmpdata
.ciphertext
= sr
->sam_track_id
;
2273 scratch
.length
= tmpdata
.ciphertext
.length
;
2274 if ((scratch
.data
= (char *) malloc(scratch
.length
)) == NULL
) {
2279 if ((retval
= krb5_c_decrypt(context
, &psr_key
, /* XXX */ 0, 0,
2280 &tmpdata
, &scratch
))) {
2281 com_err(gettext("krb5kdc"),
2283 gettext("decrypt track_id failed"));
2288 if ((retval
= decode_krb5_predicted_sam_response(&scratch
, &psr
))) {
2289 com_err(gettext("krb5kdc"), retval
,
2290 gettext("decode_krb5_predicted_sam_response failed -- replay attack?"));
2294 /* Replay detection */
2295 if ((retval
= krb5_unparse_name(context
, request
->client
, &princ_req
)))
2297 if ((retval
= krb5_unparse_name(context
, psr
->client
, &princ_psr
)))
2299 if (strcmp(princ_req
, princ_psr
) != 0) {
2300 com_err("krb5kdc", retval
= KRB5KDC_ERR_PREAUTH_FAILED
,
2301 gettext("Principal mismatch in SAM psr! -- replay attack?"));
2305 if ((retval
= krb5_timeofday(context
, &timenow
)))
2310 krb5_donot_replay rep
;
2311 extern krb5_deltat rc_lifetime
;
2313 * Verify this response came back in a timely manner.
2314 * We do this b/c otherwise very old (expunged from the rcache)
2315 * psr's would be able to be replayed.
2317 if (timenow
- psr
->stime
> rc_lifetime
) {
2318 com_err("krb5kdc", retval
= KRB5KDC_ERR_PREAUTH_FAILED
,
2319 gettext("SAM psr came back too late! -- replay attack?"));
2323 /* Now check the replay cache. */
2324 rep
.client
= princ_psr
;
2325 rep
.server
= "SAM/rc"; /* Should not match any principal name. */
2326 rep
.ctime
= psr
->stime
;
2327 rep
.cusec
= psr
->susec
;
2328 retval
= krb5_rc_store(kdc_context
, kdc_rcache
, &rep
);
2330 com_err("krb5kdc", retval
, gettext("SAM psr replay attack!"));
2334 #endif /* USE_RCACHE */
2339 scratch
.length
= sr
->sam_enc_nonce_or_ts
.ciphertext
.length
;
2340 if ((scratch
.data
= (char *) malloc(scratch
.length
)) == NULL
) {
2345 if ((retval
= krb5_c_decrypt(context
, &psr
->sam_key
, /* XXX */ 0,
2346 0, &sr
->sam_enc_nonce_or_ts
, &scratch
))) {
2347 com_err("krb5kdc", retval
, gettext("decrypt nonce_or_ts failed"));
2352 if ((retval
= decode_krb5_enc_sam_response_enc(&scratch
, &esre
))) {
2353 com_err("krb5kdc", retval
, gettext("decode_krb5_enc_sam_response_enc failed"));
2357 if (esre
->sam_timestamp
!= sr
->sam_patimestamp
) {
2358 retval
= KRB5KDC_ERR_PREAUTH_FAILED
;
2362 if (labs(timenow
- sr
->sam_patimestamp
) > context
->clockskew
) {
2363 retval
= KRB5KRB_AP_ERR_SKEW
;
2367 setflag(enc_tkt_reply
->flags
, TKT_FLG_HW_AUTH
);
2370 if (retval
) com_err(gettext("krb5kdc"),
2372 gettext("sam verify failure"));