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 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 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 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 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 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