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 if (enc_tkt_part
->authorization_data
!= NULL
)
908 free(enc_tkt_part
->authorization_data
);
910 /* Install our new list */
911 enc_tkt_part
->authorization_data
= newad
;
917 * This routine is called to verify the preauthentication information
920 * Returns 0 if the pre-authentication is valid, non-zero to indicate
921 * an error code of some sort.
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
)
929 krb5_error_code retval
= 0;
930 krb5_pa_data
**padata
;
931 krb5_preauth_systems
*pa_sys
;
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;
938 krb5_authdata
**tmp_authz_data
= NULL
;
940 if (request
->padata
== 0)
943 if (make_padata_context(context
, padata_context
) != 0) {
944 return KRB5KRB_ERR_GENERIC
;
948 krb5_klog_syslog (LOG_DEBUG
, "checking padata");
950 for (padata
= request
->padata
; *padata
; padata
++) {
952 krb5_klog_syslog (LOG_DEBUG
, ".. pa_type 0x%x", (*padata
)->pa_type
);
954 if (find_pa_system((*padata
)->pa_type
, &pa_sys
))
956 if (find_pa_context(pa_sys
, *padata_context
, &pa_context
))
959 krb5_klog_syslog (LOG_DEBUG
, ".. pa_type %s", pa_sys
->name
);
961 if (pa_sys
->verify_padata
== 0)
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
);
969 emsg
= krb5_get_error_message (context
, retval
);
970 krb5_klog_syslog (LOG_INFO
, "preauth (%s) verify failure: %s",
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
;
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
;
984 use_saved_retval
= 0; /* Make sure we use the current retval */
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.
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
;
999 saved_retval
= retval
;
1000 use_saved_retval
= 1;
1002 /* discard this extra e-data from non-PA_REQUIRED module */
1003 krb5_free_data(context
, tmp_e_data
);
1009 krb5_klog_syslog (LOG_DEBUG
, ".. .. ok");
1011 /* Ignore any edata returned on success */
1012 if (tmp_e_data
!= NULL
) {
1013 krb5_free_data(context
, tmp_e_data
);
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
;
1023 if (pa_sys
->flags
& PA_SUFFICIENT
)
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
);
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 */
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
);
1045 if (use_saved_retval
!= 0)
1046 retval
= saved_retval
;
1052 /* pa system was not found, but principal doesn't require preauth */
1054 !isflagset(client
->attributes
, KRB5_KDB_REQUIRES_PRE_AUTH
) &&
1055 !isflagset(client
->attributes
, KRB5_KDB_REQUIRES_HW_AUTH
))
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
);
1063 /* The following switch statement allows us
1064 * to return some preauth system errors back to the client.
1067 case KRB5KRB_AP_ERR_BAD_INTEGRITY
:
1068 case KRB5KRB_AP_ERR_SKEW
:
1069 case KRB5KDC_ERR_ETYPE_NOSUPP
:
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: */
1092 return KRB5KDC_ERR_PREAUTH_FAILED
;
1097 * return_padata creates any necessary preauthentication
1098 * structures which should be returned by the KDC to the client
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
)
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
;
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
;
1122 for (ap
= preauth_systems
; ap
->type
!= -1; ap
++) {
1123 if (ap
->return_padata
)
1127 if ((send_pa_list
= malloc((size
+1) * sizeof(krb5_pa_data
*))) == NULL
)
1129 if ((pa_order
= malloc((size
+1) * sizeof(int))) == NULL
) {
1133 sort_pa_order(context
, request
, pa_order
);
1135 retval
= krb5_copy_keyblock_contents(context
, encrypting_key
,
1142 key_modified
= FALSE
;
1144 send_pa
= send_pa_list
;
1147 for (pa_type
= pa_order
; *pa_type
!= -1; pa_type
++) {
1148 ap
= &preauth_systems
[*pa_type
];
1150 if (original_key
.enctype
!= encrypting_key
->enctype
)
1151 key_modified
= TRUE
;
1153 if (original_key
.length
!= encrypting_key
->length
)
1154 key_modified
= TRUE
;
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
))
1161 if (ap
->return_padata
== 0)
1163 if (find_pa_context(ap
, *padata_context
, &pa_context
))
1166 if (request
->padata
) {
1167 for (padata
= request
->padata
; *padata
; padata
++) {
1168 if ((*padata
)->pa_type
== ap
->type
) {
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
,
1188 if (send_pa_list
[0]) {
1189 reply
->padata
= send_pa_list
;
1195 krb5_free_pa_data(context
, send_pa_list
);
1197 /* Solaris Kerberos */
1198 krb5_free_keyblock_contents(context
, &original_key
);
1205 enctype_requires_etype_info_2(krb5_enctype 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
:
1217 if (krb5_c_valid_enctype(enctype
))
1224 request_contains_enctype (krb5_context context
, const krb5_kdc_req
*request
,
1225 krb5_enctype enctype
)
1228 for (i
=0; i
< request
->nktypes
; i
++)
1229 if (request
->ktype
[i
] == enctype
)
1235 static krb5_error_code
1236 verify_enc_timestamp(krb5_context context
, krb5_db_entry
*client
,
1238 krb5_kdc_req
*request
, krb5_enc_tkt_part
*enc_tkt_reply
,
1240 preauth_get_entry_data_proc ets_get_entry_data
,
1241 void *pa_system_context
,
1242 void **pa_request_context
,
1244 krb5_authdata
***authz_data
)
1246 krb5_pa_enc_ts
* pa_enc
= 0;
1247 krb5_error_code retval
;
1249 krb5_data enc_ts_data
;
1250 krb5_enc_data
*enc_data
= 0;
1252 krb5_key_data
* client_key
;
1254 krb5_timestamp timenow
;
1255 krb5_error_code decrypt_err
= 0;
1257 (void) memset(&key
, 0, sizeof(krb5_keyblock
));
1258 scratch
.data
= (char *) pa
->contents
;
1259 scratch
.length
= pa
->length
;
1261 enc_ts_data
.data
= 0;
1263 if ((retval
= decode_krb5_enc_data(&scratch
, &enc_data
)) != 0)
1266 enc_ts_data
.length
= enc_data
->ciphertext
.length
;
1267 if ((enc_ts_data
.data
= (char *) malloc(enc_ts_data
.length
)) == NULL
)
1273 if ((retval
= krb5_dbe_search_enctype(context
, client
,
1274 &start
, enc_data
->enctype
,
1275 -1, 0, &client_key
)))
1278 if ((retval
= krb5_dbekd_decrypt_key_data(context
, &master_keyblock
,
1279 client_key
, &key
, NULL
)))
1282 key
.enctype
= enc_data
->enctype
;
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
);
1290 decrypt_err
= retval
;
1293 if ((retval
= decode_krb5_pa_enc_ts(&enc_ts_data
, &pa_enc
)) != 0)
1296 if ((retval
= krb5_timeofday(context
, &timenow
)) != 0)
1299 if (labs(timenow
- pa_enc
->patimestamp
) > context
->clockskew
) {
1300 retval
= KRB5KRB_AP_ERR_SKEW
;
1304 setflag(enc_tkt_reply
->flags
, TKT_FLG_PRE_AUTH
);
1310 krb5_free_data_contents(context
, &enc_data
->ciphertext
);
1313 krb5_free_data_contents(context
, &enc_ts_data
);
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
1322 if (retval
== KRB5_KDB_NO_MATCHING_KEY
&& decrypt_err
!= 0)
1323 retval
= decrypt_err
;
1327 static krb5_error_code
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
,
1334 krb5_etype_info_entry
* tmp_entry
;
1335 krb5_error_code retval
;
1337 if ((tmp_entry
= malloc(sizeof(krb5_etype_info_entry
))) == NULL
)
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
,
1352 if (etype_info2
&& client_key
->key_data_ver
> 1 &&
1353 client_key
->key_data_type
[1] == KRB5_KDB_SALTTYPE_AFS3
) {
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
) {
1363 tmp_entry
->s2kparams
.length
= 1;
1364 tmp_entry
->s2kparams
.data
[0] = 1;
1371 if (salt
.length
>= 0) {
1372 tmp_entry
->length
= salt
.length
;
1373 tmp_entry
->salt
= (unsigned char *) salt
.data
;
1381 if (tmp_entry
->s2kparams
.data
)
1382 free(tmp_entry
->s2kparams
.data
);
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.
1395 static krb5_error_code
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
)
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
;
1409 entry
= malloc((client
->n_key_data
* 2 + 1) * sizeof(krb5_etype_info_entry
*));
1415 retval
= krb5_dbe_search_enctype(context
, client
, &start
, -1,
1416 -1, 0, &client_key
);
1417 if (retval
== KRB5_KDB_NO_MATCHING_KEY
)
1421 db_etype
= client_key
->key_data_type
[0];
1422 if (db_etype
== ENCTYPE_DES_CBC_MD4
)
1423 db_etype
= ENCTYPE_DES_CBC_MD5
;
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) {
1437 * If there is a des key in the kdb, try the "similar" enctypes,
1438 * avoid duplicate entries.
1442 case ENCTYPE_DES_CBC_MD5
:
1443 db_etype
= ENCTYPE_DES_CBC_CRC
;
1445 case ENCTYPE_DES_CBC_CRC
:
1446 db_etype
= ENCTYPE_DES_CBC_MD5
;
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) {
1464 retval
= encode_krb5_etype_info2((krb5_etype_info_entry
* const*) entry
,
1466 else retval
= encode_krb5_etype_info((krb5_etype_info_entry
* const*) entry
,
1470 pa_data
->contents
= (unsigned char *)scratch
->data
;
1471 pa_data
->length
= scratch
->length
;
1478 krb5_free_etype_info(context
, entry
);
1482 static krb5_error_code
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
)
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
1496 return etype_info_helper(context
, request
, client
, server
, pa_data
, 0);
1499 static krb5_error_code
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
)
1506 return etype_info_helper( context
, request
, client
, server
, pa_data
, 1);
1509 static krb5_error_code
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
,
1519 krb5_error_code retval
;
1520 krb5_pa_data
*tmp_padata
;
1521 krb5_etype_info_entry
**entry
= NULL
;
1522 krb5_data
*scratch
= NULL
;
1525 * Skip PA-ETYPE-INFO completely if AS-REQ lists any "newer"
1529 for (i
= 0; i
< request
->nktypes
; i
++) {
1530 if (enctype_requires_etype_info_2(request
->ktype
[i
])) {
1537 tmp_padata
= malloc( sizeof(krb5_pa_data
));
1538 if (tmp_padata
== NULL
)
1541 tmp_padata
->pa_type
= KRB5_PADATA_ETYPE_INFO2
;
1543 tmp_padata
->pa_type
= KRB5_PADATA_ETYPE_INFO
;
1545 entry
= malloc(2 * sizeof(krb5_etype_info_entry
*));
1546 if (entry
== NULL
) {
1552 retval
= _make_etype_info_entry(context
, request
,
1553 client_key
, encrypting_key
->enctype
,
1554 entry
, etype_info2
);
1559 retval
= encode_krb5_etype_info2((krb5_etype_info_entry
* const*) entry
, &scratch
);
1561 retval
= encode_krb5_etype_info((krb5_etype_info_entry
* const*) entry
, &scratch
);
1565 tmp_padata
->contents
= (uchar_t
*)scratch
->data
;
1566 tmp_padata
->length
= scratch
->length
;
1567 *send_pa
= tmp_padata
;
1569 /* For cleanup - we no longer own the contents of the krb5_data
1570 * only to pointer to the krb5_data
1576 krb5_free_etype_info(context
, entry
);
1582 krb5_free_data(context
, scratch
);
1586 static krb5_error_code
1587 return_etype_info2(krb5_context context
, krb5_pa_data
* padata
,
1588 krb5_db_entry
*client
,
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
)
1598 return etype_info_as_rep_helper(context
, padata
, client
, request
, reply
,
1599 client_key
, encrypting_key
, send_pa
, 1);
1603 static krb5_error_code
1604 return_etype_info(krb5_context context
, krb5_pa_data
* padata
,
1605 krb5_db_entry
*client
,
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
)
1615 return etype_info_as_rep_helper(context
, padata
, client
, request
, reply
,
1616 client_key
, encrypting_key
, send_pa
, 0);
1619 static krb5_error_code
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
)
1628 krb5_error_code retval
;
1629 krb5_pa_data
* padata
;
1630 krb5_data
* scratch
;
1631 krb5_data salt_data
;
1634 for (i
= 0; i
< request
->nktypes
; i
++) {
1635 if (enctype_requires_etype_info_2(request
->ktype
[i
]))
1638 if (client_key
->key_data_ver
== 1 ||
1639 client_key
->key_data_type
[1] == KRB5_KDB_SALTTYPE_NORMAL
)
1642 if ((padata
= malloc(sizeof(krb5_pa_data
))) == NULL
)
1644 padata
->magic
= KV5M_PA_DATA
;
1645 padata
->pa_type
= KRB5_PADATA_PW_SALT
;
1647 switch (client_key
->key_data_type
[1]) {
1648 case KRB5_KDB_SALTTYPE_V4
:
1649 /* send an empty (V4) salt */
1650 padata
->contents
= 0;
1653 case KRB5_KDB_SALTTYPE_NOREALM
:
1654 if ((retval
= krb5_principal2salt_norealm(kdc_context
,
1658 padata
->contents
= (krb5_octet
*)salt_data
.data
;
1659 padata
->length
= salt_data
.length
;
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
) {
1673 memcpy(padata
->contents
, scratch
->data
, scratch
->length
);
1674 padata
->length
= scratch
->length
+1;
1675 padata
->contents
[scratch
->length
] = 0;
1677 case KRB5_KDB_SALTTYPE_ONLYREALM
:
1678 scratch
= krb5_princ_realm(kdc_context
, request
->client
);
1679 if ((padata
->contents
= malloc(scratch
->length
)) == NULL
) {
1683 memcpy(padata
->contents
, scratch
->data
, scratch
->length
);
1684 padata
->length
= scratch
->length
;
1686 case KRB5_KDB_SALTTYPE_SPECIAL
:
1687 if ((padata
->contents
= malloc(client_key
->key_data_length
[1]))
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];
1709 static krb5_error_code
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
)
1718 krb5_error_code retval
;
1722 krb5_sam_response
*sr
= 0;
1723 krb5_predicted_sam_response
*psr
= 0;
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
1735 scratch
.data
= (char *) in_padata
->contents
; /* SUNWresync121 XXX */
1736 scratch
.length
= in_padata
->length
;
1738 if ((retval
= decode_krb5_sam_response(&scratch
, &sr
))) {
1739 com_err("krb5kdc", retval
,
1740 gettext("return_sam_data(): decode_krb5_sam_response failed"));
1745 krb5_enc_data tmpdata
;
1747 tmpdata
.enctype
= ENCTYPE_UNKNOWN
;
1748 tmpdata
.ciphertext
= sr
->sam_track_id
;
1750 scratch
.length
= tmpdata
.ciphertext
.length
;
1751 if ((scratch
.data
= (char *) malloc(scratch
.length
)) == NULL
) {
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"));
1765 if ((retval
= decode_krb5_predicted_sam_response(&scratch
, &psr
))) {
1766 com_err("krb5kdc", retval
,
1768 "return_sam_data(): decode_krb5_predicted_sam_response failed"));
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"));
1779 if (psr
->sam_flags
& KRB5_SAM_SEND_ENCRYPTED_SAD
) {
1780 /* No key munging */
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 */
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. */
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
);
1801 for (i
= 0; i
< length
; i
++)
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;
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;
1828 com_err("krb5kdc", retval
= KRB5KDC_ERR_PREAUTH_FAILED
,
1829 gettext("Unimplemented keytype for SAM key mixing"));
1833 /* XXX Attach a useful pa_data */
1836 krb5_free_sam_response(context
, sr
);
1838 krb5_free_predicted_sam_response(context
, psr
);
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
, },
1855 static krb5_error_code
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
)
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
;
1868 krb5_data predict_response
;
1870 (void) memset(&encrypting_key
, 0, sizeof(krb5_keyblock
));
1871 (void) memset(&sc
, 0, sizeof(sc
));
1872 (void) memset(&psr
, 0, sizeof(psr
));
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.
1883 For SNK4 in particular, the key in the database is the key for
1884 the device; kadmin needs a special interface for it.
1890 krb5_db_entry assoc
;
1891 krb5_key_data
*assoc_key
;
1892 krb5_principal newp
;
1897 retval
= krb5_copy_principal(kdc_context
, request
->client
, &newp
);
1899 com_err(gettext("krb5kdc"),
1901 gettext("copying client name for preauth probe"));
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
));
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
);
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
;
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
)--;
1926 krb5_free_principal(kdc_context
, newp
);
1928 /* if sc.sam_type is set, it worked */
1930 /* so use assoc to get the key out! */
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 */
1940 krb5_unparse_name(kdc_context
, request
->client
, &sname
);
1941 com_err(gettext("krb5kdc"),
1943 gettext("snk4 finding the enctype and key <%s>"),
1948 /* convert server.key into a real key */
1949 retval
= krb5_dbekd_decrypt_key_data(kdc_context
,
1951 assoc_key
, &encrypting_key
,
1954 com_err(gettext("krb5kdc"),
1956 gettext("snk4 pulling out key entry"));
1959 /* now we can use encrypting_key... */
1962 /* SAM is not an option - so don't return as hint */
1963 return KRB5_PREAUTH_BAD_TYPE
;
1966 sc
.magic
= KV5M_SAM_CHALLENGE
;
1967 psr
.sam_flags
= sc
.sam_flags
= KRB5_SAM_USE_SAD_AS_KEY
;
1969 /* Replay prevention */
1970 if ((retval
= krb5_copy_principal(context
, request
->client
, &psr
.client
)))
1973 if ((retval
= krb5_us_timeofday(context
, &psr
.stime
, &psr
.susec
)))
1975 #endif /* USE_RCACHE */
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
);
1986 #if 0 /* Enable this to test "normal" (no flags set) mode. */
1987 psr
.sam_flags
= sc
.sam_flags
= 0;
1990 psr
.magic
= KV5M_PREDICTED_SAM_RESPONSE
;
1991 /* string2key on sc.sam_challenge goes in here */
1992 /* eblock is just to set the enctype */
1994 const krb5_enctype type
= ENCTYPE_DES_CBC_MD5
;
1996 if ((retval
= krb5_c_string_to_key(context
, type
, &sc
.sam_challenge
,
1997 0 /* salt */, &psr
.sam_key
)))
2000 if ((retval
= encode_krb5_predicted_sam_response(&psr
, &scratch
)))
2005 krb5_enc_data tmpdata
;
2007 if ((retval
= krb5_c_encrypt_length(context
,
2009 scratch
->length
, &enclen
)))
2012 if ((tmpdata
.ciphertext
.data
= (char *) malloc(enclen
)) == NULL
) {
2016 tmpdata
.ciphertext
.length
= enclen
;
2018 if ((retval
= krb5_c_encrypt(context
, &psr_key
,
2019 /* XXX */ 0, 0, scratch
, &tmpdata
)))
2022 sc
.sam_track_id
= tmpdata
.ciphertext
;
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;
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,
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
);
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 */
2047 if (retval
) { free(sc
.sam_cksum
.contents
); return(retval
); }
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
;
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
);
2063 sc
.sam_challenge_label
.data
= "Enter the following on your keypad";
2064 sc
.sam_challenge_label
.length
= strlen(sc
.sam_challenge_label
.data
);
2066 /* generate digit string, take it mod 1000000 (six digits.) */
2069 krb5_keyblock session_key
;
2070 char outputblock
[8];
2073 (void) memset(&session_key
, 0, sizeof(krb5_keyblock
));
2075 (void) memset(inputblock
, 0, 8);
2077 retval
= krb5_c_make_random_key(kdc_context
, ENCTYPE_DES_CBC_CRC
,
2081 /* random key failed */
2082 com_err(gettext("krb5kdc"),
2084 gettext("generating random challenge for preauth"));
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"));
2096 for(i
= 0; i
<6; i
++) {
2097 inputblock
[i
] = '0' + ((session_key
.contents
[i
]/2) % 10);
2099 if (session_key
.contents
)
2100 krb5_free_keyblock_contents(kdc_context
, &session_key
);
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;
2107 encrypting_key
.enctype
= ENCTYPE_DES_CBC_RAW
;
2110 com_err(gettext("krb5kdc"),
2112 gettext("snk4 processing key"));
2117 krb5_enc_data cipher
;
2120 plain
.data
= inputblock
;
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
;
2128 if ((retval
= krb5_c_encrypt(kdc_context
, &encrypting_key
,
2129 /* XXX */ 0, 0, &plain
, &cipher
))) {
2130 com_err(gettext("krb5kdc"),
2132 gettext("snk4 response generation failed"));
2137 /* now output block is the raw bits of the response; convert it
2139 for (j
=0; j
<4; j
++) {
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;
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. */
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
);
2166 psr
.magic
= KV5M_PREDICTED_SAM_RESPONSE
;
2167 /* string2key on sc.sam_challenge goes in here */
2168 /* eblock is just to set the enctype */
2170 retval
= krb5_c_string_to_key(context
, ENCTYPE_DES_CBC_MD5
,
2171 &predict_response
, 0 /* salt */,
2173 if (retval
) goto cleanup
;
2175 retval
= encode_krb5_predicted_sam_response(&psr
, &scratch
);
2176 if (retval
) goto cleanup
;
2180 krb5_enc_data tmpdata
;
2182 if ((retval
= krb5_c_encrypt_length(context
,
2184 scratch
->length
, &enclen
)))
2187 if ((tmpdata
.ciphertext
.data
= (char *) malloc(enclen
)) == NULL
) {
2191 tmpdata
.ciphertext
.length
= enclen
;
2193 if ((retval
= krb5_c_encrypt(context
, &psr_key
,
2194 /* XXX */ 0, 0, scratch
, &tmpdata
)))
2197 sc
.sam_track_id
= tmpdata
.ciphertext
;
2199 if (retval
) goto cleanup
;
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;
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,
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
);
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 */
2223 if (retval
) { free(sc
.sam_cksum
.contents
); return(retval
); }
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
;
2238 krb5_free_keyblock_contents(context
, &encrypting_key
);
2242 static krb5_error_code
2243 verify_sam_response(krb5_context context
, krb5_db_entry
*client
,
2245 krb5_kdc_req
*request
, krb5_enc_tkt_part
*enc_tkt_reply
,
2247 preauth_get_entry_data_proc sam_get_entry_data
,
2248 void *pa_system_context
,
2249 void **pa_request_context
,
2251 krb5_authdata
***authz_data
)
2253 krb5_error_code retval
;
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;
2261 scratch
.data
= (char *) pa
->contents
;
2262 scratch
.length
= pa
->length
;
2264 if ((retval
= decode_krb5_sam_response(&scratch
, &sr
))) {
2266 com_err("krb5kdc", retval
, gettext("decode_krb5_sam_response failed"));
2270 /* XXX We can only handle the challenge/response model of SAM.
2271 See passwords-04, par 4.1, 4.2 */
2273 krb5_enc_data tmpdata
;
2275 tmpdata
.enctype
= ENCTYPE_UNKNOWN
;
2276 tmpdata
.ciphertext
= sr
->sam_track_id
;
2278 scratch
.length
= tmpdata
.ciphertext
.length
;
2279 if ((scratch
.data
= (char *) malloc(scratch
.length
)) == NULL
) {
2284 if ((retval
= krb5_c_decrypt(context
, &psr_key
, /* XXX */ 0, 0,
2285 &tmpdata
, &scratch
))) {
2286 com_err(gettext("krb5kdc"),
2288 gettext("decrypt track_id failed"));
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?"));
2299 /* Replay detection */
2300 if ((retval
= krb5_unparse_name(context
, request
->client
, &princ_req
)))
2302 if ((retval
= krb5_unparse_name(context
, psr
->client
, &princ_psr
)))
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?"));
2310 if ((retval
= krb5_timeofday(context
, &timenow
)))
2315 krb5_donot_replay rep
;
2316 extern krb5_deltat rc_lifetime
;
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.
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?"));
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
);
2335 com_err("krb5kdc", retval
, gettext("SAM psr replay attack!"));
2339 #endif /* USE_RCACHE */
2344 scratch
.length
= sr
->sam_enc_nonce_or_ts
.ciphertext
.length
;
2345 if ((scratch
.data
= (char *) malloc(scratch
.length
)) == NULL
) {
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"));
2357 if ((retval
= decode_krb5_enc_sam_response_enc(&scratch
, &esre
))) {
2358 com_err("krb5kdc", retval
, gettext("decode_krb5_enc_sam_response_enc failed"));
2362 if (esre
->sam_timestamp
!= sr
->sam_patimestamp
) {
2363 retval
= KRB5KDC_ERR_PREAUTH_FAILED
;
2367 if (labs(timenow
- sr
->sam_patimestamp
) > context
->clockskew
) {
2368 retval
= KRB5KRB_AP_ERR_SKEW
;
2372 setflag(enc_tkt_reply
->flags
, TKT_FLG_HW_AUTH
);
2375 if (retval
) com_err(gettext("krb5kdc"),
2377 gettext("sam verify failure"));
2378 if (scratch
.data
) free(scratch
.data
);
2381 if (esre
) free(esre
);
2382 if (princ_psr
) free(princ_psr
);
2383 if (princ_req
) free(princ_req
);