1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/cpuvar.h> 26 #include <sys/types.h> 27 #include <sys/conf.h> 28 #include <sys/file.h> 29 #include <sys/ddi.h> 30 #include <sys/sunddi.h> 31 #include <sys/modctl.h> 32 33 #include <sys/socket.h> 34 #include <sys/strsubr.h> 35 #include <sys/sysmacros.h> 36 37 #include <sys/stmf.h> 38 #include <sys/stmf_ioctl.h> 39 #include <sys/portif.h> 40 #include <sys/idm/idm.h> 41 #include <sys/idm/idm_text.h> 42 43 #include "iscsit.h" 44 #include "iscsit_auth.h" 45 46 static kv_status_t 47 iscsit_select_auth(iscsit_conn_t *ict, nvpair_t *nvp, 48 const idm_kv_xlate_t *ikvx); 49 50 static kv_status_t 51 auth_propose_chap(iscsit_conn_t *ict, nvpair_t *nvp, 52 const idm_kv_xlate_t *ikvx); 53 54 static kv_status_t 55 auth_chap_select_alg(iscsit_conn_t *ict, nvpair_t *nvp, 56 const idm_kv_xlate_t *ikvx); 57 58 static kv_status_t 59 auth_chap_recv_n(iscsit_conn_t *ict, nvpair_t *nvp, 60 const idm_kv_xlate_t *ikvx); 61 62 static kv_status_t 63 auth_chap_recv_r(iscsit_conn_t *ict, nvpair_t *nvp, 64 const idm_kv_xlate_t *ikvx); 65 66 static kv_status_t 67 auth_chap_recv_i(iscsit_conn_t *ict, nvpair_t *nvp, 68 const idm_kv_xlate_t *ikvx); 69 70 static kv_status_t 71 auth_chap_recv_c(iscsit_conn_t *ict, nvpair_t *nvp, 72 const idm_kv_xlate_t *ikvx); 73 74 static kv_status_t 75 iscsit_auth_propose(iscsit_conn_t *ict, nvpair_t *nvp, 76 const idm_kv_xlate_t *ikvx); 77 78 static kv_status_t 79 iscsit_auth_expect_key(iscsit_conn_t *ict, nvpair_t *nvp, 80 const idm_kv_xlate_t *ikvx); 81 82 static kv_status_t 83 auth_chap_expect_r(iscsit_conn_t *ict, nvpair_t *nvp, 84 const idm_kv_xlate_t *ikvx); 85 86 static kv_status_t 87 auth_chap_done(iscsit_conn_t *ict, nvpair_t *nvp, 88 const idm_kv_xlate_t *ikvx); 89 90 static kv_status_t 91 iscsit_auth_gen_challenge(iscsit_conn_t *ict); 92 93 static kv_status_t 94 iscsit_auth_gen_response(iscsit_conn_t *ict); 95 96 typedef struct { 97 iscsit_auth_phase_t phase; 98 iscsikey_id_t kv_id; 99 iscsit_auth_handler_t handler; 100 } auth_phase_entry_t; 101 102 /* 103 * This table defines all authentication phases which have valid 104 * handler. The entries which have a non-zero key index are for 105 * a key/value pair handling when a key/value is being received, 106 * the rest of entries are for target checking the authentication 107 * phase after all key/value pair(s) are handled. 108 */ 109 static const auth_phase_entry_t apet[] = { 110 /* by key */ 111 { AP_AM_UNDECIDED, KI_AUTH_METHOD, iscsit_select_auth }, 112 { AP_AM_PROPOSED, KI_CHAP_A, auth_propose_chap }, 113 114 { AP_CHAP_A_WAITING, KI_CHAP_A, auth_chap_select_alg }, 115 { AP_CHAP_R_WAITING, KI_CHAP_N, auth_chap_recv_n }, 116 { AP_CHAP_R_WAITING, KI_CHAP_R, auth_chap_recv_r }, 117 { AP_CHAP_R_WAITING, KI_CHAP_I, auth_chap_recv_i }, 118 { AP_CHAP_R_WAITING, KI_CHAP_C, auth_chap_recv_c }, 119 { AP_CHAP_R_RCVD, KI_CHAP_N, auth_chap_recv_n }, 120 { AP_CHAP_R_RCVD, KI_CHAP_R, auth_chap_recv_r }, 121 { AP_CHAP_R_RCVD, KI_CHAP_I, auth_chap_recv_i }, 122 { AP_CHAP_R_RCVD, KI_CHAP_C, auth_chap_recv_c }, 123 124 /* by target */ 125 { AP_AM_UNDECIDED, 0, iscsit_auth_propose }, 126 { AP_AM_DECIDED, 0, iscsit_auth_expect_key }, 127 128 { AP_CHAP_A_RCVD, 0, auth_chap_expect_r }, 129 { AP_CHAP_R_RCVD, 0, auth_chap_done } 130 }; 131 132 typedef struct { 133 iscsit_auth_method_t am_id; 134 char *am_name; 135 } auth_id_name_t; 136 137 /* 138 * a table of mapping from the authentication index to name. 139 */ 140 static const auth_id_name_t aint[] = { 141 { AM_CHAP, "CHAP" }, 142 { AM_NONE, "None" }, 143 /* { AM_KRB5, "KRB5" }, */ /* Not supported */ 144 /* { AM_SPKM1, "SPKM1" }, */ /* Not supported */ 145 /* { AM_SPKM2, "SPKM2" }, */ /* Not supported */ 146 /* { AM_SRP, "SRP" }, */ /* Not supported */ 147 }; 148 149 #define ARRAY_LENGTH(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0])) 150 151 /* 152 * get the authentication method name for the method id. 153 */ 154 static const char * 155 am_id_to_name(int id) 156 { 157 int i; 158 const auth_id_name_t *p; 159 i = 0; 160 while (i < ARRAY_LENGTH(aint)) { 161 p = &(aint[i]); 162 if (id == p->am_id) { 163 return (p->am_name); 164 } 165 i ++; 166 } 167 168 return (NULL); 169 } 170 171 /* 172 * Look for an apporiate function handler which is defined for 173 * current authentication phase and matches the key which is 174 * being handled. The key index is passed in as zero when it 175 * is looking for an handler for checking the authentication phase 176 * after all security keys are handled. 177 */ 178 iscsit_auth_handler_t 179 iscsit_auth_get_handler(iscsit_auth_client_t *client, iscsikey_id_t kv_id) 180 { 181 iscsit_auth_phase_t phase = client->phase; 182 int i; 183 const auth_phase_entry_t *p; 184 185 i = 0; 186 p = NULL; 187 while (i < ARRAY_LENGTH(apet)) { 188 p = &(apet[i]); 189 if (phase == p->phase && 190 kv_id == p->kv_id) { 191 return (p->handler); 192 } 193 i ++; 194 } 195 196 /* No handler can be found, it must be an invalid requst. */ 197 return (NULL); 198 } 199 200 /* 201 * Select an authentication method from a list of values proposed 202 * by initiator. After a valid method is selected, shift the 203 * authentication phase to AP_AM_DECIDED. 204 */ 205 static kv_status_t 206 iscsit_select_auth(iscsit_conn_t *ict, nvpair_t *nvp, 207 const idm_kv_xlate_t *ikvx) 208 { 209 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 210 conn_auth_t *auth = &lsm->icl_auth; 211 iscsit_auth_method_t *am_list = &auth->ca_method_valid_list[0]; 212 iscsit_auth_client_t *client = &lsm->icl_auth_client; 213 int nvrc; 214 kv_status_t kvrc; 215 nvpair_t *am_choice; 216 char *am; 217 const char *am_name; 218 const char *text; 219 iscsit_auth_method_t am_id; 220 int i; 221 222 client->phase = AP_AM_DECIDED; 223 224 /* select a valid authentication method */ 225 am_choice = idm_get_next_listvalue(nvp, NULL); 226 while (am_choice != NULL) { 227 nvrc = nvpair_value_string(am_choice, &am); 228 ASSERT(nvrc == 0); 229 230 i = 0; 231 am_id = am_list[i]; 232 while (am_id != 0) { 233 am_name = am_id_to_name(am_id); 234 if (strcasecmp(am, am_name) == 0) { 235 text = am; 236 goto am_decided; 237 } 238 i++; 239 am_id = am_list[i]; 240 } 241 am_choice = idm_get_next_listvalue(nvp, am_choice); 242 } 243 244 /* none of authentication method is valid */ 245 am_id = 0; 246 text = ISCSI_TEXT_REJECT; 247 248 am_decided: 249 client->negotiatedMethod = am_id; 250 /* add the selected method to the response nvlist */ 251 nvrc = nvlist_add_string(lsm->icl_response_nvlist, 252 ikvx->ik_key_name, text); 253 kvrc = idm_nvstat_to_kvstat(nvrc); 254 255 return (kvrc); 256 } 257 258 /* 259 * Initiator chooses to use CHAP after target proposed a list of 260 * authentication method. Set the authentication method to CHAP and 261 * continue on chap authentication phase. 262 */ 263 static kv_status_t 264 auth_propose_chap(iscsit_conn_t *ict, nvpair_t *nvp, 265 const idm_kv_xlate_t *ikvx) 266 { 267 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 268 iscsit_auth_client_t *client = &lsm->icl_auth_client; 269 270 client->negotiatedMethod = AM_CHAP; 271 client->phase = AP_AM_DECIDED; 272 273 return (auth_chap_select_alg(ict, nvp, ikvx)); 274 } 275 276 /* 277 * Select a CHAP algorithm from a list of values proposed by 278 * initiator and shift the authentication phase to AP_CHAP_A_RCVD. 279 */ 280 static kv_status_t 281 auth_chap_select_alg(iscsit_conn_t *ict, nvpair_t *nvp, 282 const idm_kv_xlate_t *ikvx) 283 { 284 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 285 iscsit_auth_client_t *client = &lsm->icl_auth_client; 286 int nvrc, rc; 287 kv_status_t kvrc; 288 nvpair_t *alg_choice; 289 char *alg_string; 290 uint64_t alg; 291 const char *text; 292 293 client->phase = AP_CHAP_A_RCVD; 294 295 alg_choice = idm_get_next_listvalue(nvp, NULL); 296 while (alg_choice != NULL) { 297 nvrc = nvpair_value_string(alg_choice, &alg_string); 298 ASSERT(nvrc == 0); 299 rc = ddi_strtoull(alg_string, NULL, 0, (u_longlong_t *)&alg); 300 if (rc == 0 && alg == 5) { 301 /* only MD5 is supported */ 302 text = alg_string; 303 goto alg_selected; 304 } 305 306 alg_choice = idm_get_next_listvalue(nvp, alg_choice); 307 } 308 309 /* none of algorithm is selected */ 310 alg = 0; 311 text = ISCSI_TEXT_REJECT; 312 313 alg_selected: 314 /* save the selected algorithm or zero for none is selected */ 315 client_set_numeric_data( 316 &client->recvKeyBlock, 317 AKT_CHAP_A, 318 (uint32_t)alg); 319 320 /* add the selected algorithm to the response nvlist */ 321 nvrc = nvlist_add_string(lsm->icl_response_nvlist, 322 ikvx->ik_key_name, text); 323 if (alg == 0) { 324 kvrc = KV_AUTH_FAILED; /* No algorithm selected */ 325 } else { 326 kvrc = idm_nvstat_to_kvstat(nvrc); 327 if (kvrc == 0) { 328 kvrc = iscsit_auth_gen_challenge(ict); 329 } 330 } 331 332 return (kvrc); 333 } 334 335 /* 336 * Validate and save the the chap name which is sent by initiator 337 * and shift the authentication phase to AP_CHAP_R_RCVD. 338 * 339 * Note: the CHAP_N, CHAP_R, optionally CHAP_I and CHAP_C key/value 340 * pairs need to be received in one packet, we handle each of them 341 * separately, in order to track the authentication phase, we set 342 * the authentication phase to AP_CHAP_R_RCVD once one of them is 343 * handled. So both of AP_CHAP_R_WAITING and AP_CHAP_R_RCVD phases 344 * are valid for these keys. The function auth_chap_done is going 345 * to detect if any of these keys is missing. 346 */ 347 348 /*ARGSUSED*/ 349 static kv_status_t 350 auth_chap_recv_n(iscsit_conn_t *ict, nvpair_t *nvp, 351 const idm_kv_xlate_t *ikvx) 352 { 353 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 354 iscsit_auth_client_t *client = &lsm->icl_auth_client; 355 int nvrc; 356 char *chap_name; 357 358 nvrc = nvpair_value_string(nvp, &chap_name); 359 ASSERT(nvrc == 0); 360 361 client_set_string_data(&client->recvKeyBlock, 362 AKT_CHAP_N, 363 chap_name); 364 365 client->phase = AP_CHAP_R_RCVD; 366 367 return (KV_HANDLED); 368 } 369 370 /* 371 * Validate and save the the chap response which is sent by initiator 372 * and shift the authentication phase to AP_CHAP_R_RCVD. 373 * 374 * Note: see function auth_chap_recv_n. 375 */ 376 377 /*ARGSUSED*/ 378 static kv_status_t 379 auth_chap_recv_r(iscsit_conn_t *ict, nvpair_t *nvp, 380 const idm_kv_xlate_t *ikvx) 381 { 382 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 383 iscsit_auth_client_t *client = &lsm->icl_auth_client; 384 int nvrc; 385 unsigned char *chap_resp; 386 uint_t len; 387 388 nvrc = nvpair_value_byte_array(nvp, &chap_resp, &len); 389 ASSERT(nvrc == 0); 390 391 client_set_binary_data(&client->recvKeyBlock, 392 AKT_CHAP_R, 393 chap_resp, len); 394 395 client->phase = AP_CHAP_R_RCVD; 396 397 return (KV_HANDLED); 398 } 399 400 /* 401 * Validate and save the the chap identifier which is sent by initiator 402 * and shift the authentication phase to AP_CHAP_R_RCVD. 403 * 404 * Note: see function auth_chap_recv_n. 405 */ 406 407 /*ARGSUSED*/ 408 static kv_status_t 409 auth_chap_recv_i(iscsit_conn_t *ict, nvpair_t *nvp, 410 const idm_kv_xlate_t *ikvx) 411 { 412 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 413 iscsit_auth_client_t *client = &lsm->icl_auth_client; 414 int nvrc; 415 uint64_t chap_id; 416 417 nvrc = nvpair_value_uint64(nvp, &chap_id); 418 ASSERT(nvrc == 0); 419 420 client_set_numeric_data(&client->recvKeyBlock, 421 AKT_CHAP_I, 422 chap_id); 423 424 client->phase = AP_CHAP_R_RCVD; 425 426 return (KV_HANDLED); 427 } 428 429 /* 430 * Validate and save the the chap challenge which is sent by initiator 431 * and shift the authentication phase to AP_CHAP_R_RCVD. 432 * 433 * Note: see function auth_chap_recv_n. 434 */ 435 436 /*ARGSUSED*/ 437 static kv_status_t 438 auth_chap_recv_c(iscsit_conn_t *ict, nvpair_t *nvp, 439 const idm_kv_xlate_t *ikvx) 440 { 441 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 442 iscsit_auth_client_t *client = &lsm->icl_auth_client; 443 int nvrc; 444 unsigned char *chap_challenge; 445 uint_t len; 446 447 nvrc = nvpair_value_byte_array(nvp, &chap_challenge, &len); 448 ASSERT(nvrc == 0); 449 450 client_set_binary_data( 451 &client->recvKeyBlock, 452 AKT_CHAP_C, 453 chap_challenge, len); 454 455 client->phase = AP_CHAP_R_RCVD; 456 457 return (KV_HANDLED); 458 } 459 460 /* 461 * Shift the authentication phase to AP_CHAP_R_WAITING after target 462 * has successfully selected a chap algorithm. 463 */ 464 465 /*ARGSUSED*/ 466 static kv_status_t 467 auth_chap_expect_r(iscsit_conn_t *ict, nvpair_t *nvp, 468 const idm_kv_xlate_t *ikvx) 469 { 470 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 471 iscsit_auth_client_t *client = &lsm->icl_auth_client; 472 473 uint32_t alg; 474 475 client_get_numeric_data(&client->recvKeyBlock, 476 AKT_CHAP_A, 477 &alg); 478 479 if (alg != 0) { 480 client->phase = AP_CHAP_R_WAITING; 481 } else { 482 /* none of proposed algorithm is supported or understood. */ 483 client->phase = AP_CHAP_A_WAITING; 484 } 485 486 return (KV_HANDLED); 487 } 488 489 /* 490 * Initiator does not propose security negotiation, target needs to 491 * verify if we can bypass the security negotiation phase or propose 492 * a security negotiation for the initiator. 493 */ 494 495 /*ARGSUSED*/ 496 static kv_status_t 497 iscsit_auth_propose(iscsit_conn_t *ict, nvpair_t *nvp, 498 const idm_kv_xlate_t *ikvx) 499 { 500 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 501 conn_auth_t *auth = &lsm->icl_auth; 502 iscsit_auth_method_t *am_list = &auth->ca_method_valid_list[0]; 503 iscsit_auth_client_t *client = &lsm->icl_auth_client; 504 505 int nvrc; 506 kv_status_t kvrc; 507 const char *am_name; 508 509 if (am_list[0] == AM_NONE || am_list[0] == 0) { 510 lsm->icl_auth_pass = 1; 511 } 512 513 if (lsm->icl_auth_pass == 0) { 514 /* 515 * It should be noted that the negotiation might also 516 * be directed by the target if the initiator does 517 * support security, but is not ready to direct the 518 * negotiation (propose options). 519 * - RFC3720 section 5.3.2. 520 */ 521 am_name = am_id_to_name(am_list[0]); 522 nvrc = nvlist_add_string( 523 lsm->icl_response_nvlist, 524 "AuthMethod", am_name); 525 kvrc = idm_nvstat_to_kvstat(nvrc); 526 527 client->phase = AP_AM_PROPOSED; 528 } else { 529 kvrc = KV_HANDLED; 530 531 client->phase = AP_DONE; 532 } 533 534 return (kvrc); 535 } 536 537 /* 538 * Shift the authentication phase according to the authentication 539 * method once it is selected. 540 */ 541 542 /*ARGSUSED*/ 543 static kv_status_t 544 iscsit_auth_expect_key(iscsit_conn_t *ict, nvpair_t *nvp, 545 const idm_kv_xlate_t *ikvx) 546 { 547 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 548 iscsit_auth_client_t *client = &lsm->icl_auth_client; 549 550 if (client->negotiatedMethod != 0) { 551 /* Shift security negotiation phase. */ 552 switch (client->negotiatedMethod) { 553 case AM_CHAP: 554 client->phase = AP_CHAP_A_WAITING; 555 break; 556 case AM_NONE: 557 client->phase = AP_DONE; 558 lsm->icl_auth_pass = 1; 559 break; 560 default: 561 ASSERT(0); 562 break; 563 } 564 } else { 565 /* None of proposed method is supported or understood. */ 566 client->phase = AP_AM_UNDECIDED; 567 } 568 569 return (KV_HANDLED); 570 } 571 572 /* 573 * The last step of the chap authentication. We will validate the 574 * chap parameters we received and authenticate the client here. 575 */ 576 577 /*ARGSUSED*/ 578 static kv_status_t 579 auth_chap_done(iscsit_conn_t *ict, nvpair_t *nvp, 580 const idm_kv_xlate_t *ikvx) 581 { 582 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 583 iscsit_auth_client_t *client = &lsm->icl_auth_client; 584 kv_status_t kvrc = KV_HANDLED; 585 586 conn_auth_t *auth = &lsm->icl_auth; 587 char *username_in; 588 589 uint32_t chap_id; 590 unsigned char *chap_challenge; 591 unsigned int challenge_len; 592 char *chap_name; 593 unsigned char *chap_resp; 594 unsigned int resp_len; 595 596 int bi_auth; 597 598 username_in = auth->ca_ini_chapuser; 599 if (username_in[0] == '\0') 600 return (KV_AUTH_FAILED); 601 602 /* 603 * Check if we have received a valid list of response keys. 604 */ 605 if (!client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_N) || 606 !client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_R) || 607 ((bi_auth = 608 client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_I)) ^ 609 client_auth_key_present(&client->recvKeyBlock, AKT_CHAP_C))) { 610 return (KV_MISSING_FIELDS); 611 } 612 613 client->phase = AP_DONE; 614 615 client_get_string_data(&client->recvKeyBlock, 616 AKT_CHAP_N, 617 &chap_name); 618 619 /* check username */ 620 if (strcmp(username_in, chap_name) != 0) { 621 return (KV_AUTH_FAILED); 622 } 623 624 client_get_numeric_data(&client->sendKeyBlock, 625 AKT_CHAP_I, 626 &chap_id); 627 628 client_get_binary_data(&client->sendKeyBlock, 629 AKT_CHAP_C, 630 &chap_challenge, &challenge_len); 631 632 client_get_binary_data(&client->recvKeyBlock, 633 AKT_CHAP_R, 634 &chap_resp, &resp_len); 635 636 if (iscsit_verify_chap_resp(lsm, 637 chap_id, chap_challenge, challenge_len, 638 chap_resp, resp_len) != ISCSI_AUTH_PASSED) { 639 return (KV_AUTH_FAILED); 640 } 641 642 /* bi-direction authentication is required */ 643 if (bi_auth != 0) { 644 kvrc = iscsit_auth_gen_response(ict); 645 } 646 647 lsm->icl_auth_pass = 1; 648 649 return (kvrc); 650 } 651 652 static kv_status_t 653 iscsit_auth_gen_challenge(iscsit_conn_t *ict) 654 { 655 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 656 iscsit_auth_client_t *client = &lsm->icl_auth_client; 657 int nvrc; 658 kv_status_t kvrc; 659 660 unsigned char idData[1]; 661 unsigned char *bin; 662 int len; 663 664 auth_random_set_data(idData, 1); 665 client_set_numeric_data(&client->sendKeyBlock, 666 AKT_CHAP_I, 667 idData[0]); 668 669 /* send chap identifier */ 670 nvrc = nvlist_add_uint64( 671 lsm->icl_response_nvlist, 672 "CHAP_I", idData[0]); 673 kvrc = idm_nvstat_to_kvstat(nvrc); 674 if (kvrc != 0) { 675 return (kvrc); 676 } 677 678 bin = &(client->auth_send_binary_block.largeBinary[0]); 679 len = iscsitAuthChapResponseLength; 680 auth_random_set_data(bin, len); 681 client_set_binary_data(&client->sendKeyBlock, 682 AKT_CHAP_C, 683 bin, len); 684 685 /* send chap challenge */ 686 nvrc = nvlist_add_byte_array( 687 lsm->icl_response_nvlist, 688 "CHAP_C", bin, len); 689 kvrc = idm_nvstat_to_kvstat(nvrc); 690 691 return (kvrc); 692 } 693 694 static kv_status_t 695 iscsit_auth_gen_response(iscsit_conn_t *ict) 696 { 697 iscsit_conn_login_t *lsm = &ict->ict_login_sm; 698 iscsit_auth_client_t *client = &lsm->icl_auth_client; 699 int nvrc; 700 kv_status_t kvrc; 701 702 conn_auth_t *auth = &lsm->icl_auth; 703 char *tgt_username; 704 uint8_t *tgt_password; 705 int tgt_password_length; 706 707 uint32_t chap_id; 708 unsigned char *chap_challenge; 709 unsigned int challenge_len; 710 uchar_t resp[iscsitAuthChapResponseLength]; 711 712 tgt_username = auth->ca_tgt_chapuser; 713 tgt_password = auth->ca_tgt_chapsecret; 714 tgt_password_length = auth->ca_tgt_chapsecretlen; 715 716 /* 717 * We can't know in advance whether the initiator will attempt 718 * mutual authentication, so now we need to check whether we 719 * have a target CHAP secret configured. 720 */ 721 if (tgt_password_length == 0) { 722 return (KV_AUTH_FAILED); 723 } 724 725 client_get_numeric_data(&client->recvKeyBlock, 726 AKT_CHAP_I, 727 &chap_id); 728 729 client_get_binary_data(&client->recvKeyBlock, 730 AKT_CHAP_C, 731 &chap_challenge, &challenge_len); 732 733 client_compute_chap_resp( 734 &resp[0], 735 chap_id, 736 tgt_password, tgt_password_length, 737 chap_challenge, challenge_len); 738 739 nvrc = nvlist_add_string( 740 lsm->icl_response_nvlist, 741 "CHAP_N", tgt_username); 742 743 if (nvrc == 0) { 744 nvrc = nvlist_add_byte_array( 745 lsm->icl_response_nvlist, 746 "CHAP_R", resp, sizeof (resp)); 747 } 748 kvrc = idm_nvstat_to_kvstat(nvrc); 749 750 return (kvrc); 751 } 752