1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2012 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * This software was developed by Edward Tomasz Napierala under sponsorship 8 * from the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD$"); 35 36#include <sys/types.h> 37#include <sys/ioctl.h> 38#include <assert.h> 39#include <stdbool.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <netinet/in.h> 44 45#include "iscsid.h" 46#include "iscsi_proto.h" 47 48static int 49login_nsg(const struct pdu *response) 50{ 51 struct iscsi_bhs_login_response *bhslr; 52 53 bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs; 54 55 return (bhslr->bhslr_flags & 0x03); 56} 57 58static void 59login_set_nsg(struct pdu *request, int nsg) 60{ 61 struct iscsi_bhs_login_request *bhslr; 62 63 assert(nsg == BHSLR_STAGE_SECURITY_NEGOTIATION || 64 nsg == BHSLR_STAGE_OPERATIONAL_NEGOTIATION || 65 nsg == BHSLR_STAGE_FULL_FEATURE_PHASE); 66 67 bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs; 68 69 bhslr->bhslr_flags &= 0xFC; 70 bhslr->bhslr_flags |= nsg; 71} 72 73static void 74login_set_csg(struct pdu *request, int csg) 75{ 76 struct iscsi_bhs_login_request *bhslr; 77 78 assert(csg == BHSLR_STAGE_SECURITY_NEGOTIATION || 79 csg == BHSLR_STAGE_OPERATIONAL_NEGOTIATION || 80 csg == BHSLR_STAGE_FULL_FEATURE_PHASE); 81 82 bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs; 83 84 bhslr->bhslr_flags &= 0xF3; 85 bhslr->bhslr_flags |= csg << 2; 86} 87 88static const char * 89login_target_error_str(int class, int detail) 90{ 91 static char msg[128]; 92 93 /* 94 * RFC 3270, 10.13.5. Status-Class and Status-Detail 95 */ 96 switch (class) { 97 case 0x01: 98 switch (detail) { 99 case 0x01: 100 return ("Target moved temporarily"); 101 case 0x02: 102 return ("Target moved permanently"); 103 default: 104 snprintf(msg, sizeof(msg), "unknown redirection; " 105 "Status-Class 0x%x, Status-Detail 0x%x", 106 class, detail); 107 return (msg); 108 } 109 case 0x02: 110 switch (detail) { 111 case 0x00: 112 return ("Initiator error"); 113 case 0x01: 114 return ("Authentication failure"); 115 case 0x02: 116 return ("Authorization failure"); 117 case 0x03: 118 return ("Not found"); 119 case 0x04: 120 return ("Target removed"); 121 case 0x05: 122 return ("Unsupported version"); 123 case 0x06: 124 return ("Too many connections"); 125 case 0x07: 126 return ("Missing parameter"); 127 case 0x08: 128 return ("Can't include in session"); 129 case 0x09: 130 return ("Session type not supported"); 131 case 0x0a: 132 return ("Session does not exist"); 133 case 0x0b: 134 return ("Invalid during login"); 135 default: 136 snprintf(msg, sizeof(msg), "unknown initiator error; " 137 "Status-Class 0x%x, Status-Detail 0x%x", 138 class, detail); 139 return (msg); 140 } 141 case 0x03: 142 switch (detail) { 143 case 0x00: 144 return ("Target error"); 145 case 0x01: 146 return ("Service unavailable"); 147 case 0x02: 148 return ("Out of resources"); 149 default: 150 snprintf(msg, sizeof(msg), "unknown target error; " 151 "Status-Class 0x%x, Status-Detail 0x%x", 152 class, detail); 153 return (msg); 154 } 155 default: 156 snprintf(msg, sizeof(msg), "unknown error; " 157 "Status-Class 0x%x, Status-Detail 0x%x", 158 class, detail); 159 return (msg); 160 } 161} 162 163static void 164kernel_modify(const struct connection *conn, const char *target_address) 165{ 166 struct iscsi_session_modify ism; 167 int error; 168 169 memset(&ism, 0, sizeof(ism)); 170 ism.ism_session_id = conn->conn_session_id; 171 memcpy(&ism.ism_conf, &conn->conn_conf, sizeof(ism.ism_conf)); 172 strlcpy(ism.ism_conf.isc_target_addr, target_address, 173 sizeof(ism.ism_conf.isc_target)); 174 error = ioctl(conn->conn_iscsi_fd, ISCSISMODIFY, &ism); 175 if (error != 0) { 176 log_err(1, "failed to redirect to %s: ISCSISMODIFY", 177 target_address); 178 } 179} 180 181/* 182 * XXX: The way it works is suboptimal; what should happen is described 183 * in draft-gilligan-iscsi-fault-tolerance-00. That, however, would 184 * be much more complicated: we would need to keep "dependencies" 185 * for sessions, so that, in case described in draft and using draft 186 * terminology, we would have three sessions: one for discovery, 187 * one for initial target portal, and one for redirect portal. 188 * This would allow us to "backtrack" on connection failure, 189 * as described in draft. 190 */ 191static void 192login_handle_redirection(struct connection *conn, struct pdu *response) 193{ 194 struct iscsi_bhs_login_response *bhslr; 195 struct keys *response_keys; 196 const char *target_address; 197 198 bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs; 199 assert (bhslr->bhslr_status_class == 1); 200 201 response_keys = keys_new(); 202 keys_load(response_keys, response); 203 204 target_address = keys_find(response_keys, "TargetAddress"); 205 if (target_address == NULL) 206 log_errx(1, "received redirection without TargetAddress"); 207 if (target_address[0] == '\0') 208 log_errx(1, "received redirection with empty TargetAddress"); 209 if (strlen(target_address) >= 210 sizeof(conn->conn_conf.isc_target_addr) - 1) 211 log_errx(1, "received TargetAddress is too long"); 212 213 log_debugx("received redirection to \"%s\"", target_address); 214 kernel_modify(conn, target_address); 215 keys_delete(response_keys); 216} 217 218static struct pdu * 219login_receive(struct connection *conn) 220{ 221 struct pdu *response; 222 struct iscsi_bhs_login_response *bhslr; 223 const char *errorstr; 224 static bool initial = true; 225 226 response = pdu_new(conn); 227 pdu_receive(response); 228 if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_LOGIN_RESPONSE) { 229 log_errx(1, "protocol error: received invalid opcode 0x%x", 230 response->pdu_bhs->bhs_opcode); 231 } 232 bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs; 233 /* 234 * XXX: Implement the C flag some day. 235 */ 236 if ((bhslr->bhslr_flags & BHSLR_FLAGS_CONTINUE) != 0) 237 log_errx(1, "received Login PDU with unsupported \"C\" flag"); 238 if (bhslr->bhslr_version_max != 0x00) 239 log_errx(1, "received Login PDU with unsupported " 240 "Version-max 0x%x", bhslr->bhslr_version_max); 241 if (bhslr->bhslr_version_active != 0x00) 242 log_errx(1, "received Login PDU with unsupported " 243 "Version-active 0x%x", bhslr->bhslr_version_active); 244 if (bhslr->bhslr_status_class == 1) { 245 login_handle_redirection(conn, response); 246 log_debugx("redirection handled; exiting"); 247 exit(0); 248 } 249 if (bhslr->bhslr_status_class != 0) { 250 errorstr = login_target_error_str(bhslr->bhslr_status_class, 251 bhslr->bhslr_status_detail); 252 fail(conn, errorstr); 253 log_errx(1, "target returned error: %s", errorstr); 254 } 255 if (initial == false && 256 ntohl(bhslr->bhslr_statsn) != conn->conn_statsn + 1) { 257 /* 258 * It's a warning, not an error, to work around what seems 259 * to be bug in NetBSD iSCSI target. 260 */ 261 log_warnx("received Login PDU with wrong StatSN: " 262 "is %u, should be %u", ntohl(bhslr->bhslr_statsn), 263 conn->conn_statsn + 1); 264 } 265 conn->conn_tsih = ntohs(bhslr->bhslr_tsih); 266 conn->conn_statsn = ntohl(bhslr->bhslr_statsn); 267 268 initial = false; 269 270 return (response); 271} 272 273static struct pdu * 274login_new_request(struct connection *conn, int csg) 275{ 276 struct pdu *request; 277 struct iscsi_bhs_login_request *bhslr; 278 int nsg; 279 280 request = pdu_new(conn); 281 bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs; 282 bhslr->bhslr_opcode = ISCSI_BHS_OPCODE_LOGIN_REQUEST | 283 ISCSI_BHS_OPCODE_IMMEDIATE; 284 285 bhslr->bhslr_flags = BHSLR_FLAGS_TRANSIT; 286 switch (csg) { 287 case BHSLR_STAGE_SECURITY_NEGOTIATION: 288 nsg = BHSLR_STAGE_OPERATIONAL_NEGOTIATION; 289 break; 290 case BHSLR_STAGE_OPERATIONAL_NEGOTIATION: 291 nsg = BHSLR_STAGE_FULL_FEATURE_PHASE; 292 break; 293 default: 294 assert(!"invalid csg"); 295 log_errx(1, "invalid csg %d", csg); 296 } 297 login_set_csg(request, csg); 298 login_set_nsg(request, nsg); 299 300 memcpy(bhslr->bhslr_isid, &conn->conn_isid, sizeof(bhslr->bhslr_isid)); 301 bhslr->bhslr_tsih = htons(conn->conn_tsih); 302 bhslr->bhslr_initiator_task_tag = 0; 303 bhslr->bhslr_cmdsn = 0; 304 bhslr->bhslr_expstatsn = htonl(conn->conn_statsn + 1); 305 306 return (request); 307} 308 309static int 310login_list_prefers(const char *list, 311 const char *choice1, const char *choice2) 312{ 313 char *tofree, *str, *token; 314 315 tofree = str = checked_strdup(list); 316 317 while ((token = strsep(&str, ",")) != NULL) { 318 if (strcmp(token, choice1) == 0) { 319 free(tofree); 320 return (1); 321 } 322 if (strcmp(token, choice2) == 0) { 323 free(tofree); 324 return (2); 325 } 326 } 327 free(tofree); 328 return (-1); 329} 330 331static void 332login_negotiate_key(struct connection *conn, const char *name, 333 const char *value) 334{ 335 struct iscsi_session_limits *isl; 336 int which, tmp; 337 338 isl = &conn->conn_limits; 339 if (strcmp(name, "TargetAlias") == 0) { 340 strlcpy(conn->conn_target_alias, value, 341 sizeof(conn->conn_target_alias)); 342 } else if (strcmp(value, "Irrelevant") == 0) { 343 /* Ignore. */ 344 } else if (strcmp(name, "iSCSIProtocolLevel") == 0) { 345 tmp = strtoul(value, NULL, 10); 346 if (tmp < 0 || tmp > 31) 347 log_errx(1, "received invalid iSCSIProtocolLevel"); 348 conn->conn_protocol_level = tmp; 349 } else if (strcmp(name, "HeaderDigest") == 0) { 350 which = login_list_prefers(value, "CRC32C", "None"); 351 switch (which) { 352 case 1: 353 log_debugx("target prefers CRC32C " 354 "for header digest; we'll use it"); 355 conn->conn_header_digest = CONN_DIGEST_CRC32C; 356 break; 357 case 2: 358 log_debugx("target prefers not to do " 359 "header digest; we'll comply"); 360 break; 361 default: 362 log_warnx("target sent unrecognized " 363 "HeaderDigest value \"%s\"; will use None", value); 364 break; 365 } 366 } else if (strcmp(name, "DataDigest") == 0) { 367 which = login_list_prefers(value, "CRC32C", "None"); 368 switch (which) { 369 case 1: 370 log_debugx("target prefers CRC32C " 371 "for data digest; we'll use it"); 372 conn->conn_data_digest = CONN_DIGEST_CRC32C; 373 break; 374 case 2: 375 log_debugx("target prefers not to do " 376 "data digest; we'll comply"); 377 break; 378 default: 379 log_warnx("target sent unrecognized " 380 "DataDigest value \"%s\"; will use None", value); 381 break; 382 } 383 } else if (strcmp(name, "MaxConnections") == 0) { 384 /* Ignore. */ 385 } else if (strcmp(name, "InitialR2T") == 0) { 386 if (strcmp(value, "Yes") == 0) 387 conn->conn_initial_r2t = true; 388 else 389 conn->conn_initial_r2t = false; 390 } else if (strcmp(name, "ImmediateData") == 0) { 391 if (strcmp(value, "Yes") == 0) 392 conn->conn_immediate_data = true; 393 else 394 conn->conn_immediate_data = false; 395 } else if (strcmp(name, "MaxRecvDataSegmentLength") == 0) { 396 tmp = strtoul(value, NULL, 10); 397 if (tmp <= 0) 398 log_errx(1, "received invalid " 399 "MaxRecvDataSegmentLength"); 400 if (tmp > isl->isl_max_send_data_segment_length) { 401 log_debugx("capping max_send_data_segment_length " 402 "from %d to %d", tmp, 403 isl->isl_max_send_data_segment_length); 404 tmp = isl->isl_max_send_data_segment_length; 405 } 406 conn->conn_max_send_data_segment_length = tmp; 407 /* We received target's limit, that means it accepted our's. */ 408 conn->conn_max_recv_data_segment_length = 409 isl->isl_max_recv_data_segment_length; 410 } else if (strcmp(name, "MaxBurstLength") == 0) { 411 tmp = strtoul(value, NULL, 10); 412 if (tmp <= 0) 413 log_errx(1, "received invalid MaxBurstLength"); 414 if (tmp > isl->isl_max_burst_length) { 415 log_debugx("capping MaxBurstLength " 416 "from %d to %d", tmp, isl->isl_max_burst_length); 417 tmp = isl->isl_max_burst_length; 418 } 419 conn->conn_max_burst_length = tmp; 420 } else if (strcmp(name, "FirstBurstLength") == 0) { 421 tmp = strtoul(value, NULL, 10); 422 if (tmp <= 0) 423 log_errx(1, "received invalid FirstBurstLength"); 424 if (tmp > isl->isl_first_burst_length) { 425 log_debugx("capping FirstBurstLength " 426 "from %d to %d", tmp, isl->isl_first_burst_length); 427 tmp = isl->isl_first_burst_length; 428 } 429 conn->conn_first_burst_length = tmp; 430 } else if (strcmp(name, "DefaultTime2Wait") == 0) { 431 /* Ignore */ 432 } else if (strcmp(name, "DefaultTime2Retain") == 0) { 433 /* Ignore */ 434 } else if (strcmp(name, "MaxOutstandingR2T") == 0) { 435 /* Ignore */ 436 } else if (strcmp(name, "DataPDUInOrder") == 0) { 437 /* Ignore */ 438 } else if (strcmp(name, "DataSequenceInOrder") == 0) { 439 /* Ignore */ 440 } else if (strcmp(name, "ErrorRecoveryLevel") == 0) { 441 /* Ignore */ 442 } else if (strcmp(name, "OFMarker") == 0) { 443 /* Ignore */ 444 } else if (strcmp(name, "IFMarker") == 0) { 445 /* Ignore */ 446 } else if (strcmp(name, "RDMAExtensions") == 0) { 447 if (conn->conn_conf.isc_iser == 1 && 448 strcmp(value, "Yes") != 0) { 449 log_errx(1, "received unsupported RDMAExtensions"); 450 } 451 } else if (strcmp(name, "InitiatorRecvDataSegmentLength") == 0) { 452 tmp = strtoul(value, NULL, 10); 453 if (tmp <= 0) 454 log_errx(1, "received invalid " 455 "InitiatorRecvDataSegmentLength"); 456 if ((int)tmp > isl->isl_max_recv_data_segment_length) { 457 log_debugx("capping InitiatorRecvDataSegmentLength " 458 "from %d to %d", tmp, 459 isl->isl_max_recv_data_segment_length); 460 tmp = isl->isl_max_recv_data_segment_length; 461 } 462 conn->conn_max_recv_data_segment_length = tmp; 463 } else if (strcmp(name, "TargetPortalGroupTag") == 0) { 464 /* Ignore */ 465 } else if (strcmp(name, "TargetRecvDataSegmentLength") == 0) { 466 tmp = strtoul(value, NULL, 10); 467 if (tmp <= 0) { 468 log_errx(1, 469 "received invalid TargetRecvDataSegmentLength"); 470 } 471 if (tmp > isl->isl_max_send_data_segment_length) { 472 log_debugx("capping TargetRecvDataSegmentLength " 473 "from %d to %d", tmp, 474 isl->isl_max_send_data_segment_length); 475 tmp = isl->isl_max_send_data_segment_length; 476 } 477 conn->conn_max_send_data_segment_length = tmp; 478 } else { 479 log_debugx("unknown key \"%s\"; ignoring", name); 480 } 481} 482 483static void 484login_negotiate(struct connection *conn) 485{ 486 struct pdu *request, *response; 487 struct keys *request_keys, *response_keys; 488 struct iscsi_bhs_login_response *bhslr; 489 int i, nrequests = 0; 490 struct iscsi_session_limits *isl; 491 492 log_debugx("beginning operational parameter negotiation"); 493 request = login_new_request(conn, BHSLR_STAGE_OPERATIONAL_NEGOTIATION); 494 request_keys = keys_new(); 495 496 isl = &conn->conn_limits; 497 log_debugx("Limits for offload \"%s\" are " 498 "MaxRecvDataSegment=%d, max_send_dsl=%d, " 499 "MaxBurstLength=%d, FirstBurstLength=%d", 500 conn->conn_conf.isc_offload, isl->isl_max_recv_data_segment_length, 501 isl->isl_max_send_data_segment_length, isl->isl_max_burst_length, 502 isl->isl_first_burst_length); 503 504 /* 505 * The following keys are irrelevant for discovery sessions. 506 */ 507 if (conn->conn_conf.isc_discovery == 0) { 508 keys_add(request_keys, "iSCSIProtocolLevel", "2"); 509 if (conn->conn_conf.isc_header_digest != 0) 510 keys_add(request_keys, "HeaderDigest", "CRC32C"); 511 else 512 keys_add(request_keys, "HeaderDigest", "None"); 513 if (conn->conn_conf.isc_data_digest != 0) 514 keys_add(request_keys, "DataDigest", "CRC32C"); 515 else 516 keys_add(request_keys, "DataDigest", "None"); 517 518 keys_add(request_keys, "ImmediateData", "Yes"); 519 keys_add_int(request_keys, "MaxBurstLength", 520 isl->isl_max_burst_length); 521 keys_add_int(request_keys, "FirstBurstLength", 522 isl->isl_first_burst_length); 523 keys_add(request_keys, "InitialR2T", "Yes"); 524 keys_add(request_keys, "MaxOutstandingR2T", "1"); 525 if (conn->conn_conf.isc_iser == 1) { 526 keys_add_int(request_keys, "InitiatorRecvDataSegmentLength", 527 isl->isl_max_recv_data_segment_length); 528 keys_add_int(request_keys, "TargetRecvDataSegmentLength", 529 isl->isl_max_send_data_segment_length); 530 keys_add(request_keys, "RDMAExtensions", "Yes"); 531 } else { 532 keys_add_int(request_keys, "MaxRecvDataSegmentLength", 533 isl->isl_max_recv_data_segment_length); 534 } 535 } else { 536 keys_add(request_keys, "HeaderDigest", "None"); 537 keys_add(request_keys, "DataDigest", "None"); 538 keys_add_int(request_keys, "MaxRecvDataSegmentLength", 539 isl->isl_max_recv_data_segment_length); 540 } 541 542 keys_add(request_keys, "DefaultTime2Wait", "0"); 543 keys_add(request_keys, "DefaultTime2Retain", "0"); 544 keys_add(request_keys, "ErrorRecoveryLevel", "0"); 545 keys_save(request_keys, request); 546 keys_delete(request_keys); 547 request_keys = NULL; 548 pdu_send(request); 549 pdu_delete(request); 550 request = NULL; 551 552 response = login_receive(conn); 553 response_keys = keys_new(); 554 keys_load(response_keys, response); 555 for (i = 0; i < KEYS_MAX; i++) { 556 if (response_keys->keys_names[i] == NULL) 557 break; 558 559 login_negotiate_key(conn, 560 response_keys->keys_names[i], response_keys->keys_values[i]); 561 } 562 563 keys_delete(response_keys); 564 response_keys = NULL; 565 566 for (;;) { 567 bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs; 568 if ((bhslr->bhslr_flags & BHSLR_FLAGS_TRANSIT) != 0) 569 break; 570 571 nrequests++; 572 if (nrequests > 5) { 573 log_warnx("received login response " 574 "without the \"T\" flag too many times; giving up"); 575 break; 576 } 577 578 log_debugx("received login response " 579 "without the \"T\" flag; sending another request"); 580 581 pdu_delete(response); 582 583 request = login_new_request(conn, 584 BHSLR_STAGE_OPERATIONAL_NEGOTIATION); 585 pdu_send(request); 586 pdu_delete(request); 587 588 response = login_receive(conn); 589 } 590 591 if (login_nsg(response) != BHSLR_STAGE_FULL_FEATURE_PHASE) 592 log_warnx("received final login response with wrong NSG 0x%x", 593 login_nsg(response)); 594 pdu_delete(response); 595 596 log_debugx("operational parameter negotiation done; " 597 "transitioning to Full Feature phase"); 598} 599 600static void 601login_send_chap_a(struct connection *conn) 602{ 603 struct pdu *request; 604 struct keys *request_keys; 605 606 request = login_new_request(conn, BHSLR_STAGE_SECURITY_NEGOTIATION); 607 request_keys = keys_new(); 608 keys_add(request_keys, "CHAP_A", "5"); 609 keys_save(request_keys, request); 610 keys_delete(request_keys); 611 pdu_send(request); 612 pdu_delete(request); 613} 614 615static void 616login_send_chap_r(struct pdu *response) 617{ 618 struct connection *conn; 619 struct pdu *request; 620 struct keys *request_keys, *response_keys; 621 struct rchap *rchap; 622 const char *chap_a, *chap_c, *chap_i; 623 char *chap_r; 624 int error; 625 char *mutual_chap_c, *mutual_chap_i; 626 627 /* 628 * As in the rest of the initiator, 'request' means 629 * 'initiator -> target', and 'response' means 'target -> initiator', 630 * 631 * So, here the 'response' from the target is the packet that contains 632 * CHAP challenge; our CHAP response goes into 'request'. 633 */ 634 635 conn = response->pdu_connection; 636 637 response_keys = keys_new(); 638 keys_load(response_keys, response); 639 640 /* 641 * First, compute the response. 642 */ 643 chap_a = keys_find(response_keys, "CHAP_A"); 644 if (chap_a == NULL) 645 log_errx(1, "received CHAP packet without CHAP_A"); 646 chap_c = keys_find(response_keys, "CHAP_C"); 647 if (chap_c == NULL) 648 log_errx(1, "received CHAP packet without CHAP_C"); 649 chap_i = keys_find(response_keys, "CHAP_I"); 650 if (chap_i == NULL) 651 log_errx(1, "received CHAP packet without CHAP_I"); 652 653 if (strcmp(chap_a, "5") != 0) { 654 log_errx(1, "received CHAP packet " 655 "with unsupported CHAP_A \"%s\"", chap_a); 656 } 657 658 rchap = rchap_new(conn->conn_conf.isc_secret); 659 error = rchap_receive(rchap, chap_i, chap_c); 660 if (error != 0) { 661 log_errx(1, "received CHAP packet " 662 "with malformed CHAP_I or CHAP_C"); 663 } 664 chap_r = rchap_get_response(rchap); 665 rchap_delete(rchap); 666 667 keys_delete(response_keys); 668 669 request = login_new_request(conn, BHSLR_STAGE_SECURITY_NEGOTIATION); 670 request_keys = keys_new(); 671 keys_add(request_keys, "CHAP_N", conn->conn_conf.isc_user); 672 keys_add(request_keys, "CHAP_R", chap_r); 673 free(chap_r); 674 675 /* 676 * If we want mutual authentication, we're expected to send 677 * our CHAP_I/CHAP_C now. 678 */ 679 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 680 log_debugx("requesting mutual authentication; " 681 "binary challenge size is %zd bytes", 682 sizeof(conn->conn_mutual_chap->chap_challenge)); 683 684 assert(conn->conn_mutual_chap == NULL); 685 conn->conn_mutual_chap = chap_new(); 686 mutual_chap_i = chap_get_id(conn->conn_mutual_chap); 687 mutual_chap_c = chap_get_challenge(conn->conn_mutual_chap); 688 keys_add(request_keys, "CHAP_I", mutual_chap_i); 689 keys_add(request_keys, "CHAP_C", mutual_chap_c); 690 free(mutual_chap_i); 691 free(mutual_chap_c); 692 } 693 694 keys_save(request_keys, request); 695 keys_delete(request_keys); 696 pdu_send(request); 697 pdu_delete(request); 698} 699 700static void 701login_verify_mutual(const struct pdu *response) 702{ 703 struct connection *conn; 704 struct keys *response_keys; 705 const char *chap_n, *chap_r; 706 int error; 707 708 conn = response->pdu_connection; 709 710 response_keys = keys_new(); 711 keys_load(response_keys, response); 712 713 chap_n = keys_find(response_keys, "CHAP_N"); 714 if (chap_n == NULL) 715 log_errx(1, "received CHAP Response PDU without CHAP_N"); 716 chap_r = keys_find(response_keys, "CHAP_R"); 717 if (chap_r == NULL) 718 log_errx(1, "received CHAP Response PDU without CHAP_R"); 719 720 error = chap_receive(conn->conn_mutual_chap, chap_r); 721 if (error != 0) 722 log_errx(1, "received CHAP Response PDU with invalid CHAP_R"); 723 724 if (strcmp(chap_n, conn->conn_conf.isc_mutual_user) != 0) { 725 fail(conn, "Mutual CHAP failed"); 726 log_errx(1, "mutual CHAP authentication failed: wrong user"); 727 } 728 729 error = chap_authenticate(conn->conn_mutual_chap, 730 conn->conn_conf.isc_mutual_secret); 731 if (error != 0) { 732 fail(conn, "Mutual CHAP failed"); 733 log_errx(1, "mutual CHAP authentication failed: wrong secret"); 734 } 735 736 keys_delete(response_keys); 737 chap_delete(conn->conn_mutual_chap); 738 conn->conn_mutual_chap = NULL; 739 740 log_debugx("mutual CHAP authentication succeeded"); 741} 742 743static void 744login_chap(struct connection *conn) 745{ 746 struct pdu *response; 747 748 log_debugx("beginning CHAP authentication; sending CHAP_A"); 749 login_send_chap_a(conn); 750 751 log_debugx("waiting for CHAP_A/CHAP_C/CHAP_I"); 752 response = login_receive(conn); 753 754 log_debugx("sending CHAP_N/CHAP_R"); 755 login_send_chap_r(response); 756 pdu_delete(response); 757 758 /* 759 * XXX: Make sure this is not susceptible to MITM. 760 */ 761 762 log_debugx("waiting for CHAP result"); 763 response = login_receive(conn); 764 if (conn->conn_conf.isc_mutual_user[0] != '\0') 765 login_verify_mutual(response); 766 pdu_delete(response); 767 768 log_debugx("CHAP authentication done"); 769} 770 771void 772login(struct connection *conn) 773{ 774 struct pdu *request, *response; 775 struct keys *request_keys, *response_keys; 776 struct iscsi_bhs_login_response *bhslr2; 777 const char *auth_method; 778 int i; 779 780 log_debugx("beginning Login phase; sending Login PDU"); 781 request = login_new_request(conn, BHSLR_STAGE_SECURITY_NEGOTIATION); 782 request_keys = keys_new(); 783 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 784 keys_add(request_keys, "AuthMethod", "CHAP"); 785 } else if (conn->conn_conf.isc_user[0] != '\0') { 786 /* 787 * Give target a chance to skip authentication if it 788 * doesn't feel like it. 789 * 790 * None is first, CHAP second; this is to work around 791 * what seems to be LIO (Linux target) bug: otherwise, 792 * if target is configured with no authentication, 793 * and we are configured to authenticate, the target 794 * will erroneously respond with AuthMethod=CHAP 795 * instead of AuthMethod=None, and will subsequently 796 * fail the connection. This usually happens with 797 * Discovery sessions, which default to no authentication. 798 */ 799 keys_add(request_keys, "AuthMethod", "None,CHAP"); 800 } else { 801 keys_add(request_keys, "AuthMethod", "None"); 802 } 803 keys_add(request_keys, "InitiatorName", 804 conn->conn_conf.isc_initiator); 805 if (conn->conn_conf.isc_initiator_alias[0] != '\0') { 806 keys_add(request_keys, "InitiatorAlias", 807 conn->conn_conf.isc_initiator_alias); 808 } 809 if (conn->conn_conf.isc_discovery == 0) { 810 keys_add(request_keys, "SessionType", "Normal"); 811 keys_add(request_keys, 812 "TargetName", conn->conn_conf.isc_target); 813 } else { 814 keys_add(request_keys, "SessionType", "Discovery"); 815 } 816 keys_save(request_keys, request); 817 keys_delete(request_keys); 818 pdu_send(request); 819 pdu_delete(request); 820 821 response = login_receive(conn); 822 823 response_keys = keys_new(); 824 keys_load(response_keys, response); 825 826 for (i = 0; i < KEYS_MAX; i++) { 827 if (response_keys->keys_names[i] == NULL) 828 break; 829 830 /* 831 * Not interested in AuthMethod at this point; we only need 832 * to parse things such as TargetAlias. 833 * 834 * XXX: This is somewhat ugly. We should have a way to apply 835 * all the keys to the session and use that by default 836 * instead of discarding them. 837 */ 838 if (strcmp(response_keys->keys_names[i], "AuthMethod") == 0) 839 continue; 840 841 login_negotiate_key(conn, 842 response_keys->keys_names[i], response_keys->keys_values[i]); 843 } 844 845 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs; 846 if ((bhslr2->bhslr_flags & BHSLR_FLAGS_TRANSIT) != 0 && 847 login_nsg(response) == BHSLR_STAGE_OPERATIONAL_NEGOTIATION) { 848 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 849 log_errx(1, "target requested transition " 850 "to operational parameter negotiation, " 851 "but we require mutual CHAP"); 852 } 853 854 log_debugx("target requested transition " 855 "to operational parameter negotiation"); 856 keys_delete(response_keys); 857 pdu_delete(response); 858 login_negotiate(conn); 859 return; 860 } 861 862 auth_method = keys_find(response_keys, "AuthMethod"); 863 if (auth_method == NULL) 864 log_errx(1, "received response without AuthMethod"); 865 if (strcmp(auth_method, "None") == 0) { 866 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 867 log_errx(1, "target does not require authantication, " 868 "but we require mutual CHAP"); 869 } 870 871 log_debugx("target does not require authentication"); 872 keys_delete(response_keys); 873 pdu_delete(response); 874 login_negotiate(conn); 875 return; 876 } 877 878 if (strcmp(auth_method, "CHAP") != 0) { 879 fail(conn, "Unsupported AuthMethod"); 880 log_errx(1, "received response " 881 "with unsupported AuthMethod \"%s\"", auth_method); 882 } 883 884 if (conn->conn_conf.isc_user[0] == '\0' || 885 conn->conn_conf.isc_secret[0] == '\0') { 886 fail(conn, "Authentication required"); 887 log_errx(1, "target requests CHAP authentication, but we don't " 888 "have user and secret"); 889 } 890 891 keys_delete(response_keys); 892 response_keys = NULL; 893 pdu_delete(response); 894 response = NULL; 895 896 login_chap(conn); 897 login_negotiate(conn); 898} 899