2 * Copyright (c) 2012 The FreeBSD Foundation
5 * This software was developed by Edward Tomasz Napierala under sponsorship
6 * from the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #include <netinet/in.h>
40 #include <openssl/err.h>
41 #include <openssl/md5.h>
42 #include <openssl/rand.h>
45 #include "iscsi_proto.h"
47 static void login_send_error(struct pdu *request,
48 char class, char detail);
51 login_set_nsg(struct pdu *response, int nsg)
53 struct iscsi_bhs_login_response *bhslr;
55 assert(nsg == BHSLR_STAGE_SECURITY_NEGOTIATION ||
56 nsg == BHSLR_STAGE_OPERATIONAL_NEGOTIATION ||
57 nsg == BHSLR_STAGE_FULL_FEATURE_PHASE);
59 bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs;
61 bhslr->bhslr_flags &= 0xFC;
62 bhslr->bhslr_flags |= nsg;
66 login_csg(const struct pdu *request)
68 struct iscsi_bhs_login_request *bhslr;
70 bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
72 return ((bhslr->bhslr_flags & 0x0C) >> 2);
76 login_set_csg(struct pdu *response, int csg)
78 struct iscsi_bhs_login_response *bhslr;
80 assert(csg == BHSLR_STAGE_SECURITY_NEGOTIATION ||
81 csg == BHSLR_STAGE_OPERATIONAL_NEGOTIATION ||
82 csg == BHSLR_STAGE_FULL_FEATURE_PHASE);
84 bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs;
86 bhslr->bhslr_flags &= 0xF3;
87 bhslr->bhslr_flags |= csg << 2;
91 login_receive(struct connection *conn, bool initial)
94 struct iscsi_bhs_login_request *bhslr;
96 request = pdu_new(conn);
98 if ((request->pdu_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) !=
99 ISCSI_BHS_OPCODE_LOGIN_REQUEST) {
101 * The first PDU in session is special - if we receive any PDU
102 * different than login request, we have to drop the connection
103 * without sending response ("A target receiving any PDU
104 * except a Login request before the Login Phase is started MUST
105 * immediately terminate the connection on which the PDU
108 if (initial == false)
109 login_send_error(request, 0x02, 0x0b);
110 log_errx(1, "protocol error: received invalid opcode 0x%x",
111 request->pdu_bhs->bhs_opcode);
113 bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
115 * XXX: Implement the C flag some day.
117 if ((bhslr->bhslr_flags & BHSLR_FLAGS_CONTINUE) != 0) {
118 login_send_error(request, 0x03, 0x00);
119 log_errx(1, "received Login PDU with unsupported \"C\" flag");
121 if (bhslr->bhslr_version_max != 0x00) {
122 login_send_error(request, 0x02, 0x05);
123 log_errx(1, "received Login PDU with unsupported "
124 "Version-max 0x%x", bhslr->bhslr_version_max);
126 if (bhslr->bhslr_version_min != 0x00) {
127 login_send_error(request, 0x02, 0x05);
128 log_errx(1, "received Login PDU with unsupported "
129 "Version-min 0x%x", bhslr->bhslr_version_min);
131 if (request->pdu_data_len == 0) {
132 login_send_error(request, 0x02, 0x00);
133 log_errx(1, "received Login PDU with empty data segment");
135 if (ntohl(bhslr->bhslr_cmdsn) < conn->conn_cmdsn) {
136 login_send_error(request, 0x02, 0x05);
137 log_errx(1, "received Login PDU with decreasing CmdSN: "
138 "was %d, is %d", conn->conn_cmdsn,
139 ntohl(bhslr->bhslr_cmdsn));
141 if (initial == false &&
142 ntohl(bhslr->bhslr_expstatsn) != conn->conn_statsn) {
143 login_send_error(request, 0x02, 0x05);
144 log_errx(1, "received Login PDU with wrong ExpStatSN: "
145 "is %d, should be %d", ntohl(bhslr->bhslr_expstatsn),
148 conn->conn_cmdsn = ntohl(bhslr->bhslr_cmdsn);
154 login_new_response(struct pdu *request)
156 struct pdu *response;
157 struct connection *conn;
158 struct iscsi_bhs_login_request *bhslr;
159 struct iscsi_bhs_login_response *bhslr2;
161 bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
162 conn = request->pdu_connection;
164 response = pdu_new_response(request);
165 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
166 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGIN_RESPONSE;
167 login_set_csg(response, BHSLR_STAGE_SECURITY_NEGOTIATION);
168 memcpy(bhslr2->bhslr_isid,
169 bhslr->bhslr_isid, sizeof(bhslr2->bhslr_isid));
170 bhslr2->bhslr_initiator_task_tag = bhslr->bhslr_initiator_task_tag;
171 bhslr2->bhslr_statsn = htonl(conn->conn_statsn++);
172 bhslr2->bhslr_expcmdsn = htonl(conn->conn_cmdsn);
173 bhslr2->bhslr_maxcmdsn = htonl(conn->conn_cmdsn);
179 login_send_error(struct pdu *request, char class, char detail)
181 struct pdu *response;
182 struct iscsi_bhs_login_response *bhslr2;
184 log_debugx("sending Login Response PDU with failure class 0x%x/0x%x; "
185 "see next line for reason", class, detail);
186 response = login_new_response(request);
187 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
188 bhslr2->bhslr_status_class = class;
189 bhslr2->bhslr_status_detail = detail;
192 pdu_delete(response);
196 login_list_contains(const char *list, const char *what)
198 char *tofree, *str, *token;
200 tofree = str = checked_strdup(list);
202 while ((token = strsep(&str, ",")) != NULL) {
203 if (strcmp(token, what) == 0) {
213 login_list_prefers(const char *list,
214 const char *choice1, const char *choice2)
216 char *tofree, *str, *token;
218 tofree = str = checked_strdup(list);
220 while ((token = strsep(&str, ",")) != NULL) {
221 if (strcmp(token, choice1) == 0) {
225 if (strcmp(token, choice2) == 0) {
235 login_hex2int(const char hex)
282 * XXX: Review this _carefully_.
285 login_hex2bin(const char *hex, char **binp, size_t *bin_lenp)
287 int i, hex_len, nibble;
288 bool lo = true; /* As opposed to 'hi'. */
290 size_t bin_off, bin_len;
292 if (strncasecmp(hex, "0x", strlen("0x")) != 0) {
293 log_warnx("malformed variable, should start with \"0x\"");
298 hex_len = strlen(hex);
300 log_warnx("malformed variable; doesn't contain anything "
305 bin_len = hex_len / 2 + hex_len % 2;
306 bin = calloc(bin_len, 1);
308 log_err(1, "calloc");
310 bin_off = bin_len - 1;
311 for (i = hex_len - 1; i >= 0; i--) {
312 nibble = login_hex2int(hex[i]);
314 log_warnx("malformed variable, invalid char \"%c\"",
319 assert(bin_off < bin_len);
321 bin[bin_off] = nibble;
324 bin[bin_off] |= nibble << 4;
336 login_bin2hex(const char *bin, size_t bin_len)
338 unsigned char *hex, *tmp, ch;
342 hex_len = bin_len * 2 + 3; /* +2 for "0x", +1 for '\0'. */
343 hex = malloc(hex_len);
345 log_err(1, "malloc");
348 tmp += sprintf(tmp, "0x");
349 for (i = 0; i < bin_len; i++) {
351 tmp += sprintf(tmp, "%02x", ch);
358 login_compute_md5(const char id, const char *secret,
359 const void *challenge, size_t challenge_len, void *response,
365 assert(response_len == MD5_DIGEST_LENGTH);
368 MD5_Update(&ctx, &id, sizeof(id));
369 MD5_Update(&ctx, secret, strlen(secret));
370 MD5_Update(&ctx, challenge, challenge_len);
371 rv = MD5_Final(response, &ctx);
373 log_errx(1, "MD5_Final");
376 #define LOGIN_CHALLENGE_LEN 1024
379 login_receive_chap_a(struct connection *conn)
382 struct keys *request_keys;
385 request = login_receive(conn, false);
386 request_keys = keys_new();
387 keys_load(request_keys, request);
389 chap_a = keys_find(request_keys, "CHAP_A");
390 if (chap_a == NULL) {
391 login_send_error(request, 0x02, 0x07);
392 log_errx(1, "received CHAP Login PDU without CHAP_A");
394 if (login_list_contains(chap_a, "5") == 0) {
395 login_send_error(request, 0x02, 0x01);
396 log_errx(1, "received CHAP Login PDU with unsupported CHAP_A "
399 keys_delete(request_keys);
405 login_send_chap_c(struct pdu *request, const unsigned char id,
406 const void *challenge, const size_t challenge_len)
408 struct pdu *response;
409 struct keys *response_keys;
410 char *chap_c, chap_i[4];
412 chap_c = login_bin2hex(challenge, challenge_len);
413 snprintf(chap_i, sizeof(chap_i), "%d", id);
415 response = login_new_response(request);
416 response_keys = keys_new();
417 keys_add(response_keys, "CHAP_A", "5");
418 keys_add(response_keys, "CHAP_I", chap_i);
419 keys_add(response_keys, "CHAP_C", chap_c);
421 keys_save(response_keys, response);
423 pdu_delete(response);
424 keys_delete(response_keys);
428 login_receive_chap_r(struct connection *conn,
429 struct auth_group *ag, const unsigned char id, const void *challenge,
430 const size_t challenge_len, const struct auth **cap)
433 struct keys *request_keys;
434 const char *chap_n, *chap_r;
435 char *response_bin, expected_response_bin[MD5_DIGEST_LENGTH];
436 size_t response_bin_len;
437 const struct auth *auth;
440 request = login_receive(conn, false);
441 request_keys = keys_new();
442 keys_load(request_keys, request);
444 chap_n = keys_find(request_keys, "CHAP_N");
445 if (chap_n == NULL) {
446 login_send_error(request, 0x02, 0x07);
447 log_errx(1, "received CHAP Login PDU without CHAP_N");
449 chap_r = keys_find(request_keys, "CHAP_R");
450 if (chap_r == NULL) {
451 login_send_error(request, 0x02, 0x07);
452 log_errx(1, "received CHAP Login PDU without CHAP_R");
454 error = login_hex2bin(chap_r, &response_bin, &response_bin_len);
456 login_send_error(request, 0x02, 0x07);
457 log_errx(1, "received CHAP Login PDU with malformed CHAP_R");
461 * Verify the response.
463 assert(ag->ag_type == AG_TYPE_CHAP ||
464 ag->ag_type == AG_TYPE_CHAP_MUTUAL);
465 auth = auth_find(ag, chap_n);
467 login_send_error(request, 0x02, 0x01);
468 log_errx(1, "received CHAP Login with invalid user \"%s\"",
472 assert(auth->a_secret != NULL);
473 assert(strlen(auth->a_secret) > 0);
474 login_compute_md5(id, auth->a_secret, challenge,
475 challenge_len, expected_response_bin,
476 sizeof(expected_response_bin));
478 if (memcmp(response_bin, expected_response_bin,
479 sizeof(expected_response_bin)) != 0) {
480 login_send_error(request, 0x02, 0x01);
481 log_errx(1, "CHAP authentication failed for user \"%s\"",
485 keys_delete(request_keys);
493 login_send_chap_success(struct pdu *request,
494 const struct auth *auth)
496 struct pdu *response;
497 struct keys *request_keys, *response_keys;
498 struct iscsi_bhs_login_response *bhslr2;
499 const char *chap_i, *chap_c;
500 char *chap_r, *challenge, response_bin[MD5_DIGEST_LENGTH];
501 size_t challenge_len;
505 response = login_new_response(request);
506 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
507 bhslr2->bhslr_flags |= BHSLR_FLAGS_TRANSIT;
508 login_set_nsg(response, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
511 * Actually, one more thing: mutual authentication.
513 request_keys = keys_new();
514 keys_load(request_keys, request);
515 chap_i = keys_find(request_keys, "CHAP_I");
516 chap_c = keys_find(request_keys, "CHAP_C");
517 if (chap_i != NULL || chap_c != NULL) {
518 if (chap_i == NULL) {
519 login_send_error(request, 0x02, 0x07);
520 log_errx(1, "initiator requested target "
521 "authentication, but didn't send CHAP_I");
523 if (chap_c == NULL) {
524 login_send_error(request, 0x02, 0x07);
525 log_errx(1, "initiator requested target "
526 "authentication, but didn't send CHAP_C");
528 if (auth->a_auth_group->ag_type != AG_TYPE_CHAP_MUTUAL) {
529 login_send_error(request, 0x02, 0x01);
530 log_errx(1, "initiator requests target authentication "
531 "for user \"%s\", but mutual user/secret "
532 "is not set", auth->a_user);
535 id = strtoul(chap_i, NULL, 10);
536 error = login_hex2bin(chap_c, &challenge, &challenge_len);
538 login_send_error(request, 0x02, 0x07);
539 log_errx(1, "received CHAP Login PDU with malformed "
543 log_debugx("performing mutual authentication as user \"%s\"",
544 auth->a_mutual_user);
545 login_compute_md5(id, auth->a_mutual_secret, challenge,
546 challenge_len, response_bin, sizeof(response_bin));
548 chap_r = login_bin2hex(response_bin,
549 sizeof(response_bin));
550 response_keys = keys_new();
551 keys_add(response_keys, "CHAP_N", auth->a_mutual_user);
552 keys_add(response_keys, "CHAP_R", chap_r);
554 keys_save(response_keys, response);
555 keys_delete(response_keys);
557 log_debugx("initiator did not request target authentication");
560 keys_delete(request_keys);
562 pdu_delete(response);
566 login_chap(struct connection *conn, struct auth_group *ag)
568 const struct auth *auth;
570 char challenge_bin[LOGIN_CHALLENGE_LEN];
575 * Receive CHAP_A PDU.
577 log_debugx("beginning CHAP authentication; waiting for CHAP_A");
578 request = login_receive_chap_a(conn);
581 * Generate the challenge.
583 rv = RAND_bytes(challenge_bin, sizeof(challenge_bin));
585 login_send_error(request, 0x03, 0x02);
586 log_errx(1, "RAND_bytes failed: %s",
587 ERR_error_string(ERR_get_error(), NULL));
589 rv = RAND_bytes(&id, sizeof(id));
591 login_send_error(request, 0x03, 0x02);
592 log_errx(1, "RAND_bytes failed: %s",
593 ERR_error_string(ERR_get_error(), NULL));
597 * Send the challenge.
599 log_debugx("sending CHAP_C, binary challenge size is %zd bytes",
600 sizeof(challenge_bin));
601 login_send_chap_c(request, id, challenge_bin,
602 sizeof(challenge_bin));
606 * Receive CHAP_N/CHAP_R PDU and authenticate.
608 log_debugx("waiting for CHAP_N/CHAP_R");
609 request = login_receive_chap_r(conn, ag, id, challenge_bin,
610 sizeof(challenge_bin), &auth);
613 * Yay, authentication succeeded!
615 log_debugx("authentication succeeded for user \"%s\"; "
616 "transitioning to Negotiation Phase", auth->a_user);
617 login_send_chap_success(request, auth);
622 login_negotiate_key(struct pdu *request, const char *name,
623 const char *value, bool skipped_security, struct keys *response_keys)
626 struct connection *conn;
628 conn = request->pdu_connection;
630 if (strcmp(name, "InitiatorName") == 0) {
631 if (!skipped_security)
632 log_errx(1, "initiator resent InitiatorName");
633 } else if (strcmp(name, "SessionType") == 0) {
634 if (!skipped_security)
635 log_errx(1, "initiator resent SessionType");
636 } else if (strcmp(name, "TargetName") == 0) {
637 if (!skipped_security)
638 log_errx(1, "initiator resent TargetName");
639 } else if (strcmp(name, "InitiatorAlias") == 0) {
640 if (conn->conn_initiator_alias != NULL)
641 free(conn->conn_initiator_alias);
642 conn->conn_initiator_alias = checked_strdup(value);
643 } else if (strcmp(value, "Irrelevant") == 0) {
645 } else if (strcmp(name, "HeaderDigest") == 0) {
647 * We don't handle digests for discovery sessions.
649 if (conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
650 log_debugx("discovery session; digests disabled");
651 keys_add(response_keys, name, "None");
655 which = login_list_prefers(value, "CRC32C", "None");
658 log_debugx("initiator prefers CRC32C "
659 "for header digest; we'll use it");
660 conn->conn_header_digest = CONN_DIGEST_CRC32C;
661 keys_add(response_keys, name, "CRC32C");
664 log_debugx("initiator prefers not to do "
665 "header digest; we'll comply");
666 keys_add(response_keys, name, "None");
669 log_warnx("initiator sent unrecognized "
670 "HeaderDigest value \"%s\"; will use None", value);
671 keys_add(response_keys, name, "None");
674 } else if (strcmp(name, "DataDigest") == 0) {
675 if (conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
676 log_debugx("discovery session; digests disabled");
677 keys_add(response_keys, name, "None");
681 which = login_list_prefers(value, "CRC32C", "None");
684 log_debugx("initiator prefers CRC32C "
685 "for data digest; we'll use it");
686 conn->conn_data_digest = CONN_DIGEST_CRC32C;
687 keys_add(response_keys, name, "CRC32C");
690 log_debugx("initiator prefers not to do "
691 "data digest; we'll comply");
692 keys_add(response_keys, name, "None");
695 log_warnx("initiator sent unrecognized "
696 "DataDigest value \"%s\"; will use None", value);
697 keys_add(response_keys, name, "None");
700 } else if (strcmp(name, "MaxConnections") == 0) {
701 keys_add(response_keys, name, "1");
702 } else if (strcmp(name, "InitialR2T") == 0) {
703 keys_add(response_keys, name, "Yes");
704 } else if (strcmp(name, "ImmediateData") == 0) {
705 if (conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
706 log_debugx("discovery session; ImmediateData irrelevant");
707 keys_add(response_keys, name, "Irrelevant");
709 if (strcmp(value, "Yes") == 0) {
710 conn->conn_immediate_data = true;
711 keys_add(response_keys, name, "Yes");
713 conn->conn_immediate_data = false;
714 keys_add(response_keys, name, "No");
717 } else if (strcmp(name, "MaxRecvDataSegmentLength") == 0) {
718 tmp = strtoul(value, NULL, 10);
720 login_send_error(request, 0x02, 0x00);
721 log_errx(1, "received invalid "
722 "MaxRecvDataSegmentLength");
724 if (tmp > MAX_DATA_SEGMENT_LENGTH) {
725 log_debugx("capping MaxDataSegmentLength from %d to %d",
726 tmp, MAX_DATA_SEGMENT_LENGTH);
727 tmp = MAX_DATA_SEGMENT_LENGTH;
729 conn->conn_max_data_segment_length = tmp;
730 keys_add_int(response_keys, name, tmp);
731 } else if (strcmp(name, "MaxBurstLength") == 0) {
732 tmp = strtoul(value, NULL, 10);
734 login_send_error(request, 0x02, 0x00);
735 log_errx(1, "received invalid MaxBurstLength");
737 if (tmp > MAX_BURST_LENGTH) {
738 log_debugx("capping MaxBurstLength from %d to %d",
739 tmp, MAX_BURST_LENGTH);
740 tmp = MAX_BURST_LENGTH;
742 conn->conn_max_burst_length = tmp;
743 keys_add(response_keys, name, value);
744 } else if (strcmp(name, "FirstBurstLength") == 0) {
745 tmp = strtoul(value, NULL, 10);
747 login_send_error(request, 0x02, 0x00);
748 log_errx(1, "received invalid "
751 if (tmp > MAX_DATA_SEGMENT_LENGTH) {
752 log_debugx("capping FirstBurstLength from %d to %d",
753 tmp, MAX_DATA_SEGMENT_LENGTH);
754 tmp = MAX_DATA_SEGMENT_LENGTH;
757 * We don't pass the value to the kernel; it only enforces
758 * hardcoded limit anyway.
760 keys_add_int(response_keys, name, tmp);
761 } else if (strcmp(name, "DefaultTime2Wait") == 0) {
762 keys_add(response_keys, name, value);
763 } else if (strcmp(name, "DefaultTime2Retain") == 0) {
764 keys_add(response_keys, name, "0");
765 } else if (strcmp(name, "MaxOutstandingR2T") == 0) {
766 keys_add(response_keys, name, "1");
767 } else if (strcmp(name, "DataPDUInOrder") == 0) {
768 keys_add(response_keys, name, "Yes");
769 } else if (strcmp(name, "DataSequenceInOrder") == 0) {
770 keys_add(response_keys, name, "Yes");
771 } else if (strcmp(name, "ErrorRecoveryLevel") == 0) {
772 keys_add(response_keys, name, "0");
773 } else if (strcmp(name, "OFMarker") == 0) {
774 keys_add(response_keys, name, "No");
775 } else if (strcmp(name, "IFMarker") == 0) {
776 keys_add(response_keys, name, "No");
778 log_debugx("unknown key \"%s\"; responding "
779 "with NotUnderstood", name);
780 keys_add(response_keys, name, "NotUnderstood");
785 login_negotiate(struct connection *conn, struct pdu *request)
787 struct pdu *response;
788 struct iscsi_bhs_login_response *bhslr2;
789 struct keys *request_keys, *response_keys;
791 bool skipped_security;
793 if (request == NULL) {
794 log_debugx("beginning parameter negotiation; "
795 "waiting for Login PDU");
796 request = login_receive(conn, false);
797 skipped_security = false;
799 skipped_security = true;
801 request_keys = keys_new();
802 keys_load(request_keys, request);
804 response = login_new_response(request);
805 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
806 bhslr2->bhslr_flags |= BHSLR_FLAGS_TRANSIT;
807 bhslr2->bhslr_tsih = htons(0xbadd);
808 login_set_csg(response, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
809 login_set_nsg(response, BHSLR_STAGE_FULL_FEATURE_PHASE);
810 response_keys = keys_new();
811 for (i = 0; i < KEYS_MAX; i++) {
812 if (request_keys->keys_names[i] == NULL)
815 login_negotiate_key(request, request_keys->keys_names[i],
816 request_keys->keys_values[i], skipped_security,
820 log_debugx("parameter negotiation done; "
821 "transitioning to Full Feature Phase");
823 keys_save(response_keys, response);
825 pdu_delete(response);
826 keys_delete(response_keys);
828 keys_delete(request_keys);
832 login(struct connection *conn)
834 struct pdu *request, *response;
835 struct iscsi_bhs_login_request *bhslr;
836 struct iscsi_bhs_login_response *bhslr2;
837 struct keys *request_keys, *response_keys;
838 struct auth_group *ag;
839 const char *initiator_name, *initiator_alias, *session_type,
840 *target_name, *auth_method;
841 char *portal_group_tag;
845 * Handle the initial Login Request - figure out required authentication
846 * method and either transition to the next phase, if no authentication
847 * is required, or call appropriate authentication code.
849 log_debugx("beginning Login Phase; waiting for Login PDU");
850 request = login_receive(conn, true);
851 bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
852 if (bhslr->bhslr_tsih != 0) {
853 login_send_error(request, 0x02, 0x0a);
854 log_errx(1, "received Login PDU with non-zero TSIH");
858 * XXX: Implement the C flag some day.
860 request_keys = keys_new();
861 keys_load(request_keys, request);
863 assert(conn->conn_initiator_name == NULL);
864 initiator_name = keys_find(request_keys, "InitiatorName");
865 if (initiator_name == NULL) {
866 login_send_error(request, 0x02, 0x07);
867 log_errx(1, "received Login PDU without InitiatorName");
869 if (valid_iscsi_name(initiator_name) == false) {
870 login_send_error(request, 0x02, 0x00);
871 log_errx(1, "received Login PDU with invalid InitiatorName");
873 conn->conn_initiator_name = checked_strdup(initiator_name);
874 log_set_peer_name(conn->conn_initiator_name);
876 * XXX: This doesn't work (does nothing) because of Capsicum.
878 setproctitle("%s (%s)", conn->conn_initiator_addr, conn->conn_initiator_name);
880 initiator_alias = keys_find(request_keys, "InitiatorAlias");
881 if (initiator_alias != NULL)
882 conn->conn_initiator_alias = checked_strdup(initiator_alias);
884 assert(conn->conn_session_type == CONN_SESSION_TYPE_NONE);
885 session_type = keys_find(request_keys, "SessionType");
886 if (session_type != NULL) {
887 if (strcmp(session_type, "Normal") == 0) {
888 conn->conn_session_type = CONN_SESSION_TYPE_NORMAL;
889 } else if (strcmp(session_type, "Discovery") == 0) {
890 conn->conn_session_type = CONN_SESSION_TYPE_DISCOVERY;
892 login_send_error(request, 0x02, 0x00);
893 log_errx(1, "received Login PDU with invalid "
894 "SessionType \"%s\"", session_type);
897 conn->conn_session_type = CONN_SESSION_TYPE_NORMAL;
899 assert(conn->conn_target == NULL);
900 if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
901 target_name = keys_find(request_keys, "TargetName");
902 if (target_name == NULL) {
903 login_send_error(request, 0x02, 0x07);
904 log_errx(1, "received Login PDU without TargetName");
908 target_find(conn->conn_portal->p_portal_group->pg_conf,
910 if (conn->conn_target == NULL) {
911 login_send_error(request, 0x02, 0x03);
912 log_errx(1, "requested target \"%s\" not found",
918 * At this point we know what kind of authentication we need.
920 if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
921 ag = conn->conn_target->t_auth_group;
922 if (ag->ag_name != NULL) {
923 log_debugx("initiator requests to connect "
924 "to target \"%s\"; auth-group \"%s\"",
925 conn->conn_target->t_iqn,
926 conn->conn_target->t_auth_group->ag_name);
928 log_debugx("initiator requests to connect "
929 "to target \"%s\"", conn->conn_target->t_iqn);
932 assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY);
933 ag = conn->conn_portal->p_portal_group->pg_discovery_auth_group;
934 if (ag->ag_name != NULL) {
935 log_debugx("initiator requests "
936 "discovery session; auth-group \"%s\"", ag->ag_name);
938 log_debugx("initiator requests discovery session");
943 * Let's see if the initiator intends to do any kind of authentication
946 if (login_csg(request) == BHSLR_STAGE_OPERATIONAL_NEGOTIATION) {
947 if (ag->ag_type != AG_TYPE_NO_AUTHENTICATION) {
948 login_send_error(request, 0x02, 0x01);
949 log_errx(1, "initiator skipped the authentication, "
950 "but authentication is required");
953 keys_delete(request_keys);
955 log_debugx("initiator skipped the authentication, "
956 "and we don't need it; proceeding with negotiation");
957 login_negotiate(conn, request);
961 if (ag->ag_type == AG_TYPE_NO_AUTHENTICATION) {
963 * Initiator might want to to authenticate,
964 * but we don't need it.
966 log_debugx("authentication not required; "
967 "transitioning to parameter negotiation");
969 if ((bhslr->bhslr_flags & BHSLR_FLAGS_TRANSIT) == 0)
970 log_warnx("initiator did not set the \"T\" flag; "
971 "transitioning anyway");
973 response = login_new_response(request);
974 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
975 bhslr2->bhslr_flags |= BHSLR_FLAGS_TRANSIT;
976 login_set_nsg(response,
977 BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
978 response_keys = keys_new();
980 * Required by Linux initiator.
982 auth_method = keys_find(request_keys, "AuthMethod");
983 if (auth_method != NULL &&
984 login_list_contains(auth_method, "None"))
985 keys_add(response_keys, "AuthMethod", "None");
987 if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
988 if (conn->conn_target->t_alias != NULL)
989 keys_add(response_keys,
990 "TargetAlias", conn->conn_target->t_alias);
991 rv = asprintf(&portal_group_tag, "%d",
992 conn->conn_portal->p_portal_group->pg_tag);
994 log_err(1, "asprintf");
995 keys_add(response_keys,
996 "TargetPortalGroupTag", portal_group_tag);
997 free(portal_group_tag);
999 keys_save(response_keys, response);
1001 pdu_delete(response);
1002 keys_delete(response_keys);
1003 pdu_delete(request);
1004 keys_delete(request_keys);
1006 login_negotiate(conn, NULL);
1010 log_debugx("CHAP authentication required");
1012 auth_method = keys_find(request_keys, "AuthMethod");
1013 if (auth_method == NULL) {
1014 login_send_error(request, 0x02, 0x07);
1015 log_errx(1, "received Login PDU without AuthMethod");
1018 * XXX: This should be Reject, not just a login failure (5.3.2).
1020 if (login_list_contains(auth_method, "CHAP") == 0) {
1021 login_send_error(request, 0x02, 0x01);
1022 log_errx(1, "initiator requests unsupported AuthMethod \"%s\" "
1023 "instead of \"CHAP\"", auth_method);
1026 response = login_new_response(request);
1028 response_keys = keys_new();
1029 keys_add(response_keys, "AuthMethod", "CHAP");
1030 if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
1031 rv = asprintf(&portal_group_tag, "%d",
1032 conn->conn_portal->p_portal_group->pg_tag);
1034 log_err(1, "asprintf");
1035 keys_add(response_keys,
1036 "TargetPortalGroupTag", portal_group_tag);
1037 free(portal_group_tag);
1038 if (conn->conn_target->t_alias != NULL)
1039 keys_add(response_keys,
1040 "TargetAlias", conn->conn_target->t_alias);
1042 keys_save(response_keys, response);
1045 pdu_delete(response);
1046 keys_delete(response_keys);
1047 pdu_delete(request);
1048 keys_delete(request_keys);
1050 login_chap(conn, ag);
1052 login_negotiate(conn, NULL);