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