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 48 static int 49 login_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 58 static void 59 login_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 73 static void 74 login_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 88 static const char * 89 login_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 163 static void 164 kernel_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 */ 191 static void 192 login_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 218 static struct pdu * 219 login_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 273 static struct pdu * 274 login_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 309 static int 310 login_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 331 static void 332 login_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, "HeaderDigest") == 0) { 345 which = login_list_prefers(value, "CRC32C", "None"); 346 switch (which) { 347 case 1: 348 log_debugx("target prefers CRC32C " 349 "for header digest; we'll use it"); 350 conn->conn_header_digest = CONN_DIGEST_CRC32C; 351 break; 352 case 2: 353 log_debugx("target prefers not to do " 354 "header digest; we'll comply"); 355 break; 356 default: 357 log_warnx("target sent unrecognized " 358 "HeaderDigest value \"%s\"; will use None", value); 359 break; 360 } 361 } else if (strcmp(name, "DataDigest") == 0) { 362 which = login_list_prefers(value, "CRC32C", "None"); 363 switch (which) { 364 case 1: 365 log_debugx("target prefers CRC32C " 366 "for data digest; we'll use it"); 367 conn->conn_data_digest = CONN_DIGEST_CRC32C; 368 break; 369 case 2: 370 log_debugx("target prefers not to do " 371 "data digest; we'll comply"); 372 break; 373 default: 374 log_warnx("target sent unrecognized " 375 "DataDigest value \"%s\"; will use None", value); 376 break; 377 } 378 } else if (strcmp(name, "MaxConnections") == 0) { 379 /* Ignore. */ 380 } else if (strcmp(name, "InitialR2T") == 0) { 381 if (strcmp(value, "Yes") == 0) 382 conn->conn_initial_r2t = true; 383 else 384 conn->conn_initial_r2t = false; 385 } else if (strcmp(name, "ImmediateData") == 0) { 386 if (strcmp(value, "Yes") == 0) 387 conn->conn_immediate_data = true; 388 else 389 conn->conn_immediate_data = false; 390 } else if (strcmp(name, "MaxRecvDataSegmentLength") == 0) { 391 tmp = strtoul(value, NULL, 10); 392 if (tmp <= 0) 393 log_errx(1, "received invalid " 394 "MaxRecvDataSegmentLength"); 395 if (tmp > isl->isl_max_send_data_segment_length) { 396 log_debugx("capping max_send_data_segment_length " 397 "from %d to %d", tmp, 398 isl->isl_max_send_data_segment_length); 399 tmp = isl->isl_max_send_data_segment_length; 400 } 401 conn->conn_max_send_data_segment_length = tmp; 402 /* We received target's limit, that means it accepted our's. */ 403 conn->conn_max_recv_data_segment_length = 404 isl->isl_max_recv_data_segment_length; 405 } else if (strcmp(name, "MaxBurstLength") == 0) { 406 tmp = strtoul(value, NULL, 10); 407 if (tmp <= 0) 408 log_errx(1, "received invalid MaxBurstLength"); 409 if (tmp > isl->isl_max_burst_length) { 410 log_debugx("capping MaxBurstLength " 411 "from %d to %d", tmp, isl->isl_max_burst_length); 412 tmp = isl->isl_max_burst_length; 413 } 414 conn->conn_max_burst_length = tmp; 415 } else if (strcmp(name, "FirstBurstLength") == 0) { 416 tmp = strtoul(value, NULL, 10); 417 if (tmp <= 0) 418 log_errx(1, "received invalid FirstBurstLength"); 419 if (tmp > isl->isl_first_burst_length) { 420 log_debugx("capping FirstBurstLength " 421 "from %d to %d", tmp, isl->isl_first_burst_length); 422 tmp = isl->isl_first_burst_length; 423 } 424 conn->conn_first_burst_length = tmp; 425 } else if (strcmp(name, "DefaultTime2Wait") == 0) { 426 /* Ignore */ 427 } else if (strcmp(name, "DefaultTime2Retain") == 0) { 428 /* Ignore */ 429 } else if (strcmp(name, "MaxOutstandingR2T") == 0) { 430 /* Ignore */ 431 } else if (strcmp(name, "DataPDUInOrder") == 0) { 432 /* Ignore */ 433 } else if (strcmp(name, "DataSequenceInOrder") == 0) { 434 /* Ignore */ 435 } else if (strcmp(name, "ErrorRecoveryLevel") == 0) { 436 /* Ignore */ 437 } else if (strcmp(name, "OFMarker") == 0) { 438 /* Ignore */ 439 } else if (strcmp(name, "IFMarker") == 0) { 440 /* Ignore */ 441 } else if (strcmp(name, "RDMAExtensions") == 0) { 442 if (conn->conn_conf.isc_iser == 1 && 443 strcmp(value, "Yes") != 0) { 444 log_errx(1, "received unsupported RDMAExtensions"); 445 } 446 } else if (strcmp(name, "InitiatorRecvDataSegmentLength") == 0) { 447 tmp = strtoul(value, NULL, 10); 448 if (tmp <= 0) 449 log_errx(1, "received invalid " 450 "InitiatorRecvDataSegmentLength"); 451 if ((int)tmp > isl->isl_max_recv_data_segment_length) { 452 log_debugx("capping InitiatorRecvDataSegmentLength " 453 "from %d to %d", tmp, 454 isl->isl_max_recv_data_segment_length); 455 tmp = isl->isl_max_recv_data_segment_length; 456 } 457 conn->conn_max_recv_data_segment_length = tmp; 458 } else if (strcmp(name, "TargetPortalGroupTag") == 0) { 459 /* Ignore */ 460 } else if (strcmp(name, "TargetRecvDataSegmentLength") == 0) { 461 tmp = strtoul(value, NULL, 10); 462 if (tmp <= 0) { 463 log_errx(1, 464 "received invalid TargetRecvDataSegmentLength"); 465 } 466 if (tmp > isl->isl_max_send_data_segment_length) { 467 log_debugx("capping TargetRecvDataSegmentLength " 468 "from %d to %d", tmp, 469 isl->isl_max_send_data_segment_length); 470 tmp = isl->isl_max_send_data_segment_length; 471 } 472 conn->conn_max_send_data_segment_length = tmp; 473 } else { 474 log_debugx("unknown key \"%s\"; ignoring", name); 475 } 476 } 477 478 static void 479 login_negotiate(struct connection *conn) 480 { 481 struct pdu *request, *response; 482 struct keys *request_keys, *response_keys; 483 struct iscsi_bhs_login_response *bhslr; 484 int i, nrequests = 0; 485 struct iscsi_session_limits *isl; 486 487 log_debugx("beginning operational parameter negotiation"); 488 request = login_new_request(conn, BHSLR_STAGE_OPERATIONAL_NEGOTIATION); 489 request_keys = keys_new(); 490 491 isl = &conn->conn_limits; 492 log_debugx("Limits for offload \"%s\" are " 493 "MaxRecvDataSegment=%d, max_send_dsl=%d, " 494 "MaxBurstLength=%d, FirstBurstLength=%d", 495 conn->conn_conf.isc_offload, isl->isl_max_recv_data_segment_length, 496 isl->isl_max_send_data_segment_length, isl->isl_max_burst_length, 497 isl->isl_first_burst_length); 498 499 /* 500 * The following keys are irrelevant for discovery sessions. 501 */ 502 if (conn->conn_conf.isc_discovery == 0) { 503 if (conn->conn_conf.isc_header_digest != 0) 504 keys_add(request_keys, "HeaderDigest", "CRC32C"); 505 else 506 keys_add(request_keys, "HeaderDigest", "None"); 507 if (conn->conn_conf.isc_data_digest != 0) 508 keys_add(request_keys, "DataDigest", "CRC32C"); 509 else 510 keys_add(request_keys, "DataDigest", "None"); 511 512 keys_add(request_keys, "ImmediateData", "Yes"); 513 keys_add_int(request_keys, "MaxBurstLength", 514 isl->isl_max_burst_length); 515 keys_add_int(request_keys, "FirstBurstLength", 516 isl->isl_first_burst_length); 517 keys_add(request_keys, "InitialR2T", "Yes"); 518 keys_add(request_keys, "MaxOutstandingR2T", "1"); 519 if (conn->conn_conf.isc_iser == 1) { 520 keys_add_int(request_keys, "InitiatorRecvDataSegmentLength", 521 isl->isl_max_recv_data_segment_length); 522 keys_add_int(request_keys, "TargetRecvDataSegmentLength", 523 isl->isl_max_send_data_segment_length); 524 keys_add(request_keys, "RDMAExtensions", "Yes"); 525 } else { 526 keys_add_int(request_keys, "MaxRecvDataSegmentLength", 527 isl->isl_max_recv_data_segment_length); 528 } 529 } else { 530 keys_add(request_keys, "HeaderDigest", "None"); 531 keys_add(request_keys, "DataDigest", "None"); 532 keys_add_int(request_keys, "MaxRecvDataSegmentLength", 533 isl->isl_max_recv_data_segment_length); 534 } 535 536 keys_add(request_keys, "DefaultTime2Wait", "0"); 537 keys_add(request_keys, "DefaultTime2Retain", "0"); 538 keys_add(request_keys, "ErrorRecoveryLevel", "0"); 539 keys_save(request_keys, request); 540 keys_delete(request_keys); 541 request_keys = NULL; 542 pdu_send(request); 543 pdu_delete(request); 544 request = NULL; 545 546 response = login_receive(conn); 547 response_keys = keys_new(); 548 keys_load(response_keys, response); 549 for (i = 0; i < KEYS_MAX; i++) { 550 if (response_keys->keys_names[i] == NULL) 551 break; 552 553 login_negotiate_key(conn, 554 response_keys->keys_names[i], response_keys->keys_values[i]); 555 } 556 557 keys_delete(response_keys); 558 response_keys = NULL; 559 560 for (;;) { 561 bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs; 562 if ((bhslr->bhslr_flags & BHSLR_FLAGS_TRANSIT) != 0) 563 break; 564 565 nrequests++; 566 if (nrequests > 5) { 567 log_warnx("received login response " 568 "without the \"T\" flag too many times; giving up"); 569 break; 570 } 571 572 log_debugx("received login response " 573 "without the \"T\" flag; sending another request"); 574 575 pdu_delete(response); 576 577 request = login_new_request(conn, 578 BHSLR_STAGE_OPERATIONAL_NEGOTIATION); 579 pdu_send(request); 580 pdu_delete(request); 581 582 response = login_receive(conn); 583 } 584 585 if (login_nsg(response) != BHSLR_STAGE_FULL_FEATURE_PHASE) 586 log_warnx("received final login response with wrong NSG 0x%x", 587 login_nsg(response)); 588 pdu_delete(response); 589 590 log_debugx("operational parameter negotiation done; " 591 "transitioning to Full Feature phase"); 592 } 593 594 static void 595 login_send_chap_a(struct connection *conn) 596 { 597 struct pdu *request; 598 struct keys *request_keys; 599 600 request = login_new_request(conn, BHSLR_STAGE_SECURITY_NEGOTIATION); 601 request_keys = keys_new(); 602 keys_add(request_keys, "CHAP_A", "5"); 603 keys_save(request_keys, request); 604 keys_delete(request_keys); 605 pdu_send(request); 606 pdu_delete(request); 607 } 608 609 static void 610 login_send_chap_r(struct pdu *response) 611 { 612 struct connection *conn; 613 struct pdu *request; 614 struct keys *request_keys, *response_keys; 615 struct rchap *rchap; 616 const char *chap_a, *chap_c, *chap_i; 617 char *chap_r; 618 int error; 619 char *mutual_chap_c, *mutual_chap_i; 620 621 /* 622 * As in the rest of the initiator, 'request' means 623 * 'initiator -> target', and 'response' means 'target -> initiator', 624 * 625 * So, here the 'response' from the target is the packet that contains 626 * CHAP challenge; our CHAP response goes into 'request'. 627 */ 628 629 conn = response->pdu_connection; 630 631 response_keys = keys_new(); 632 keys_load(response_keys, response); 633 634 /* 635 * First, compute the response. 636 */ 637 chap_a = keys_find(response_keys, "CHAP_A"); 638 if (chap_a == NULL) 639 log_errx(1, "received CHAP packet without CHAP_A"); 640 chap_c = keys_find(response_keys, "CHAP_C"); 641 if (chap_c == NULL) 642 log_errx(1, "received CHAP packet without CHAP_C"); 643 chap_i = keys_find(response_keys, "CHAP_I"); 644 if (chap_i == NULL) 645 log_errx(1, "received CHAP packet without CHAP_I"); 646 647 if (strcmp(chap_a, "5") != 0) { 648 log_errx(1, "received CHAP packet " 649 "with unsupported CHAP_A \"%s\"", chap_a); 650 } 651 652 rchap = rchap_new(conn->conn_conf.isc_secret); 653 error = rchap_receive(rchap, chap_i, chap_c); 654 if (error != 0) { 655 log_errx(1, "received CHAP packet " 656 "with malformed CHAP_I or CHAP_C"); 657 } 658 chap_r = rchap_get_response(rchap); 659 rchap_delete(rchap); 660 661 keys_delete(response_keys); 662 663 request = login_new_request(conn, BHSLR_STAGE_SECURITY_NEGOTIATION); 664 request_keys = keys_new(); 665 keys_add(request_keys, "CHAP_N", conn->conn_conf.isc_user); 666 keys_add(request_keys, "CHAP_R", chap_r); 667 free(chap_r); 668 669 /* 670 * If we want mutual authentication, we're expected to send 671 * our CHAP_I/CHAP_C now. 672 */ 673 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 674 log_debugx("requesting mutual authentication; " 675 "binary challenge size is %zd bytes", 676 sizeof(conn->conn_mutual_chap->chap_challenge)); 677 678 assert(conn->conn_mutual_chap == NULL); 679 conn->conn_mutual_chap = chap_new(); 680 mutual_chap_i = chap_get_id(conn->conn_mutual_chap); 681 mutual_chap_c = chap_get_challenge(conn->conn_mutual_chap); 682 keys_add(request_keys, "CHAP_I", mutual_chap_i); 683 keys_add(request_keys, "CHAP_C", mutual_chap_c); 684 free(mutual_chap_i); 685 free(mutual_chap_c); 686 } 687 688 keys_save(request_keys, request); 689 keys_delete(request_keys); 690 pdu_send(request); 691 pdu_delete(request); 692 } 693 694 static void 695 login_verify_mutual(const struct pdu *response) 696 { 697 struct connection *conn; 698 struct keys *response_keys; 699 const char *chap_n, *chap_r; 700 int error; 701 702 conn = response->pdu_connection; 703 704 response_keys = keys_new(); 705 keys_load(response_keys, response); 706 707 chap_n = keys_find(response_keys, "CHAP_N"); 708 if (chap_n == NULL) 709 log_errx(1, "received CHAP Response PDU without CHAP_N"); 710 chap_r = keys_find(response_keys, "CHAP_R"); 711 if (chap_r == NULL) 712 log_errx(1, "received CHAP Response PDU without CHAP_R"); 713 714 error = chap_receive(conn->conn_mutual_chap, chap_r); 715 if (error != 0) 716 log_errx(1, "received CHAP Response PDU with invalid CHAP_R"); 717 718 if (strcmp(chap_n, conn->conn_conf.isc_mutual_user) != 0) { 719 fail(conn, "Mutual CHAP failed"); 720 log_errx(1, "mutual CHAP authentication failed: wrong user"); 721 } 722 723 error = chap_authenticate(conn->conn_mutual_chap, 724 conn->conn_conf.isc_mutual_secret); 725 if (error != 0) { 726 fail(conn, "Mutual CHAP failed"); 727 log_errx(1, "mutual CHAP authentication failed: wrong secret"); 728 } 729 730 keys_delete(response_keys); 731 chap_delete(conn->conn_mutual_chap); 732 conn->conn_mutual_chap = NULL; 733 734 log_debugx("mutual CHAP authentication succeeded"); 735 } 736 737 static void 738 login_chap(struct connection *conn) 739 { 740 struct pdu *response; 741 742 log_debugx("beginning CHAP authentication; sending CHAP_A"); 743 login_send_chap_a(conn); 744 745 log_debugx("waiting for CHAP_A/CHAP_C/CHAP_I"); 746 response = login_receive(conn); 747 748 log_debugx("sending CHAP_N/CHAP_R"); 749 login_send_chap_r(response); 750 pdu_delete(response); 751 752 /* 753 * XXX: Make sure this is not susceptible to MITM. 754 */ 755 756 log_debugx("waiting for CHAP result"); 757 response = login_receive(conn); 758 if (conn->conn_conf.isc_mutual_user[0] != '\0') 759 login_verify_mutual(response); 760 pdu_delete(response); 761 762 log_debugx("CHAP authentication done"); 763 } 764 765 void 766 login(struct connection *conn) 767 { 768 struct pdu *request, *response; 769 struct keys *request_keys, *response_keys; 770 struct iscsi_bhs_login_response *bhslr2; 771 const char *auth_method; 772 int i; 773 774 log_debugx("beginning Login phase; sending Login PDU"); 775 request = login_new_request(conn, BHSLR_STAGE_SECURITY_NEGOTIATION); 776 request_keys = keys_new(); 777 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 778 keys_add(request_keys, "AuthMethod", "CHAP"); 779 } else if (conn->conn_conf.isc_user[0] != '\0') { 780 /* 781 * Give target a chance to skip authentication if it 782 * doesn't feel like it. 783 * 784 * None is first, CHAP second; this is to work around 785 * what seems to be LIO (Linux target) bug: otherwise, 786 * if target is configured with no authentication, 787 * and we are configured to authenticate, the target 788 * will erroneously respond with AuthMethod=CHAP 789 * instead of AuthMethod=None, and will subsequently 790 * fail the connection. This usually happens with 791 * Discovery sessions, which default to no authentication. 792 */ 793 keys_add(request_keys, "AuthMethod", "None,CHAP"); 794 } else { 795 keys_add(request_keys, "AuthMethod", "None"); 796 } 797 keys_add(request_keys, "InitiatorName", 798 conn->conn_conf.isc_initiator); 799 if (conn->conn_conf.isc_initiator_alias[0] != '\0') { 800 keys_add(request_keys, "InitiatorAlias", 801 conn->conn_conf.isc_initiator_alias); 802 } 803 if (conn->conn_conf.isc_discovery == 0) { 804 keys_add(request_keys, "SessionType", "Normal"); 805 keys_add(request_keys, 806 "TargetName", conn->conn_conf.isc_target); 807 } else { 808 keys_add(request_keys, "SessionType", "Discovery"); 809 } 810 keys_save(request_keys, request); 811 keys_delete(request_keys); 812 pdu_send(request); 813 pdu_delete(request); 814 815 response = login_receive(conn); 816 817 response_keys = keys_new(); 818 keys_load(response_keys, response); 819 820 for (i = 0; i < KEYS_MAX; i++) { 821 if (response_keys->keys_names[i] == NULL) 822 break; 823 824 /* 825 * Not interested in AuthMethod at this point; we only need 826 * to parse things such as TargetAlias. 827 * 828 * XXX: This is somewhat ugly. We should have a way to apply 829 * all the keys to the session and use that by default 830 * instead of discarding them. 831 */ 832 if (strcmp(response_keys->keys_names[i], "AuthMethod") == 0) 833 continue; 834 835 login_negotiate_key(conn, 836 response_keys->keys_names[i], response_keys->keys_values[i]); 837 } 838 839 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs; 840 if ((bhslr2->bhslr_flags & BHSLR_FLAGS_TRANSIT) != 0 && 841 login_nsg(response) == BHSLR_STAGE_OPERATIONAL_NEGOTIATION) { 842 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 843 log_errx(1, "target requested transition " 844 "to operational parameter negotiation, " 845 "but we require mutual CHAP"); 846 } 847 848 log_debugx("target requested transition " 849 "to operational parameter negotiation"); 850 keys_delete(response_keys); 851 pdu_delete(response); 852 login_negotiate(conn); 853 return; 854 } 855 856 auth_method = keys_find(response_keys, "AuthMethod"); 857 if (auth_method == NULL) 858 log_errx(1, "received response without AuthMethod"); 859 if (strcmp(auth_method, "None") == 0) { 860 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 861 log_errx(1, "target does not require authantication, " 862 "but we require mutual CHAP"); 863 } 864 865 log_debugx("target does not require authentication"); 866 keys_delete(response_keys); 867 pdu_delete(response); 868 login_negotiate(conn); 869 return; 870 } 871 872 if (strcmp(auth_method, "CHAP") != 0) { 873 fail(conn, "Unsupported AuthMethod"); 874 log_errx(1, "received response " 875 "with unsupported AuthMethod \"%s\"", auth_method); 876 } 877 878 if (conn->conn_conf.isc_user[0] == '\0' || 879 conn->conn_conf.isc_secret[0] == '\0') { 880 fail(conn, "Authentication required"); 881 log_errx(1, "target requests CHAP authentication, but we don't " 882 "have user and secret"); 883 } 884 885 keys_delete(response_keys); 886 response_keys = NULL; 887 pdu_delete(response); 888 response = NULL; 889 890 login_chap(conn); 891 login_negotiate(conn); 892 } 893