1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* plugins/preauth/securid_sam2/securid2.c */
3 /*
4 * Copyright (C) 2010 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26 /*
27 * Copyright (c) 2002 Naval Research Laboratory (NRL/CCS)
28 *
29 * Permission to use, copy, modify and distribute this software and its
30 * documentation is hereby granted, provided that both the copyright
31 * notice and this permission notice appear in all copies of the software,
32 * derivative works or modified versions, and any portions thereof.
33 *
34 * NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
35 * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
36 * RESULTING FROM THE USE OF THIS SOFTWARE.
37 */
38
39 #ifdef ARL_SECURID_PREAUTH
40
41 #include "k5-int.h"
42 #include <kdb.h>
43 #include <stdio.h>
44 #include <adm_proto.h>
45 #include <syslog.h>
46 #include <acexport.h>
47 #include <sdi_defs.h>
48 #include "extern.h"
49
50 #define KRB5_SAM_SECURID_NEXT_CHALLENGE_MAGIC 0x5ec1d000
51 struct securid_track_data {
52 SDI_HANDLE handle;
53 char state;
54 char passcode[LENPRNST+1];
55 long hostid;
56 };
57
58 #define SECURID_STATE_NEW_PIN 1 /* Ask for a new pin */
59 #define SECURID_STATE_NEW_PIN_AGAIN 2 /* Ask for new pin again */
60 #define SECURID_STATE_NEXT_CODE 3 /* Ask for the next pin code */
61 #define SECURID_STATE_INITIAL 4
62
63 static char *PASSCODE_message = "SecurID Passcode";
64 static char *NEXT_PASSCODE_message = "Next Passcode";
65 static char *NEW_PIN_AGAIN_message = "New PIN Again";
66 static char PIN_message[64]; /* Max length should be 50 chars */
67
68 /*
69 * krb5_error_code get_securid_key():
70 * inputs: context: from KDC process
71 * client: database entry of client executing
72 * SecurID SAM preauthentication
73 * outputs: client_securid_key: pointer to krb5_keyblock
74 * which is key for the client's SecurID
75 * database entry.
76 * returns: 0 on success
77 * KRB5 error codes otherwise
78 *
79 * builds principal name with final instance of "SECURID" and
80 * finds the database entry, decrypts the key out of the database
81 * and passes the key back to the calling process
82 */
83
84 static krb5_error_code
get_securid_key(krb5_context context,krb5_db_entry * client,krb5_keyblock * client_securid_key)85 get_securid_key(krb5_context context, krb5_db_entry *client,
86 krb5_keyblock *client_securid_key)
87 {
88 krb5_db_entry *sam_securid_entry = NULL;
89 krb5_key_data *client_securid_key_data = NULL;
90 int sam_type = PA_SAM_TYPE_SECURID;
91 krb5_error_code retval = 0;
92
93 if (!client_securid_key)
94 return KRB5_PREAUTH_NO_KEY;
95
96 retval = sam_get_db_entry(context, client->princ,
97 &sam_type, &sam_securid_entry);
98 if (retval)
99 return KRB5_PREAUTH_NO_KEY;
100
101 /* Find key with key_type = salt_type = kvno = -1. This finds the */
102 /* latest kvno in the list. */
103
104 retval = krb5_dbe_find_enctype(context, sam_securid_entry,
105 -1, -1, -1, &client_securid_key_data);
106 if (retval) {
107 com_err("krb5kdc", retval,
108 "while getting key from client's SAM SecurID entry");
109 goto cleanup;
110 }
111 retval = krb5_dbe_decrypt_key_data(context, NULL, client_securid_key_data,
112 client_securid_key, NULL);
113 if (retval) {
114 com_err("krb5kdc", retval,
115 "while decrypting key from client's SAM SecurID entry");
116 goto cleanup;
117 }
118 cleanup:
119 if (sam_securid_entry)
120 krb5_db_free_principal(context, sam_securid_entry);
121 return retval;
122 }
123
124 static krb5_error_code
securid_decrypt_track_data_2(krb5_context context,krb5_db_entry * client,krb5_data * enc_track_data,krb5_data * output)125 securid_decrypt_track_data_2(krb5_context context, krb5_db_entry *client,
126 krb5_data *enc_track_data, krb5_data *output)
127 {
128 krb5_error_code retval;
129 krb5_keyblock sam_key;
130 krb5_enc_data tmp_enc_data;
131 sam_key.contents = NULL;
132
133 retval = get_securid_key(context, client, &sam_key);
134 if (retval != 0)
135 return retval;
136
137 tmp_enc_data.ciphertext = *enc_track_data;
138 tmp_enc_data.enctype = ENCTYPE_UNKNOWN;
139 tmp_enc_data.kvno = 0;
140
141 output->length = tmp_enc_data.ciphertext.length;
142 free(output->data);
143 output->data = k5alloc(output->length, &retval);
144 if (output->data == NULL)
145 goto cleanup;
146 retval = krb5_c_decrypt(context, &sam_key,
147 KRB5_KEYUSAGE_PA_SAM_CHALLENGE_TRACKID, 0,
148 &tmp_enc_data, output);
149 cleanup:
150 krb5_free_keyblock_contents(context, &sam_key);
151
152 if (retval) {
153 output->length = 0;
154 free(output->data);
155 output->data = NULL;
156 return retval;
157 }
158
159 return 0;
160 }
161
162 static krb5_error_code
securid_encrypt_track_data_2(krb5_context context,krb5_db_entry * client,krb5_data * track_data,krb5_data * output)163 securid_encrypt_track_data_2(krb5_context context, krb5_db_entry *client,
164 krb5_data *track_data, krb5_data *output)
165 {
166 krb5_error_code retval;
167 size_t olen;
168 krb5_keyblock sam_key;
169 krb5_enc_data tmp_enc_data;
170
171 output->data = NULL;
172
173 retval = get_securid_key(context,client, &sam_key);
174 if (retval != 0)
175 return retval;
176
177 retval = krb5_c_encrypt_length(context, sam_key.enctype,
178 track_data->length, &olen);
179 if (retval != 0)
180 goto cleanup;
181 assert(olen <= 65536);
182 output->length = olen;
183 output->data = k5alloc(output->length, &retval);
184 if (retval)
185 goto cleanup;
186 tmp_enc_data.ciphertext = *output;
187 tmp_enc_data.enctype = sam_key.enctype;
188 tmp_enc_data.kvno = 0;
189
190 retval = krb5_c_encrypt(context, &sam_key,
191 KRB5_KEYUSAGE_PA_SAM_CHALLENGE_TRACKID, 0,
192 track_data, &tmp_enc_data);
193 cleanup:
194 krb5_free_keyblock_contents(context, &sam_key);
195
196 if (retval) {
197 output->length = 0;
198 free(output->data);
199 output->data = NULL;
200 return retval;
201 }
202 return 0;
203 }
204
205
206 krb5_error_code
get_securid_edata_2(krb5_context context,krb5_db_entry * client,krb5_keyblock * client_key,krb5_sam_challenge_2 * sc2)207 get_securid_edata_2(krb5_context context, krb5_db_entry *client,
208 krb5_keyblock *client_key, krb5_sam_challenge_2 *sc2)
209 {
210 krb5_error_code retval;
211 krb5_data scratch, track_id = empty_data();
212 char *user = NULL;
213 char *def_user = "<unknown user>";
214 struct securid_track_data sid_track_data;
215 krb5_data tmp_data;
216 krb5_sam_challenge_2_body sc2b;
217
218 scratch.data = NULL;
219
220 retval = krb5_unparse_name(context, client->princ, &user);
221 if (retval)
222 goto cleanup;
223
224 memset(&sc2b, 0, sizeof(sc2b));
225 sc2b.magic = KV5M_SAM_CHALLENGE_2;
226 sc2b.sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD;
227 sc2b.sam_type_name.length = 0;
228 sc2b.sam_challenge_label.length = 0;
229 sc2b.sam_challenge.length = 0;
230 sc2b.sam_response_prompt.data = PASSCODE_message;
231 sc2b.sam_response_prompt.length = strlen(sc2b.sam_response_prompt.data);
232 sc2b.sam_pk_for_sad.length = 0;
233 sc2b.sam_type = PA_SAM_TYPE_SECURID;
234
235 sid_track_data.state = SECURID_STATE_INITIAL;
236 sid_track_data.hostid = gethostid();
237 tmp_data.data = (char *)&sid_track_data;
238 tmp_data.length = sizeof(sid_track_data);
239 retval = securid_encrypt_track_data_2(context, client, &tmp_data,
240 &track_id);
241 if (retval != 0) {
242 com_err("krb5kdc", retval, "while encrypting nonce track data");
243 goto cleanup;
244 }
245 sc2b.sam_track_id = track_id;
246
247 scratch.data = (char *)&sc2b.sam_nonce;
248 scratch.length = sizeof(sc2b.sam_nonce);
249 retval = krb5_c_random_make_octets(context, &scratch);
250 if (retval) {
251 com_err("krb5kdc", retval,
252 "while generating nonce data in get_securid_edata_2 (%s)",
253 user ? user : def_user);
254 goto cleanup;
255 }
256
257 /* Get the client's key */
258 sc2b.sam_etype = client_key->enctype;
259
260 retval = sam_make_challenge(context, &sc2b, client_key, sc2);
261 if (retval) {
262 com_err("krb5kdc", retval,
263 "while making SAM_CHALLENGE_2 checksum (%s)",
264 user ? user : def_user);
265 }
266
267 cleanup:
268 free(user);
269 krb5_free_data_contents(context, &track_id);
270 return retval;
271 }
272
273 krb5_error_code
verify_securid_data_2(krb5_context context,krb5_db_entry * client,krb5_sam_response_2 * sr2,krb5_enc_tkt_part * enc_tkt_reply,krb5_pa_data * pa,krb5_sam_challenge_2 ** sc2_out)274 verify_securid_data_2(krb5_context context, krb5_db_entry *client,
275 krb5_sam_response_2 *sr2,
276 krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa,
277 krb5_sam_challenge_2 **sc2_out)
278 {
279 krb5_error_code retval;
280 int new_pin = 0;
281 krb5_key_data *client_key_data = NULL;
282 krb5_keyblock client_key;
283 krb5_data scratch;
284 krb5_enc_sam_response_enc_2 *esre2 = NULL;
285 struct securid_track_data sid_track_data, *trackp = NULL;
286 krb5_data tmp_data;
287 SDI_HANDLE sd_handle = SDI_HANDLE_NONE;
288 krb5_sam_challenge_2 *sc2p = NULL;
289 char *cp, *user = NULL;
290 char *securid_user = NULL;
291 char passcode[LENPRNST+1];
292 char max_pin_len, min_pin_len, alpha_pin;
293
294 memset(&client_key, 0, sizeof(client_key));
295 memset(&scratch, 0, sizeof(scratch));
296 *sc2_out = NULL;
297
298 retval = krb5_unparse_name(context, client->princ, &user);
299 if (retval != 0) {
300 com_err("krb5kdc", retval,
301 "while unparsing client name in verify_securid_data_2");
302 return retval;
303 }
304
305 if ((sr2->sam_enc_nonce_or_sad.ciphertext.data == NULL) ||
306 (sr2->sam_enc_nonce_or_sad.ciphertext.length <= 0)) {
307 retval = KRB5KDC_ERR_PREAUTH_FAILED;
308 k5_setmsg(context, retval,
309 "No preauth data supplied in verify_securid_data_2 (%s)",
310 user);
311 goto cleanup;
312 }
313
314 retval = krb5_dbe_find_enctype(context, client,
315 sr2->sam_enc_nonce_or_sad.enctype, -1,
316 sr2->sam_enc_nonce_or_sad.kvno,
317 &client_key_data);
318 if (retval) {
319 com_err("krb5kdc", retval,
320 "while getting client key in verify_securid_data_2 (%s)",
321 user);
322 goto cleanup;
323 }
324
325 retval = krb5_dbe_decrypt_key_data(context, NULL, client_key_data,
326 &client_key, NULL);
327 if (retval != 0) {
328 com_err("krb5kdc", retval,
329 "while decrypting client key in verify_securid_data_2 (%s)",
330 user);
331 goto cleanup;
332 }
333
334 scratch.length = sr2->sam_enc_nonce_or_sad.ciphertext.length;
335 scratch.data = k5alloc(scratch.length, &retval);
336 if (retval)
337 goto cleanup;
338 retval = krb5_c_decrypt(context, &client_key,
339 KRB5_KEYUSAGE_PA_SAM_RESPONSE, 0,
340 &sr2->sam_enc_nonce_or_sad, &scratch);
341 if (retval) {
342 com_err("krb5kdc", retval,
343 "while decrypting SAD in verify_securid_data_2 (%s)", user);
344 goto cleanup;
345 }
346
347 retval = decode_krb5_enc_sam_response_enc_2(&scratch, &esre2);
348 if (retval) {
349 com_err("krb5kdc", retval,
350 "while decoding SAD in verify_securid_data_2 (%s)", user);
351 esre2 = NULL;
352 goto cleanup;
353 }
354
355 if (sr2->sam_nonce != esre2->sam_nonce) {
356 com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED,
357 "while checking nonce in verify_securid_data_2 (%s)", user);
358 retval = KRB5KDC_ERR_PREAUTH_FAILED;
359 goto cleanup;
360 }
361
362 if (esre2->sam_sad.length == 0 || esre2->sam_sad.data == NULL) {
363 com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED,
364 "No SecurID passcode in verify_securid_data_2 (%s)", user);
365 retval = KRB5KDC_ERR_PREAUTH_FAILED;
366 goto cleanup;
367 }
368
369 /* Copy out SAD to null-terminated buffer */
370 memset(passcode, 0, sizeof(passcode));
371 if (esre2->sam_sad.length > (sizeof(passcode) - 1)) {
372 retval = KRB5KDC_ERR_PREAUTH_FAILED;
373 com_err("krb5kdc", retval,
374 "SecurID passcode/PIN too long (%d bytes) in "
375 "verify_securid_data_2 (%s)",
376 esre2->sam_sad.length, user);
377 goto cleanup;
378 }
379 if (esre2->sam_sad.length > 0)
380 memcpy(passcode, esre2->sam_sad.data, esre2->sam_sad.length);
381
382 securid_user = strdup(user);
383 if (!securid_user) {
384 retval = ENOMEM;
385 com_err("krb5kdc", ENOMEM,
386 "while copying user name in verify_securid_data_2 (%s)", user);
387 goto cleanup;
388 }
389 cp = strchr(securid_user, '@');
390 if (cp != NULL)
391 *cp = '\0';
392
393 /* Check for any track_id data that may have state from a previous attempt
394 * at SecurID authentication. */
395
396 if (sr2->sam_track_id.data && (sr2->sam_track_id.length > 0)) {
397 krb5_data track_id_data;
398
399 memset(&track_id_data, 0, sizeof(track_id_data));
400 retval = securid_decrypt_track_data_2(context, client,
401 &sr2->sam_track_id,
402 &track_id_data);
403 if (retval) {
404 com_err("krb5kdc", retval,
405 "while decrypting SecurID trackID in "
406 "verify_securid_data_2 (%s)", user);
407 goto cleanup;
408 }
409 if (track_id_data.length < sizeof (struct securid_track_data)) {
410 retval = KRB5KDC_ERR_PREAUTH_FAILED;
411 com_err("krb5kdc", retval, "Length of track data incorrect");
412 goto cleanup;
413 }
414 trackp = (struct securid_track_data *)track_id_data.data;
415
416 if(trackp->hostid != gethostid()) {
417 krb5_klog_syslog(LOG_INFO, "Unexpected challenge response");
418 retval = KRB5KDC_ERR_DISCARD;
419 goto cleanup;
420 }
421
422 switch(trackp->state) {
423 case SECURID_STATE_INITIAL:
424 goto initial;
425 break;
426 case SECURID_STATE_NEW_PIN_AGAIN:
427 {
428 int pin1_len, pin2_len;
429
430 trackp->handle = ntohl(trackp->handle);
431 pin2_len = strlen(passcode);
432 pin1_len = strlen(trackp->passcode);
433
434 if ((pin1_len != pin2_len) ||
435 (memcmp(passcode, trackp->passcode, pin1_len) != 0)) {
436 retval = KRB5KDC_ERR_PREAUTH_FAILED;
437 krb5_klog_syslog(LOG_INFO, "New SecurID PIN Failed for user "
438 "%s: PIN mismatch", user);
439 break;
440 }
441 retval = SD_Pin(trackp->handle, passcode);
442 SD_Close(trackp->handle);
443 if (retval == ACM_NEW_PIN_ACCEPTED) {
444 enc_tkt_reply->flags|= TKT_FLG_HW_AUTH;
445 enc_tkt_reply->flags|= TKT_FLG_PRE_AUTH;
446 krb5_klog_syslog(LOG_INFO, "SecurID PIN Accepted for %s in "
447 "verify_securid_data_2",
448 securid_user);
449 retval = 0;
450 } else {
451 retval = KRB5KDC_ERR_PREAUTH_FAILED;
452 krb5_klog_syslog(LOG_INFO,
453 "SecurID PIN Failed for user %s (AceServer "
454 "returns %d) in verify_securid_data_2",
455 user, retval);
456 }
457 break;
458 }
459 case SECURID_STATE_NEW_PIN: {
460 krb5_sam_challenge_2_body sc2b;
461 sc2p = k5alloc(sizeof *sc2p, &retval);
462 if (retval)
463 goto cleanup;
464 memset(sc2p, 0, sizeof(*sc2p));
465 memset(&sc2b, 0, sizeof(sc2b));
466 sc2b.sam_type = PA_SAM_TYPE_SECURID;
467 sc2b.sam_response_prompt.data = NEW_PIN_AGAIN_message;
468 sc2b.sam_response_prompt.length =
469 strlen(sc2b.sam_response_prompt.data);
470 sc2b.sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD;
471 sc2b.sam_etype = client_key.enctype;
472
473 tmp_data.data = (char *)&sc2b.sam_nonce;
474 tmp_data.length = sizeof(sc2b.sam_nonce);
475 if ((retval = krb5_c_random_make_octets(context, &tmp_data))) {
476 com_err("krb5kdc", retval,
477 "while making nonce for SecurID new "
478 "PIN2 SAM_CHALLENGE_2 (%s)", user);
479 goto cleanup;
480 }
481 sid_track_data.state = SECURID_STATE_NEW_PIN_AGAIN;
482 sid_track_data.handle = trackp->handle;
483 sid_track_data.hostid = gethostid();
484 /* Should we complain if sizes don't work ?? */
485 memcpy(sid_track_data.passcode, passcode,
486 sizeof(sid_track_data.passcode));
487 tmp_data.data = (char *)&sid_track_data;
488 tmp_data.length = sizeof(sid_track_data);
489 if ((retval = securid_encrypt_track_data_2(context, client,
490 &tmp_data,
491 &sc2b.sam_track_id))) {
492 com_err("krb5kdc", retval,
493 "while encrypting NEW PIN2 SecurID "
494 "track data for SAM_CHALLENGE_2 (%s)",
495 securid_user);
496 goto cleanup;
497 }
498 retval = sam_make_challenge(context, &sc2b, &client_key, sc2p);
499 if (retval) {
500 com_err("krb5kdc", retval,
501 "while making cksum for "
502 "SAM_CHALLENGE_2 (new PIN2) (%s)", securid_user);
503 goto cleanup;
504 }
505 krb5_klog_syslog(LOG_INFO,
506 "Requesting verification of new PIN for user %s",
507 securid_user);
508 *sc2_out = sc2p;
509 sc2p = NULL;
510 /*sc2_out may be set even on error path*/
511 retval = KRB5KDC_ERR_PREAUTH_REQUIRED;
512 goto cleanup;
513 }
514 case SECURID_STATE_NEXT_CODE:
515 trackp->handle = ntohl(trackp->handle);
516 retval = SD_Next(trackp->handle, passcode);
517 SD_Close(trackp->handle);
518 if (retval == ACM_OK) {
519 enc_tkt_reply->flags |= TKT_FLG_HW_AUTH | TKT_FLG_PRE_AUTH;
520
521 krb5_klog_syslog(LOG_INFO, "Next SecurID Code Accepted for "
522 "user %s", securid_user);
523 retval = 0;
524 } else {
525 krb5_klog_syslog(LOG_INFO, "Next SecurID Code Failed for user "
526 "%s (AceServer returns %d) in "
527 "verify_securid_data_2", user, retval);
528 retval = KRB5KDC_ERR_PREAUTH_FAILED;
529 }
530 break;
531 }
532 } else { /* No track data, this is first of N attempts */
533 initial:
534 retval = SD_Init(&sd_handle);
535 if (retval) {
536 com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED,
537 "SD_Init() returns error %d in verify_securid_data_2 (%s)",
538 retval, securid_user);
539 retval = KRB5KDC_ERR_PREAUTH_FAILED;
540 goto cleanup;
541 }
542
543 retval = SD_Lock(sd_handle, securid_user);
544 if (retval != ACM_OK) {
545 SD_Close(sd_handle);
546 retval = KRB5KDC_ERR_PREAUTH_FAILED;
547 krb5_klog_syslog(LOG_INFO,
548 "SD_Lock() failed (AceServer returns %d) for %s",
549 retval, securid_user);
550 goto cleanup;
551 }
552
553 retval = SD_Check(sd_handle, passcode, securid_user);
554 switch (retval) {
555 case ACM_OK:
556 SD_Close(sd_handle);
557 enc_tkt_reply->flags|= TKT_FLG_HW_AUTH;
558 enc_tkt_reply->flags|= TKT_FLG_PRE_AUTH;
559 krb5_klog_syslog(LOG_INFO, "SecurID passcode accepted for user %s",
560 user);
561 retval = 0;
562 break;
563 case ACM_ACCESS_DENIED:
564 SD_Close(sd_handle);
565 retval = KRB5KDC_ERR_PREAUTH_FAILED;
566 krb5_klog_syslog(LOG_INFO, "AceServer returns Access Denied for "
567 "user %s (SAM2)", user);
568 goto cleanup;
569 case ACM_NEW_PIN_REQUIRED:
570 new_pin = 1;
571 /*fall through*/
572 case ACM_NEXT_CODE_REQUIRED: {
573 krb5_sam_challenge_2_body sc2b;
574 sc2p = k5alloc(sizeof *sc2p, &retval);
575 if (retval)
576 goto cleanup;
577
578 memset(sc2p, 0, sizeof(*sc2p));
579 memset(&sc2b, 0, sizeof(sc2b));
580
581 sc2b.sam_type = PA_SAM_TYPE_SECURID;
582 sc2b.sam_response_prompt.data = NEXT_PASSCODE_message;
583 sc2b.sam_response_prompt.length =
584 strlen(sc2b.sam_response_prompt.data);
585 sc2b.sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD;
586 sc2b.sam_etype = client_key.enctype;
587 if (new_pin) {
588 if ((AceGetMaxPinLen(sd_handle, &max_pin_len) == ACE_SUCCESS)
589 && (AceGetMinPinLen(sd_handle,
590 &min_pin_len) == ACE_SUCCESS)
591 && (AceGetAlphanumeric(sd_handle,
592 &alpha_pin) == ACE_SUCCESS)) {
593 sprintf(PIN_message,
594 "New PIN must contain %d to %d %sdigits",
595 min_pin_len, max_pin_len,
596 (alpha_pin == 0) ? "" : "alphanumeric ");
597 sc2b.sam_challenge_label.data = PIN_message;
598 sc2b.sam_challenge_label.length =
599 strlen(sc2b.sam_challenge_label.data);
600 } else {
601 sc2b.sam_challenge_label.length = 0;
602 }
603 }
604
605 tmp_data.data = (char *)&sc2b.sam_nonce;
606 tmp_data.length = sizeof(sc2b.sam_nonce);
607 if ((retval = krb5_c_random_make_octets(context, &tmp_data))) {
608 com_err("krb5kdc", retval,
609 "while making nonce for SecurID SAM_CHALLENGE_2 (%s)",
610 user);
611 goto cleanup;
612 }
613 if (new_pin)
614 sid_track_data.state = SECURID_STATE_NEW_PIN;
615 else
616 sid_track_data.state = SECURID_STATE_NEXT_CODE;
617 sid_track_data.handle = htonl(sd_handle);
618 sid_track_data.hostid = gethostid();
619 tmp_data.data = (char *)&sid_track_data;
620 tmp_data.length = sizeof(sid_track_data);
621 retval = securid_encrypt_track_data_2(context, client, &tmp_data,
622 &sc2b.sam_track_id);
623 if (retval) {
624 com_err("krb5kdc", retval,
625 "while encrypting SecurID track "
626 "data for SAM_CHALLENGE_2 (%s)",
627 securid_user);
628 goto cleanup;
629 }
630 retval = sam_make_challenge(context, &sc2b, &client_key, sc2p);
631 if (retval) {
632 com_err("krb5kdc", retval,
633 "while making cksum for SAM_CHALLENGE_2 (%s)",
634 securid_user);
635 }
636 if (new_pin)
637 krb5_klog_syslog(LOG_INFO, "New SecurID PIN required for "
638 "user %s", securid_user);
639 else
640 krb5_klog_syslog(LOG_INFO, "Next SecurID passcode required "
641 "for user %s", securid_user);
642 *sc2_out = sc2p;
643 sc2p = NULL;
644 retval = KRB5KDC_ERR_PREAUTH_REQUIRED;
645 /*sc2_out is permitted as an output on error path*/
646 goto cleanup;
647 }
648 default:
649 com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED,
650 "AceServer returns unknown error code %d "
651 "in verify_securid_data_2\n", retval);
652 retval = KRB5KDC_ERR_PREAUTH_FAILED;
653 goto cleanup;
654 }
655 } /* no track_id data */
656
657 cleanup:
658 krb5_free_keyblock_contents(context, &client_key);
659 free(scratch.data);
660 krb5_free_enc_sam_response_enc_2(context, esre2);
661 free(user);
662 free(securid_user);
663 free(trackp);
664 krb5_free_sam_challenge_2(context, sc2p);
665 return retval;
666 }
667
668 #endif /* ARL_SECURID_PREAUTH */
669