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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <strings.h> 31 #include <sys/types.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <syslog.h> 35 #include <sys/iscsi_protocol.h> 36 #include <arpa/inet.h> 37 #include <iscsitgt_impl.h> 38 #include "queue.h" 39 #include "iscsi_conn.h" 40 #include "iscsi_sess.h" 41 #include "iscsi_login.h" 42 #include "iscsi_provider_impl.h" 43 #include "utility.h" 44 #include "target.h" 45 #include "isns_client.h" 46 47 typedef enum auth_action { 48 LOGIN_NO_AUTH, 49 LOGIN_AUTH, 50 LOGIN_DROP 51 } auth_action_t; 52 53 /* 54 * Forward declarations 55 */ 56 static iscsi_login_rsp_hdr_t *make_login_response(iscsi_conn_t *c, 57 iscsi_login_hdr_t *lhp); 58 static void send_login_reject(iscsi_conn_t *c, iscsi_login_hdr_t *lhp, 59 int err_code); 60 static Boolean_t check_for_valid_I_T(iscsi_conn_t *c); 61 static auth_action_t login_set_auth(iscsi_sess_t *s); 62 63 /* 64 * iscsi_null_callback - This callback may be used under certain 65 * conditions when authenticating a target, but I'm not sure what 66 * we need to do here. 67 */ 68 /* ARGSUSED */ 69 static void 70 iscsi_null_callback(void *user_handle, void *message_handle, int auth_status) 71 { 72 } 73 74 /* 75 * iscsi_find_key_value - 76 */ 77 static int 78 iscsi_find_key_value(char *param, char *ihp, char *pdu_end, 79 char **value_start, char **value_end) 80 { 81 char *str = param; 82 char *text = ihp; 83 char *value = NULL; 84 85 if (value_start) 86 *value_start = NULL; 87 if (value_end) 88 *value_end = NULL; 89 90 /* 91 * make sure they contain the same bytes 92 */ 93 while (*str) { 94 if (text >= pdu_end) { 95 return (0); 96 } 97 if (*text == '\0') { 98 return (0); 99 } 100 if (*str != *text) { 101 return (0); 102 } 103 str++; 104 text++; 105 } 106 107 if ((text >= pdu_end) || 108 (*text == '\0') || 109 (*text != ISCSI_TEXT_SEPARATOR)) { 110 return (0); 111 } 112 113 /* 114 * find the value 115 */ 116 value = text + 1; 117 118 /* 119 * find the end of the value 120 */ 121 while ((text < pdu_end) && (*text)) 122 text++; 123 124 if (value_start) 125 *value_start = value; 126 if (value_end) 127 *value_end = text; 128 129 return (1); 130 } 131 132 Boolean_t 133 iscsi_handle_login_pkt(iscsi_conn_t *c) 134 { 135 iscsi_login_hdr_t lh; 136 iscsi_login_rsp_hdr_t *rsp = NULL; 137 Boolean_t rval = False; 138 IscsiAuthClient *auth_client = NULL; 139 char *text = NULL; 140 char *end = NULL; 141 char *text_rsp = NULL; 142 char debug[128]; 143 int debug_status = 0; 144 int errcode = 0; 145 int text_length = 0; 146 int keytype = 0; 147 int transit = 0; 148 int rc = 0; 149 auth_action_t auth_action = LOGIN_DROP; 150 tgt_node_t *tnode = NULL; 151 152 if (read(c->c_fd, &lh, sizeof (lh)) != sizeof (lh)) { 153 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, 154 "Header to small"); 155 return (False); 156 } 157 158 if ((lh.opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_LOGIN_CMD) { 159 (void) snprintf(debug, sizeof (debug), 160 "CON%x Wrong OP code for state (Got 0x%x, Expected 0x%x)", 161 c->c_num, lh.opcode, ISCSI_OP_LOGIN_CMD); 162 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 163 send_login_reject(c, &lh, 164 (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | 165 ISCSI_LOGIN_STATUS_INVALID_REQUEST); 166 conn_state(c, T7); 167 return (True); 168 } 169 170 if (ISCSI_LOGIN_COMMAND_ENABLED()) { 171 uiscsiproto_t info; 172 char nil = '\0'; 173 174 info.uip_target_addr = &c->c_target_sockaddr; 175 info.uip_initiator_addr = &c->c_initiator_sockaddr; 176 177 info.uip_target = &nil; 178 info.uip_initiator = &nil; 179 info.uip_lun = 0; 180 181 info.uip_itt = lh.itt; 182 info.uip_ttt = ISCSI_RSVD_TASK_TAG; 183 184 info.uip_cmdsn = ntohl(lh.cmdsn); 185 info.uip_statsn = ntohl(lh.expstatsn); 186 info.uip_datasn = 0; 187 188 info.uip_datalen = ntoh24(lh.dlength); 189 info.uip_flags = lh.flags; 190 191 ISCSI_LOGIN_COMMAND(&info); 192 } 193 194 if ((rval = session_alloc(c, lh.isid)) == False) { 195 conn_state(c, T7); 196 return (True); 197 } 198 199 connection_parameters_default(c); 200 201 c->c_cid = ntohl(lh.cid); 202 c->c_statsn = ntohl(lh.expstatsn); 203 204 (void) pthread_mutex_lock(&c->c_sess->s_mutex); 205 c->c_sess->s_cmdsn = ntohl(lh.cmdsn); 206 c->c_sess->s_seencmdsn = ntohl(lh.cmdsn); 207 (void) pthread_mutex_unlock(&c->c_sess->s_mutex); 208 209 /* 210 * Is this a new session or an attempt to add a connection to 211 * an existing session. 212 */ 213 if (ntohs(lh.tsid) != 0) { 214 215 /* Multiple connections per session not handled right now */ 216 conn_state(c, T7); 217 return (True); 218 } 219 220 if ((rsp = make_login_response(c, &lh)) == NULL) { 221 (void) snprintf(debug, sizeof (debug), 222 "CON%x Failed make_login_response", c->c_num); 223 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 224 return (False); 225 } 226 /* default is ISCSI_FLAG_LOGIN_TRANSIT, not good for login */ 227 rsp->flags = 0; 228 229 if ((rsp->active_version < lh.min_version) || 230 (rsp->active_version > lh.max_version)) { 231 (void) snprintf(debug, sizeof (debug), 232 "CON%x Version: Active %d, min %d, max %d", c->c_num, 233 rsp->active_version, lh.min_version, lh.max_version); 234 send_login_reject(c, &lh, 235 (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | 236 ISCSI_LOGIN_STATUS_NO_VERSION); 237 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 238 conn_state(c, T7); 239 free(rsp); 240 return (True); 241 } 242 243 if (lh.flags & ISCSI_FLAG_LOGIN_CONTINUE) { 244 (void) snprintf(debug, sizeof (debug), 245 "CON%x Continuation pkt", c->c_num); 246 queue_str(c->c_mgmtq, Q_CONN_LOGIN, msg_log, debug); 247 } 248 249 auth_client = 250 (c->c_sess->sess_auth.auth_buffers && 251 c->c_sess->sess_auth.num_auth_buffers) ? 252 (IscsiAuthClient *) c->c_sess->sess_auth.auth_buffers[0].address : 253 NULL; 254 255 if (c->auth_text != NULL) 256 free(c->auth_text); 257 c->auth_text_length = 0; 258 259 transit = lh.flags & ISCSI_FLAG_LOGIN_TRANSIT; 260 261 switch (ISCSI_LOGIN_CURRENT_STAGE(lh.flags)) { 262 case ISCSI_SECURITY_NEGOTIATION_STAGE: 263 264 /* 265 * Grab the parameters and create the response 266 * text. 267 */ 268 rval = parse_text(c, ntoh24(lh.dlength), 269 &text_rsp, &text_length, &errcode); 270 if (rval == False) { 271 send_login_reject(c, &lh, errcode); 272 (void) snprintf(debug, sizeof (debug), 273 "CON%x SecurityNegotiation: parse_text" 274 " failed", c->c_num); 275 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 276 conn_state(c, T7); 277 break; 278 } 279 280 if ((rval = check_for_valid_I_T(c)) == False) { 281 send_login_reject(c, &lh, 282 (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | 283 ISCSI_LOGIN_STATUS_INIT_ERR); 284 (void) snprintf(debug, sizeof (debug), 285 "CON%x SecurityNegotiation: invalid I " 286 "or T", c->c_num); 287 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 288 conn_state(c, T7); 289 break; 290 } 291 292 auth_action = login_set_auth(c->c_sess); 293 294 if (auth_action == LOGIN_NO_AUTH) { 295 rsp->flags |= ISCSI_FLAG_LOGIN_TRANSIT; 296 rsp->flags |= ISCSI_OP_PARMS_NEGOTIATION_STAGE; 297 rval = add_text(&text_rsp, &text_length, "AuthMethod", 298 "None"); 299 if (rval == False) { 300 send_login_reject(c, &lh, 301 (ISCSI_STATUS_CLASS_TARGET_ERR << 8) | 302 ISCSI_LOGIN_STATUS_TARGET_ERROR); 303 (void) snprintf(debug, sizeof (debug), 304 "CON%x Norm: Failed to add AuthMethod=None", 305 c->c_num); 306 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, 307 debug); 308 conn_state(c, T7); 309 } 310 break; 311 } 312 313 if (auth_action == LOGIN_DROP) { 314 send_login_reject(c, &lh, 315 (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | 316 ISCSI_LOGIN_STATUS_TGT_FORBIDDEN); 317 (void) snprintf(debug, sizeof (debug), 318 "CON%x SecurityNegotiation: access denied", 319 c->c_num); 320 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 321 conn_state(c, T7); 322 rval = False; 323 break; 324 } 325 326 if (iscsiAuthClientRecvBegin(auth_client) != 327 iscsiAuthStatusNoError) { 328 (void) snprintf(debug, sizeof (debug), "CON%x " 329 "login failed - authentication receive failed", 330 c->c_num); 331 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 332 break; 333 } 334 335 if (iscsiAuthClientRecvTransitBit(auth_client, 336 transit) != iscsiAuthStatusNoError) { 337 (void) snprintf(debug, sizeof (debug), 338 "iscsi connection(%u) login failed - " 339 "authentication transmit failed", c->c_num); 340 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 341 break; 342 } 343 344 /* 345 * scan the text data 346 */ 347 text = c->auth_text; 348 end = text + c->auth_text_length; 349 more_text: 350 while (text && (text < end)) { 351 char *value = NULL; 352 char *value_end = NULL; 353 keytype = iscsiAuthKeyTypeNone; 354 355 /* 356 * skip any NULs separating each text key=value pair 357 */ 358 while ((text < end) && (*text == '\0')) { 359 text++; 360 } 361 if (text >= end) { 362 break; 363 } 364 365 while (iscsiAuthClientGetNextKeyType(&keytype) == 366 iscsiAuthStatusNoError) { 367 char *key = 368 (char *)iscsiAuthClientGetKeyName(keytype); 369 if ((key) && 370 (iscsi_find_key_value(key, text, end, 371 &value, &value_end))) { 372 (void) snprintf(debug, sizeof (debug), 373 "%s=%s", key, value); 374 queue_str(c->c_mgmtq, Q_CONN_ERRS, 375 msg_log, debug); 376 if (iscsiAuthClientRecvKeyValue( 377 auth_client, keytype, value) 378 != iscsiAuthStatusNoError) { 379 (void) snprintf(debug, 380 sizeof (debug), 381 "iscsi connection(%u) login" 382 "failed - can't accept " 383 "%s in security stage", 384 c->c_num, text); 385 queue_str(c->c_mgmtq, 386 Q_CONN_ERRS, 387 msg_log, debug); 388 } 389 text = value_end; 390 goto more_text; 391 } 392 } 393 } 394 395 switch (iscsiAuthClientRecvEnd(auth_client, iscsi_null_callback, 396 (void *)c->c_sess, NULL)) { 397 case iscsiAuthStatusContinue: 398 /* 399 * continue sending PDUs 400 */ 401 break; 402 403 case iscsiAuthStatusPass: 404 c->c_auth_pass = 1; 405 break; 406 407 case iscsiAuthStatusInProgress: 408 /* 409 * this should only occur if we were authenticating the 410 * target, which we don't do yet, so treat this as an 411 * error. 412 */ 413 case iscsiAuthStatusNoError: 414 /* 415 * treat this as an error, since we should get a 416 * different code 417 */ 418 case iscsiAuthStatusError: 419 case iscsiAuthStatusFail: 420 default: 421 debug_status = 0; 422 423 (void) iscsiAuthClientGetDebugStatus(auth_client, 424 &debug_status); 425 (void) snprintf(debug, sizeof (debug), 426 "iscsi connection(%u) authentication failed (%s)", 427 c->c_num, iscsiAuthClientDebugStatusToText( 428 debug_status)); 429 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 430 431 send_login_reject(c, &lh, 432 (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | 433 ISCSI_LOGIN_STATUS_AUTH_FAILED); 434 conn_state(c, T7); 435 rval = False; 436 break; 437 } 438 439 if (rval == False) 440 break; 441 442 keytype = iscsiAuthKeyTypeNone; 443 rc = iscsiAuthClientSendTransitBit(auth_client, &transit); 444 445 /* 446 * see if we're ready for a stage change 447 */ 448 if (rc == iscsiAuthStatusNoError) { 449 if (transit) { 450 rsp->flags = lh.flags; 451 } 452 453 } else { 454 send_login_reject(c, &lh, 455 (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | 456 ISCSI_LOGIN_STATUS_AUTH_FAILED); 457 (void) snprintf(debug, sizeof (debug), 458 "CON%x SecurityNegotiation: wants", c->c_num); 459 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 460 conn_state(c, T7); 461 rval = False; 462 } 463 464 /* 465 * enumerate all the keys the auth code might want to send 466 */ 467 while (iscsiAuthClientGetNextKeyType(&keytype) == 468 iscsiAuthStatusNoError) { 469 int present = 0; 470 char *key = (char *)iscsiAuthClientGetKeyName(keytype); 471 int key_length = key ? strlen(key) : 0; 472 int pdu_length = ntoh24(rsp->dlength); 473 char *auth_value = NULL; 474 unsigned int max_length = ISCSI_DEFAULT_MAX_XMIT_SEG_LEN 475 - (pdu_length + key_length + 1); /* FIXME: check */ 476 477 /* 478 * add the key/value pairs the auth code wants to 479 * send directly to the PDU, since they could in 480 * theory be large. 481 */ 482 if ((auth_value = (char *)malloc(max_length)) == 483 NULL) { 484 send_login_reject(c, &lh, 485 (ISCSI_STATUS_CLASS_TARGET_ERR << 8) | 486 ISCSI_LOGIN_STATUS_TARGET_ERROR); 487 488 (void) snprintf(debug, sizeof (debug), 489 "CON%x Norm: Failed alloc auth_key %S=%s", 490 c->c_num, key, auth_value); 491 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, 492 debug); 493 conn_state(c, T7); 494 rval = False; 495 break; 496 } 497 rc = iscsiAuthClientSendKeyValue(auth_client, keytype, 498 &present, auth_value, max_length); 499 if ((rc == iscsiAuthStatusNoError) && present) { 500 (void) snprintf(debug, sizeof (debug), 501 "key:%s, auth_value:%s\n", key, auth_value); 502 queue_str(c->c_mgmtq, Q_CONN_LOGIN, msg_log, 503 debug); 504 505 rval = add_text(&text_rsp, &text_length, 506 key, auth_value); 507 if (rval == False) { 508 send_login_reject(c, &lh, 509 (ISCSI_STATUS_CLASS_TARGET_ERR << 510 8) | 511 ISCSI_LOGIN_STATUS_TARGET_ERROR); 512 (void) snprintf(debug, sizeof (debug), 513 "CON%x Norm: Failed to add %S=%s", 514 c->c_num, key, auth_value); 515 queue_str(c->c_mgmtq, Q_CONN_ERRS, 516 msg_log, debug); 517 conn_state(c, T7); 518 } 519 } 520 if (auth_value != NULL) 521 free(auth_value); 522 } 523 524 break; 525 526 case ISCSI_OP_PARMS_NEGOTIATION_STAGE: 527 528 /* 529 * Gather up the parameters sent across and build a response 530 * based on any selection required. 531 */ 532 if ((rval = parse_text(c, ntoh24(lh.dlength), &text_rsp, 533 &text_length, &errcode)) == False) { 534 535 send_login_reject(c, &lh, errcode); 536 (void) snprintf(debug, sizeof (debug), 537 "CON%x Norm: parse_text failed", c->c_num); 538 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 539 conn_state(c, T7); 540 break; 541 } 542 543 /* 544 * If the connection hasn't passed authentication and 545 * it's a normal session see if this connection MUST 546 * have gone through authentication first. If the 547 * initiator has a CHAP secret stored that means we 548 * want to validate. 549 */ 550 if ((c->c_auth_pass == 0) && 551 (c->c_sess->s_type == SessionNormal)) { 552 if ((tnode = find_target_node(c->c_sess->s_t_name)) == 553 NULL) { 554 send_login_reject(c, &lh, 555 (ISCSI_STATUS_CLASS_TARGET_ERR << 8) | 556 ISCSI_LOGIN_STATUS_TARGET_ERROR); 557 (void) snprintf(debug, sizeof (debug), 558 "CON%x No target node in login", 559 c->c_num); 560 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, 561 debug); 562 conn_state(c, T7); 563 } 564 565 /* 566 * check_access will return True if the initiator 567 * is required to use CHAP authentication. So if 568 * true and we're here it means that the initiator 569 * is trying to skip the authentication step. 570 */ 571 if (check_access(tnode, c->c_sess->s_i_name, True) == 572 False) { 573 send_login_reject(c, &lh, 574 (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | 575 ISCSI_LOGIN_STATUS_AUTH_FAILED); 576 (void) snprintf(debug, sizeof (debug), 577 "CON%x Authentication required for %s", 578 c->c_num, c->c_sess->s_i_name); 579 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, 580 debug); 581 conn_state(c, T7); 582 } 583 } 584 585 if ((rval = check_for_valid_I_T(c)) == False) { 586 send_login_reject(c, &lh, 587 (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | 588 ISCSI_LOGIN_STATUS_INIT_ERR); 589 590 (void) snprintf(debug, sizeof (debug), 591 "CON%x Norm: bad I or T", c->c_num); 592 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 593 conn_state(c, T7); 594 break; 595 } 596 597 /* 598 * We accept transition and stage information as is 599 * and echo it back because at this point there's no need 600 * to send a parameter to the Initiator and expect a 601 * reply. 602 */ 603 rsp->flags = lh.flags; 604 605 break; 606 607 case ISCSI_FULL_FEATURE_PHASE: 608 /* can't jump directly to full feature phase */ 609 (void) snprintf(debug, sizeof (debug), 610 "CON%x Protocol error: wrong stage", c->c_num); 611 queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); 612 send_login_reject(c, &lh, 613 (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | 614 ISCSI_LOGIN_STATUS_INIT_ERR); 615 conn_state(c, T7); 616 rval = False; 617 break; 618 619 default: 620 /* just drop the connection since we don't know what's up */ 621 rval = False; 622 break; 623 } 624 625 hton24(rsp->dlength, text_length); 626 if ((rval == True) && (session_validate(c->c_sess) == True)) { 627 628 if (ISCSI_LOGIN_RESPONSE_ENABLED()) { 629 uiscsiproto_t info; 630 char nil = '\0'; 631 632 info.uip_target_addr = &c->c_target_sockaddr; 633 info.uip_initiator_addr = &c->c_initiator_sockaddr; 634 635 info.uip_target = &nil; 636 info.uip_initiator = c->c_sess->s_i_name; 637 info.uip_lun = 0; 638 639 info.uip_itt = rsp->itt; 640 info.uip_ttt = ISCSI_RSVD_TASK_TAG; 641 642 info.uip_cmdsn = ntohl(rsp->expcmdsn); 643 info.uip_statsn = ntohl(rsp->statsn); 644 info.uip_datasn = 0; 645 646 info.uip_datalen = text_length; 647 info.uip_flags = rsp->flags; 648 649 ISCSI_LOGIN_RESPONSE(&info); 650 } 651 652 send_iscsi_pkt(c, (iscsi_hdr_t *)rsp, text_rsp); 653 654 if ((lh.flags & ISCSI_FLAG_LOGIN_TRANSIT) && 655 (ISCSI_LOGIN_NEXT_STAGE(lh.flags) == 656 ISCSI_FULL_FEATURE_PHASE)) { 657 658 conn_state(c, T5); 659 660 /* 661 * At this point we've completed the negotiation 662 * of all login parameters. Now we need to perform 663 * some quick boundary checks and then send a couple 664 * pieces of information to STE for it's use. 665 */ 666 c->c_max_burst_len = MIN(c->c_max_burst_len, 667 c->c_max_recv_data); 668 } 669 } 670 671 if (text_rsp != NULL) 672 free(text_rsp); 673 if (rsp != NULL) 674 free(rsp); 675 676 return (rval); 677 } 678 679 /* 680 * check_for_valid_I_T -- check to see if we have valid names 681 * 682 * This routine checks to see if we have received a valid InitiatorName 683 * and TargetName which is the bare minimum which an Initiator must send 684 * across during the login phase. 685 */ 686 static Boolean_t 687 check_for_valid_I_T(iscsi_conn_t *c) 688 { 689 iscsi_sess_t *s = c->c_sess; 690 if (s->s_type == SessionDiscovery) 691 return (s->s_i_name == NULL || strlen(s->s_i_name) == 0) ? 692 False : True; 693 else 694 return (s->s_t_name == NULL || strlen(s->s_t_name) == 0) || 695 (s->s_i_name == NULL || strlen(s->s_i_name) == 0) ? 696 False : True; 697 } 698 699 static iscsi_login_rsp_hdr_t * 700 make_login_response(iscsi_conn_t *c, iscsi_login_hdr_t *lhp) 701 { 702 iscsi_login_rsp_hdr_t *r; 703 704 if (lhp->tsid != 0) 705 /* don't except existing sessions for now */ 706 return (NULL); 707 708 r = (iscsi_login_rsp_hdr_t *)calloc(sizeof (*r), sizeof (char)); 709 if (r == NULL) 710 return (NULL); 711 712 bcopy(lhp->isid, r->isid, 6); /* 6 is defined by protocol */ 713 r->opcode = ISCSI_OP_LOGIN_RSP; 714 r->flags = ISCSI_FLAG_LOGIN_TRANSIT; 715 r->max_version = ISCSI_MAX_VERSION; 716 r->active_version = ISCSI_MIN_VERSION; 717 r->itt = lhp->itt; 718 719 /* 720 * As per section 10.13.3 of iSCSI RFC (3720), For a new session, 721 * the target MUST generate a non-zero TSIH and ONLY return it 722 * in the Login Final-Response 723 */ 724 if ((lhp->flags & ISCSI_FLAG_LOGIN_TRANSIT) && 725 (ISCSI_LOGIN_NEXT_STAGE(lhp->flags) == 726 ISCSI_FULL_FEATURE_PHASE)) 727 /* 728 * If this is the final Login Response, send the target 729 * calculated TSIH 730 */ 731 r->tsid = htons(c->c_sess->s_tsid); 732 else 733 /* 734 * If this is not the final Login Response, send the TSIH value 735 * provided by the initiator. 736 */ 737 r->tsid = lhp->tsid; 738 739 (void) pthread_mutex_lock(&c->c_mutex); 740 r->statsn = htonl(c->c_statsn++); 741 (void) pthread_mutex_unlock(&c->c_mutex); 742 if (c->c_sess != NULL) { 743 (void) pthread_mutex_lock(&c->c_sess->s_mutex); 744 /* ---- cmdsn is not advanced during login ---- */ 745 r->expcmdsn = htonl(c->c_sess->s_seencmdsn); 746 r->maxcmdsn = htonl(CMD_MAXOUTSTANDING + 747 c->c_sess->s_seencmdsn); 748 (void) pthread_mutex_unlock(&c->c_sess->s_mutex); 749 } 750 751 return (r); 752 } 753 754 static void 755 send_login_reject(iscsi_conn_t *c, iscsi_login_hdr_t *lhp, int err_code) 756 { 757 iscsi_login_rsp_hdr_t *r; 758 759 if ((r = make_login_response(c, lhp)) == NULL) 760 return; 761 762 r->status_class = (err_code >> 8) & 0xff; 763 r->status_detail = err_code & 0xff; 764 765 if (ISCSI_LOGIN_RESPONSE_ENABLED()) { 766 uiscsiproto_t info; 767 char nil = '\0'; 768 769 info.uip_target_addr = &c->c_target_sockaddr; 770 info.uip_initiator_addr = &c->c_initiator_sockaddr; 771 772 info.uip_target = &nil; 773 info.uip_initiator = &nil; 774 info.uip_lun = 0; 775 776 info.uip_itt = r->itt; 777 info.uip_ttt = ISCSI_RSVD_TASK_TAG; 778 779 info.uip_cmdsn = ntohl(r->expcmdsn); 780 info.uip_statsn = ntohl(r->statsn); 781 info.uip_datasn = 0; 782 783 info.uip_datalen = ntoh24(r->dlength); 784 info.uip_flags = r->flags; 785 786 ISCSI_LOGIN_RESPONSE(&info); 787 } 788 789 (void) write(c->c_fd, r, sizeof (*r)); 790 free(r); 791 } 792 793 static auth_action_t 794 login_set_auth(iscsi_sess_t *s) 795 { 796 tgt_node_t *xnInitiator = NULL; 797 tgt_node_t *xnTarget = NULL; 798 tgt_node_t *xnAcl = NULL; 799 char *szIniAlias = NULL; 800 char *szIscsiName = NULL; 801 char *szChapName = NULL; 802 char *szChapSecret = NULL; 803 char *possible = NULL; 804 iscsi_auth_t *sess_auth = &(s->sess_auth); 805 int comp = 0; 806 int username_len = 0; 807 808 bzero(sess_auth->username_in, sizeof (sess_auth->username_in)); 809 bzero(sess_auth->password_in, sizeof (sess_auth->password_in)); 810 sess_auth->password_length_in = 0; 811 812 /* Load alias, iscsi-name, chap-name, chap-secret from config file */ 813 while ((xnInitiator = tgt_node_next_child(main_config, XML_ELEMENT_INIT, 814 xnInitiator)) != NULL) { 815 816 (void) tgt_find_value_str(xnInitiator, XML_ELEMENT_INIT, 817 &szIniAlias); 818 819 if (tgt_find_value_str(xnInitiator, XML_ELEMENT_INAME, 820 &szIscsiName) == True) { 821 822 comp = strcmp(s->s_i_name, szIscsiName); 823 free(szIscsiName); 824 szIscsiName = NULL; 825 826 if (comp == 0) { 827 828 if (tgt_find_value_str(xnInitiator, 829 XML_ELEMENT_CHAPNAME, 830 &szChapName) == True) { 831 /*CSTYLED*/ 832 (void) strcpy( 833 (char *)sess_auth->username_in, 834 szChapName); 835 username_len = strlen(szChapName); 836 free(szChapName); 837 } 838 839 if (tgt_find_value_str(xnInitiator, 840 XML_ELEMENT_CHAPSECRET, 841 &szChapSecret) == True) { 842 /*CSTYLED*/ 843 (void) strcpy( 844 (char *)sess_auth->password_in, 845 szChapSecret); 846 sess_auth->password_length_in = 847 strlen(szChapSecret); 848 free(szChapSecret); 849 } 850 break; 851 } 852 } 853 } 854 855 if (s->s_type == SessionDiscovery) { 856 return (LOGIN_NO_AUTH); 857 } 858 859 if (s->s_t_name == NULL) { 860 /* 861 * Should not happen for non-discovery session 862 */ 863 return (LOGIN_DROP); 864 } 865 866 /* 867 * If iSNS enabled set LOGIN_AUTH 868 */ 869 if (isns_enabled() == True) { 870 if (username_len == 0) 871 return (LOGIN_NO_AUTH); 872 return (LOGIN_AUTH); 873 } 874 875 /* 876 * If no acc_list for current target 877 * If no CHAP secret for the initiator, transit. 878 * If CHAP secret exists for the initiator, it must be authed. 879 * If acc_list exists for the target, and 880 * If the initiator not in the list, drop it. 881 * If the initiator in the list, and 882 * If no CHAP name for the initiator, transit. 883 * If a CHAP name exists for the initiator, it must be authed. 884 */ 885 886 while ((xnTarget = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, 887 xnTarget)) != NULL) { 888 889 if ((tgt_find_value_str(xnTarget, XML_ELEMENT_INAME, 890 &szIscsiName) == False) || (szIscsiName == NULL)) { 891 return (LOGIN_DROP); 892 } 893 894 comp = strcmp(szIscsiName, s->s_t_name); 895 free(szIscsiName); 896 szIscsiName = NULL; 897 898 if (comp == 0) { 899 900 if ((xnAcl = tgt_node_next(xnTarget, 901 XML_ELEMENT_ACLLIST, 0)) == NULL) { 902 /* 903 * No acl_list found, return auth or no auth 904 */ 905 if (username_len == 0) 906 return (LOGIN_NO_AUTH); 907 return (LOGIN_AUTH); 908 } 909 910 /* 911 * This target has an access_list. Now compare 912 * those entries against the initiator who started 913 * this session. 914 */ 915 xnInitiator = NULL; 916 while ((xnInitiator = tgt_node_next(xnAcl, 917 XML_ELEMENT_INIT, xnInitiator)) != NULL) { 918 919 if ((tgt_find_value_str(xnInitiator, 920 XML_ELEMENT_INIT, &possible) == False) || 921 (possible == NULL)) 922 continue; 923 924 if (strcmp(szIniAlias, possible) == 0) { 925 /* 926 * Found the initiator in acl-list, 927 * authentication needed 928 */ 929 free(possible); 930 if (username_len == 0) 931 return (LOGIN_NO_AUTH); 932 else 933 return (LOGIN_AUTH); 934 } 935 936 free(possible); 937 possible = NULL; 938 } 939 /* 940 * Acl-list exists, while the initiator is not found in 941 * the list, we should drop the connection 942 */ 943 return (LOGIN_DROP); 944 } 945 } 946 947 /* False means Need authentication */ 948 return (LOGIN_AUTH); 949 } 950