1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/types.h> 36 #include <sys/ioctl.h> 37 #include <assert.h> 38 #include <stdbool.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <netinet/in.h> 43 44 #include "iscsid.h" 45 #include "iscsi_proto.h" 46 47 static int 48 login_nsg(const struct pdu *response) 49 { 50 struct iscsi_bhs_login_response *bhslr; 51 52 bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs; 53 54 return (bhslr->bhslr_flags & 0x03); 55 } 56 57 static void 58 login_set_nsg(struct pdu *request, int nsg) 59 { 60 struct iscsi_bhs_login_request *bhslr; 61 62 assert(nsg == BHSLR_STAGE_SECURITY_NEGOTIATION || 63 nsg == BHSLR_STAGE_OPERATIONAL_NEGOTIATION || 64 nsg == BHSLR_STAGE_FULL_FEATURE_PHASE); 65 66 bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs; 67 68 bhslr->bhslr_flags &= 0xFC; 69 bhslr->bhslr_flags |= nsg; 70 } 71 72 static void 73 login_set_csg(struct pdu *request, int csg) 74 { 75 struct iscsi_bhs_login_request *bhslr; 76 77 assert(csg == BHSLR_STAGE_SECURITY_NEGOTIATION || 78 csg == BHSLR_STAGE_OPERATIONAL_NEGOTIATION || 79 csg == BHSLR_STAGE_FULL_FEATURE_PHASE); 80 81 bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs; 82 83 bhslr->bhslr_flags &= 0xF3; 84 bhslr->bhslr_flags |= csg << 2; 85 } 86 87 static const char * 88 login_target_error_str(int class, int detail) 89 { 90 static char msg[128]; 91 92 /* 93 * RFC 3270, 10.13.5. Status-Class and Status-Detail 94 */ 95 switch (class) { 96 case 0x01: 97 switch (detail) { 98 case 0x01: 99 return ("Target moved temporarily"); 100 case 0x02: 101 return ("Target moved permanently"); 102 default: 103 snprintf(msg, sizeof(msg), "unknown redirection; " 104 "Status-Class 0x%x, Status-Detail 0x%x", 105 class, detail); 106 return (msg); 107 } 108 case 0x02: 109 switch (detail) { 110 case 0x00: 111 return ("Initiator error"); 112 case 0x01: 113 return ("Authentication failure"); 114 case 0x02: 115 return ("Authorization failure"); 116 case 0x03: 117 return ("Not found"); 118 case 0x04: 119 return ("Target removed"); 120 case 0x05: 121 return ("Unsupported version"); 122 case 0x06: 123 return ("Too many connections"); 124 case 0x07: 125 return ("Missing parameter"); 126 case 0x08: 127 return ("Can't include in session"); 128 case 0x09: 129 return ("Session type not supported"); 130 case 0x0a: 131 return ("Session does not exist"); 132 case 0x0b: 133 return ("Invalid during login"); 134 default: 135 snprintf(msg, sizeof(msg), "unknown initiator error; " 136 "Status-Class 0x%x, Status-Detail 0x%x", 137 class, detail); 138 return (msg); 139 } 140 case 0x03: 141 switch (detail) { 142 case 0x00: 143 return ("Target error"); 144 case 0x01: 145 return ("Service unavailable"); 146 case 0x02: 147 return ("Out of resources"); 148 default: 149 snprintf(msg, sizeof(msg), "unknown target error; " 150 "Status-Class 0x%x, Status-Detail 0x%x", 151 class, detail); 152 return (msg); 153 } 154 default: 155 snprintf(msg, sizeof(msg), "unknown error; " 156 "Status-Class 0x%x, Status-Detail 0x%x", 157 class, detail); 158 return (msg); 159 } 160 } 161 162 static void 163 kernel_modify(const struct iscsid_connection *conn, const char *target_address) 164 { 165 struct iscsi_session_modify ism; 166 int error; 167 168 memset(&ism, 0, sizeof(ism)); 169 ism.ism_session_id = conn->conn_session_id; 170 memcpy(&ism.ism_conf, &conn->conn_conf, sizeof(ism.ism_conf)); 171 strlcpy(ism.ism_conf.isc_target_addr, target_address, 172 sizeof(ism.ism_conf.isc_target_addr)); 173 error = ioctl(conn->conn_iscsi_fd, ISCSISMODIFY, &ism); 174 if (error != 0) { 175 log_err(1, "failed to redirect to %s: ISCSISMODIFY", 176 target_address); 177 } 178 } 179 180 /* 181 * XXX: The way it works is suboptimal; what should happen is described 182 * in draft-gilligan-iscsi-fault-tolerance-00. That, however, would 183 * be much more complicated: we would need to keep "dependencies" 184 * for sessions, so that, in case described in draft and using draft 185 * terminology, we would have three sessions: one for discovery, 186 * one for initial target portal, and one for redirect portal. 187 * This would allow us to "backtrack" on connection failure, 188 * as described in draft. 189 */ 190 static void 191 login_handle_redirection(struct iscsid_connection *conn, struct pdu *response) 192 { 193 struct iscsi_bhs_login_response *bhslr; 194 struct keys *response_keys; 195 const char *target_address; 196 197 bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs; 198 assert (bhslr->bhslr_status_class == 1); 199 200 response_keys = keys_new(); 201 keys_load_pdu(response_keys, response); 202 203 target_address = keys_find(response_keys, "TargetAddress"); 204 if (target_address == NULL) 205 log_errx(1, "received redirection without TargetAddress"); 206 if (target_address[0] == '\0') 207 log_errx(1, "received redirection with empty TargetAddress"); 208 if (strlen(target_address) >= 209 sizeof(conn->conn_conf.isc_target_addr) - 1) 210 log_errx(1, "received TargetAddress is too long"); 211 212 log_debugx("received redirection to \"%s\"", target_address); 213 kernel_modify(conn, target_address); 214 keys_delete(response_keys); 215 } 216 217 static struct pdu * 218 login_receive(struct connection *conn) 219 { 220 struct pdu *response; 221 struct iscsi_bhs_login_response *bhslr; 222 const char *errorstr; 223 static bool initial = true; 224 225 response = pdu_new(conn); 226 pdu_receive(response); 227 if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_LOGIN_RESPONSE) { 228 log_errx(1, "protocol error: received invalid opcode 0x%x", 229 response->pdu_bhs->bhs_opcode); 230 } 231 bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs; 232 /* 233 * XXX: Implement the C flag some day. 234 */ 235 if ((bhslr->bhslr_flags & BHSLR_FLAGS_CONTINUE) != 0) 236 log_errx(1, "received Login PDU with unsupported \"C\" flag"); 237 if (bhslr->bhslr_version_max != 0x00) 238 log_errx(1, "received Login PDU with unsupported " 239 "Version-max 0x%x", bhslr->bhslr_version_max); 240 if (bhslr->bhslr_version_active != 0x00) 241 log_errx(1, "received Login PDU with unsupported " 242 "Version-active 0x%x", bhslr->bhslr_version_active); 243 if (bhslr->bhslr_status_class == 1) { 244 login_handle_redirection((struct iscsid_connection *)conn, 245 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 iscsid_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.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.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.conn_immediate_data = true; 393 else 394 conn->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.conn_max_send_data_segment_length = tmp; 407 } else if (strcmp(name, "MaxBurstLength") == 0) { 408 tmp = strtoul(value, NULL, 10); 409 if (tmp <= 0) 410 log_errx(1, "received invalid MaxBurstLength"); 411 if (tmp > isl->isl_max_burst_length) { 412 log_debugx("capping MaxBurstLength " 413 "from %d to %d", tmp, isl->isl_max_burst_length); 414 tmp = isl->isl_max_burst_length; 415 } 416 conn->conn.conn_max_burst_length = tmp; 417 } else if (strcmp(name, "FirstBurstLength") == 0) { 418 tmp = strtoul(value, NULL, 10); 419 if (tmp <= 0) 420 log_errx(1, "received invalid FirstBurstLength"); 421 if (tmp > isl->isl_first_burst_length) { 422 log_debugx("capping FirstBurstLength " 423 "from %d to %d", tmp, isl->isl_first_burst_length); 424 tmp = isl->isl_first_burst_length; 425 } 426 conn->conn.conn_first_burst_length = tmp; 427 } else if (strcmp(name, "DefaultTime2Wait") == 0) { 428 /* Ignore */ 429 } else if (strcmp(name, "DefaultTime2Retain") == 0) { 430 /* Ignore */ 431 } else if (strcmp(name, "MaxOutstandingR2T") == 0) { 432 /* Ignore */ 433 } else if (strcmp(name, "DataPDUInOrder") == 0) { 434 /* Ignore */ 435 } else if (strcmp(name, "DataSequenceInOrder") == 0) { 436 /* Ignore */ 437 } else if (strcmp(name, "ErrorRecoveryLevel") == 0) { 438 /* Ignore */ 439 } else if (strcmp(name, "OFMarker") == 0) { 440 /* Ignore */ 441 } else if (strcmp(name, "IFMarker") == 0) { 442 /* Ignore */ 443 } else if (strcmp(name, "RDMAExtensions") == 0) { 444 if (conn->conn_conf.isc_iser == 1 && 445 strcmp(value, "Yes") != 0) { 446 log_errx(1, "received unsupported RDMAExtensions"); 447 } 448 } else if (strcmp(name, "InitiatorRecvDataSegmentLength") == 0) { 449 tmp = strtoul(value, NULL, 10); 450 if (tmp <= 0) 451 log_errx(1, "received invalid " 452 "InitiatorRecvDataSegmentLength"); 453 if ((int)tmp > isl->isl_max_recv_data_segment_length) { 454 log_debugx("capping InitiatorRecvDataSegmentLength " 455 "from %d to %d", tmp, 456 isl->isl_max_recv_data_segment_length); 457 tmp = isl->isl_max_recv_data_segment_length; 458 } 459 conn->conn.conn_max_recv_data_segment_length = tmp; 460 } else if (strcmp(name, "TargetPortalGroupTag") == 0) { 461 /* Ignore */ 462 } else if (strcmp(name, "TargetRecvDataSegmentLength") == 0) { 463 tmp = strtoul(value, NULL, 10); 464 if (tmp <= 0) { 465 log_errx(1, 466 "received invalid TargetRecvDataSegmentLength"); 467 } 468 if (tmp > isl->isl_max_send_data_segment_length) { 469 log_debugx("capping TargetRecvDataSegmentLength " 470 "from %d to %d", tmp, 471 isl->isl_max_send_data_segment_length); 472 tmp = isl->isl_max_send_data_segment_length; 473 } 474 conn->conn.conn_max_send_data_segment_length = tmp; 475 } else { 476 log_debugx("unknown key \"%s\"; ignoring", name); 477 } 478 } 479 480 static void 481 login_negotiate(struct iscsid_connection *conn) 482 { 483 struct pdu *request, *response; 484 struct keys *request_keys, *response_keys; 485 struct iscsi_bhs_login_response *bhslr; 486 int i, nrequests = 0; 487 struct iscsi_session_limits *isl; 488 489 log_debugx("beginning operational parameter negotiation"); 490 request = login_new_request(&conn->conn, 491 BHSLR_STAGE_OPERATIONAL_NEGOTIATION); 492 request_keys = keys_new(); 493 494 isl = &conn->conn_limits; 495 log_debugx("Limits for offload \"%s\" are " 496 "MaxRecvDataSegment=%d, max_send_dsl=%d, " 497 "MaxBurstLength=%d, FirstBurstLength=%d", 498 conn->conn_conf.isc_offload, isl->isl_max_recv_data_segment_length, 499 isl->isl_max_send_data_segment_length, isl->isl_max_burst_length, 500 isl->isl_first_burst_length); 501 502 /* 503 * The following keys are irrelevant for discovery sessions. 504 */ 505 if (conn->conn_conf.isc_discovery == 0) { 506 keys_add(request_keys, "iSCSIProtocolLevel", "2"); 507 if (conn->conn_conf.isc_header_digest != 0) 508 keys_add(request_keys, "HeaderDigest", "CRC32C"); 509 else 510 keys_add(request_keys, "HeaderDigest", "None"); 511 if (conn->conn_conf.isc_data_digest != 0) 512 keys_add(request_keys, "DataDigest", "CRC32C"); 513 else 514 keys_add(request_keys, "DataDigest", "None"); 515 516 keys_add(request_keys, "ImmediateData", "Yes"); 517 keys_add_int(request_keys, "MaxBurstLength", 518 isl->isl_max_burst_length); 519 keys_add_int(request_keys, "FirstBurstLength", 520 isl->isl_first_burst_length); 521 keys_add(request_keys, "InitialR2T", "Yes"); 522 keys_add(request_keys, "MaxOutstandingR2T", "1"); 523 if (conn->conn_conf.isc_iser == 1) { 524 keys_add_int(request_keys, "InitiatorRecvDataSegmentLength", 525 isl->isl_max_recv_data_segment_length); 526 keys_add_int(request_keys, "TargetRecvDataSegmentLength", 527 isl->isl_max_send_data_segment_length); 528 keys_add(request_keys, "RDMAExtensions", "Yes"); 529 } else { 530 keys_add_int(request_keys, "MaxRecvDataSegmentLength", 531 isl->isl_max_recv_data_segment_length); 532 } 533 } else { 534 keys_add(request_keys, "HeaderDigest", "None"); 535 keys_add(request_keys, "DataDigest", "None"); 536 keys_add_int(request_keys, "MaxRecvDataSegmentLength", 537 isl->isl_max_recv_data_segment_length); 538 } 539 540 conn->conn.conn_max_recv_data_segment_length = 541 isl->isl_max_recv_data_segment_length; 542 543 keys_add(request_keys, "DefaultTime2Wait", "0"); 544 keys_add(request_keys, "DefaultTime2Retain", "0"); 545 keys_add(request_keys, "ErrorRecoveryLevel", "0"); 546 keys_save_pdu(request_keys, request); 547 keys_delete(request_keys); 548 request_keys = NULL; 549 pdu_send(request); 550 pdu_delete(request); 551 request = NULL; 552 553 response = login_receive(&conn->conn); 554 response_keys = keys_new(); 555 keys_load_pdu(response_keys, response); 556 for (i = 0; i < KEYS_MAX; i++) { 557 if (response_keys->keys_names[i] == NULL) 558 break; 559 560 login_negotiate_key(conn, 561 response_keys->keys_names[i], response_keys->keys_values[i]); 562 } 563 564 keys_delete(response_keys); 565 response_keys = NULL; 566 567 for (;;) { 568 bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs; 569 if ((bhslr->bhslr_flags & BHSLR_FLAGS_TRANSIT) != 0) 570 break; 571 572 nrequests++; 573 if (nrequests > 5) { 574 log_warnx("received login response " 575 "without the \"T\" flag too many times; giving up"); 576 break; 577 } 578 579 log_debugx("received login response " 580 "without the \"T\" flag; sending another request"); 581 582 pdu_delete(response); 583 584 request = login_new_request(&conn->conn, 585 BHSLR_STAGE_OPERATIONAL_NEGOTIATION); 586 pdu_send(request); 587 pdu_delete(request); 588 589 response = login_receive(&conn->conn); 590 } 591 592 if (login_nsg(response) != BHSLR_STAGE_FULL_FEATURE_PHASE) 593 log_warnx("received final login response with wrong NSG 0x%x", 594 login_nsg(response)); 595 pdu_delete(response); 596 597 log_debugx("operational parameter negotiation done; " 598 "transitioning to Full Feature phase"); 599 } 600 601 static void 602 login_send_chap_a(struct connection *conn) 603 { 604 struct pdu *request; 605 struct keys *request_keys; 606 607 request = login_new_request(conn, BHSLR_STAGE_SECURITY_NEGOTIATION); 608 request_keys = keys_new(); 609 keys_add(request_keys, "CHAP_A", "5"); 610 keys_save_pdu(request_keys, request); 611 keys_delete(request_keys); 612 pdu_send(request); 613 pdu_delete(request); 614 } 615 616 static void 617 login_send_chap_r(struct pdu *response) 618 { 619 struct iscsid_connection *conn; 620 struct pdu *request; 621 struct keys *request_keys, *response_keys; 622 struct rchap *rchap; 623 const char *chap_a, *chap_c, *chap_i; 624 char *chap_r; 625 int error; 626 char *mutual_chap_c, *mutual_chap_i; 627 628 /* 629 * As in the rest of the initiator, 'request' means 630 * 'initiator -> target', and 'response' means 'target -> initiator', 631 * 632 * So, here the 'response' from the target is the packet that contains 633 * CHAP challenge; our CHAP response goes into 'request'. 634 */ 635 636 conn = (struct iscsid_connection *)response->pdu_connection; 637 638 response_keys = keys_new(); 639 keys_load_pdu(response_keys, response); 640 641 /* 642 * First, compute the response. 643 */ 644 chap_a = keys_find(response_keys, "CHAP_A"); 645 if (chap_a == NULL) 646 log_errx(1, "received CHAP packet without CHAP_A"); 647 chap_c = keys_find(response_keys, "CHAP_C"); 648 if (chap_c == NULL) 649 log_errx(1, "received CHAP packet without CHAP_C"); 650 chap_i = keys_find(response_keys, "CHAP_I"); 651 if (chap_i == NULL) 652 log_errx(1, "received CHAP packet without CHAP_I"); 653 654 if (strcmp(chap_a, "5") != 0) { 655 log_errx(1, "received CHAP packet " 656 "with unsupported CHAP_A \"%s\"", chap_a); 657 } 658 659 rchap = rchap_new(conn->conn_conf.isc_secret); 660 error = rchap_receive(rchap, chap_i, chap_c); 661 if (error != 0) { 662 log_errx(1, "received CHAP packet " 663 "with malformed CHAP_I or CHAP_C"); 664 } 665 chap_r = rchap_get_response(rchap); 666 rchap_delete(rchap); 667 668 keys_delete(response_keys); 669 670 request = login_new_request(&conn->conn, 671 BHSLR_STAGE_SECURITY_NEGOTIATION); 672 request_keys = keys_new(); 673 keys_add(request_keys, "CHAP_N", conn->conn_conf.isc_user); 674 keys_add(request_keys, "CHAP_R", chap_r); 675 free(chap_r); 676 677 /* 678 * If we want mutual authentication, we're expected to send 679 * our CHAP_I/CHAP_C now. 680 */ 681 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 682 log_debugx("requesting mutual authentication; " 683 "binary challenge size is %zd bytes", 684 sizeof(conn->conn_mutual_chap->chap_challenge)); 685 686 assert(conn->conn_mutual_chap == NULL); 687 conn->conn_mutual_chap = chap_new(); 688 mutual_chap_i = chap_get_id(conn->conn_mutual_chap); 689 mutual_chap_c = chap_get_challenge(conn->conn_mutual_chap); 690 keys_add(request_keys, "CHAP_I", mutual_chap_i); 691 keys_add(request_keys, "CHAP_C", mutual_chap_c); 692 free(mutual_chap_i); 693 free(mutual_chap_c); 694 } 695 696 keys_save_pdu(request_keys, request); 697 keys_delete(request_keys); 698 pdu_send(request); 699 pdu_delete(request); 700 } 701 702 static void 703 login_verify_mutual(const struct pdu *response) 704 { 705 struct iscsid_connection *conn; 706 struct keys *response_keys; 707 const char *chap_n, *chap_r; 708 int error; 709 710 conn = (struct iscsid_connection *)response->pdu_connection; 711 712 response_keys = keys_new(); 713 keys_load_pdu(response_keys, response); 714 715 chap_n = keys_find(response_keys, "CHAP_N"); 716 if (chap_n == NULL) 717 log_errx(1, "received CHAP Response PDU without CHAP_N"); 718 chap_r = keys_find(response_keys, "CHAP_R"); 719 if (chap_r == NULL) 720 log_errx(1, "received CHAP Response PDU without CHAP_R"); 721 722 error = chap_receive(conn->conn_mutual_chap, chap_r); 723 if (error != 0) 724 log_errx(1, "received CHAP Response PDU with invalid CHAP_R"); 725 726 if (strcmp(chap_n, conn->conn_conf.isc_mutual_user) != 0) { 727 fail(&conn->conn, "Mutual CHAP failed"); 728 log_errx(1, "mutual CHAP authentication failed: wrong user"); 729 } 730 731 error = chap_authenticate(conn->conn_mutual_chap, 732 conn->conn_conf.isc_mutual_secret); 733 if (error != 0) { 734 fail(&conn->conn, "Mutual CHAP failed"); 735 log_errx(1, "mutual CHAP authentication failed: wrong secret"); 736 } 737 738 keys_delete(response_keys); 739 chap_delete(conn->conn_mutual_chap); 740 conn->conn_mutual_chap = NULL; 741 742 log_debugx("mutual CHAP authentication succeeded"); 743 } 744 745 static void 746 login_chap(struct iscsid_connection *conn) 747 { 748 struct pdu *response; 749 750 log_debugx("beginning CHAP authentication; sending CHAP_A"); 751 login_send_chap_a(&conn->conn); 752 753 log_debugx("waiting for CHAP_A/CHAP_C/CHAP_I"); 754 response = login_receive(&conn->conn); 755 756 log_debugx("sending CHAP_N/CHAP_R"); 757 login_send_chap_r(response); 758 pdu_delete(response); 759 760 /* 761 * XXX: Make sure this is not susceptible to MITM. 762 */ 763 764 log_debugx("waiting for CHAP result"); 765 response = login_receive(&conn->conn); 766 if (conn->conn_conf.isc_mutual_user[0] != '\0') 767 login_verify_mutual(response); 768 pdu_delete(response); 769 770 log_debugx("CHAP authentication done"); 771 } 772 773 void 774 login(struct iscsid_connection *conn) 775 { 776 struct pdu *request, *response; 777 struct keys *request_keys, *response_keys; 778 struct iscsi_bhs_login_response *bhslr2; 779 const char *auth_method; 780 int i; 781 782 log_debugx("beginning Login phase; sending Login PDU"); 783 request = login_new_request(&conn->conn, 784 BHSLR_STAGE_SECURITY_NEGOTIATION); 785 request_keys = keys_new(); 786 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 787 keys_add(request_keys, "AuthMethod", "CHAP"); 788 } else if (conn->conn_conf.isc_user[0] != '\0') { 789 /* 790 * Give target a chance to skip authentication if it 791 * doesn't feel like it. 792 * 793 * None is first, CHAP second; this is to work around 794 * what seems to be LIO (Linux target) bug: otherwise, 795 * if target is configured with no authentication, 796 * and we are configured to authenticate, the target 797 * will erroneously respond with AuthMethod=CHAP 798 * instead of AuthMethod=None, and will subsequently 799 * fail the connection. This usually happens with 800 * Discovery sessions, which default to no authentication. 801 */ 802 keys_add(request_keys, "AuthMethod", "None,CHAP"); 803 } else { 804 keys_add(request_keys, "AuthMethod", "None"); 805 } 806 keys_add(request_keys, "InitiatorName", 807 conn->conn_conf.isc_initiator); 808 if (conn->conn_conf.isc_initiator_alias[0] != '\0') { 809 keys_add(request_keys, "InitiatorAlias", 810 conn->conn_conf.isc_initiator_alias); 811 } 812 if (conn->conn_conf.isc_discovery == 0) { 813 keys_add(request_keys, "SessionType", "Normal"); 814 keys_add(request_keys, 815 "TargetName", conn->conn_conf.isc_target); 816 } else { 817 keys_add(request_keys, "SessionType", "Discovery"); 818 } 819 keys_save_pdu(request_keys, request); 820 keys_delete(request_keys); 821 pdu_send(request); 822 pdu_delete(request); 823 824 response = login_receive(&conn->conn); 825 826 response_keys = keys_new(); 827 keys_load_pdu(response_keys, response); 828 829 for (i = 0; i < KEYS_MAX; i++) { 830 if (response_keys->keys_names[i] == NULL) 831 break; 832 833 /* 834 * Not interested in AuthMethod at this point; we only need 835 * to parse things such as TargetAlias. 836 * 837 * XXX: This is somewhat ugly. We should have a way to apply 838 * all the keys to the session and use that by default 839 * instead of discarding them. 840 */ 841 if (strcmp(response_keys->keys_names[i], "AuthMethod") == 0) 842 continue; 843 844 login_negotiate_key(conn, 845 response_keys->keys_names[i], response_keys->keys_values[i]); 846 } 847 848 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs; 849 if ((bhslr2->bhslr_flags & BHSLR_FLAGS_TRANSIT) != 0 && 850 login_nsg(response) == BHSLR_STAGE_OPERATIONAL_NEGOTIATION) { 851 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 852 log_errx(1, "target requested transition " 853 "to operational parameter negotiation, " 854 "but we require mutual CHAP"); 855 } 856 857 log_debugx("target requested transition " 858 "to operational parameter negotiation"); 859 keys_delete(response_keys); 860 pdu_delete(response); 861 login_negotiate(conn); 862 return; 863 } 864 865 auth_method = keys_find(response_keys, "AuthMethod"); 866 if (auth_method == NULL) 867 log_errx(1, "received response without AuthMethod"); 868 if (strcmp(auth_method, "None") == 0) { 869 if (conn->conn_conf.isc_mutual_user[0] != '\0') { 870 log_errx(1, "target does not require authantication, " 871 "but we require mutual CHAP"); 872 } 873 874 log_debugx("target does not require authentication"); 875 keys_delete(response_keys); 876 pdu_delete(response); 877 login_negotiate(conn); 878 return; 879 } 880 881 if (strcmp(auth_method, "CHAP") != 0) { 882 fail(&conn->conn, "Unsupported AuthMethod"); 883 log_errx(1, "received response " 884 "with unsupported AuthMethod \"%s\"", auth_method); 885 } 886 887 if (conn->conn_conf.isc_user[0] == '\0' || 888 conn->conn_conf.isc_secret[0] == '\0') { 889 fail(&conn->conn, "Authentication required"); 890 log_errx(1, "target requests CHAP authentication, but we don't " 891 "have user and secret"); 892 } 893 894 keys_delete(response_keys); 895 response_keys = NULL; 896 pdu_delete(response); 897 response = NULL; 898 899 login_chap(conn); 900 login_negotiate(conn); 901 } 902