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