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 (ntohl(bhslr->bhslr_cmdsn) < conn->conn_cmdsn) {
132 login_send_error(request, 0x02, 0x05);
133 log_errx(1, "received Login PDU with decreasing CmdSN: "
134 "was %d, is %d", conn->conn_cmdsn,
135 ntohl(bhslr->bhslr_cmdsn));
137 if (initial == false &&
138 ntohl(bhslr->bhslr_expstatsn) != conn->conn_statsn) {
139 login_send_error(request, 0x02, 0x05);
140 log_errx(1, "received Login PDU with wrong ExpStatSN: "
141 "is %d, should be %d", ntohl(bhslr->bhslr_expstatsn),
144 conn->conn_cmdsn = ntohl(bhslr->bhslr_cmdsn);
150 login_new_response(struct pdu *request)
152 struct pdu *response;
153 struct connection *conn;
154 struct iscsi_bhs_login_request *bhslr;
155 struct iscsi_bhs_login_response *bhslr2;
157 bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
158 conn = request->pdu_connection;
160 response = pdu_new_response(request);
161 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
162 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGIN_RESPONSE;
163 login_set_csg(response, BHSLR_STAGE_SECURITY_NEGOTIATION);
164 memcpy(bhslr2->bhslr_isid,
165 bhslr->bhslr_isid, sizeof(bhslr2->bhslr_isid));
166 bhslr2->bhslr_initiator_task_tag = bhslr->bhslr_initiator_task_tag;
167 bhslr2->bhslr_statsn = htonl(conn->conn_statsn++);
168 bhslr2->bhslr_expcmdsn = htonl(conn->conn_cmdsn);
169 bhslr2->bhslr_maxcmdsn = htonl(conn->conn_cmdsn);
175 login_send_error(struct pdu *request, char class, char detail)
177 struct pdu *response;
178 struct iscsi_bhs_login_response *bhslr2;
180 log_debugx("sending Login Response PDU with failure class 0x%x/0x%x; "
181 "see next line for reason", class, detail);
182 response = login_new_response(request);
183 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
184 bhslr2->bhslr_status_class = class;
185 bhslr2->bhslr_status_detail = detail;
188 pdu_delete(response);
192 login_list_contains(const char *list, const char *what)
194 char *tofree, *str, *token;
196 tofree = str = checked_strdup(list);
198 while ((token = strsep(&str, ",")) != NULL) {
199 if (strcmp(token, what) == 0) {
209 login_list_prefers(const char *list,
210 const char *choice1, const char *choice2)
212 char *tofree, *str, *token;
214 tofree = str = checked_strdup(list);
216 while ((token = strsep(&str, ",")) != NULL) {
217 if (strcmp(token, choice1) == 0) {
221 if (strcmp(token, choice2) == 0) {
231 login_hex2int(const char hex)
278 * XXX: Review this _carefully_.
281 login_hex2bin(const char *hex, char **binp, size_t *bin_lenp)
283 int i, hex_len, nibble;
284 bool lo = true; /* As opposed to 'hi'. */
286 size_t bin_off, bin_len;
288 if (strncasecmp(hex, "0x", strlen("0x")) != 0) {
289 log_warnx("malformed variable, should start with \"0x\"");
294 hex_len = strlen(hex);
296 log_warnx("malformed variable; doesn't contain anything "
301 bin_len = hex_len / 2 + hex_len % 2;
302 bin = calloc(bin_len, 1);
304 log_err(1, "calloc");
306 bin_off = bin_len - 1;
307 for (i = hex_len - 1; i >= 0; i--) {
308 nibble = login_hex2int(hex[i]);
310 log_warnx("malformed variable, invalid char \"%c\"",
315 assert(bin_off < bin_len);
317 bin[bin_off] = nibble;
320 bin[bin_off] |= nibble << 4;
332 login_bin2hex(const char *bin, size_t bin_len)
334 unsigned char *hex, *tmp, ch;
338 hex_len = bin_len * 2 + 3; /* +2 for "0x", +1 for '\0'. */
339 hex = malloc(hex_len);
341 log_err(1, "malloc");
344 tmp += sprintf(tmp, "0x");
345 for (i = 0; i < bin_len; i++) {
347 tmp += sprintf(tmp, "%02x", ch);
354 login_compute_md5(const char id, const char *secret,
355 const void *challenge, size_t challenge_len, void *response,
361 assert(response_len == MD5_DIGEST_LENGTH);
364 MD5_Update(&ctx, &id, sizeof(id));
365 MD5_Update(&ctx, secret, strlen(secret));
366 MD5_Update(&ctx, challenge, challenge_len);
367 rv = MD5_Final(response, &ctx);
369 log_errx(1, "MD5_Final");
372 #define LOGIN_CHALLENGE_LEN 1024
375 login_receive_chap_a(struct connection *conn)
378 struct keys *request_keys;
381 request = login_receive(conn, false);
382 request_keys = keys_new();
383 keys_load(request_keys, request);
385 chap_a = keys_find(request_keys, "CHAP_A");
386 if (chap_a == NULL) {
387 login_send_error(request, 0x02, 0x07);
388 log_errx(1, "received CHAP Login PDU without CHAP_A");
390 if (login_list_contains(chap_a, "5") == 0) {
391 login_send_error(request, 0x02, 0x01);
392 log_errx(1, "received CHAP Login PDU with unsupported CHAP_A "
395 keys_delete(request_keys);
401 login_send_chap_c(struct pdu *request, const unsigned char id,
402 const void *challenge, const size_t challenge_len)
404 struct pdu *response;
405 struct keys *response_keys;
406 char *chap_c, chap_i[4];
408 chap_c = login_bin2hex(challenge, challenge_len);
409 snprintf(chap_i, sizeof(chap_i), "%d", id);
411 response = login_new_response(request);
412 response_keys = keys_new();
413 keys_add(response_keys, "CHAP_A", "5");
414 keys_add(response_keys, "CHAP_I", chap_i);
415 keys_add(response_keys, "CHAP_C", chap_c);
417 keys_save(response_keys, response);
419 pdu_delete(response);
420 keys_delete(response_keys);
424 login_receive_chap_r(struct connection *conn,
425 struct auth_group *ag, const unsigned char id, const void *challenge,
426 const size_t challenge_len, const struct auth **cap)
429 struct keys *request_keys;
430 const char *chap_n, *chap_r;
431 char *response_bin, expected_response_bin[MD5_DIGEST_LENGTH];
432 size_t response_bin_len;
433 const struct auth *auth;
436 request = login_receive(conn, false);
437 request_keys = keys_new();
438 keys_load(request_keys, request);
440 chap_n = keys_find(request_keys, "CHAP_N");
441 if (chap_n == NULL) {
442 login_send_error(request, 0x02, 0x07);
443 log_errx(1, "received CHAP Login PDU without CHAP_N");
445 chap_r = keys_find(request_keys, "CHAP_R");
446 if (chap_r == NULL) {
447 login_send_error(request, 0x02, 0x07);
448 log_errx(1, "received CHAP Login PDU without CHAP_R");
450 error = login_hex2bin(chap_r, &response_bin, &response_bin_len);
452 login_send_error(request, 0x02, 0x07);
453 log_errx(1, "received CHAP Login PDU with malformed CHAP_R");
457 * Verify the response.
459 assert(ag->ag_type == AG_TYPE_CHAP ||
460 ag->ag_type == AG_TYPE_CHAP_MUTUAL);
461 auth = auth_find(ag, chap_n);
463 login_send_error(request, 0x02, 0x01);
464 log_errx(1, "received CHAP Login with invalid user \"%s\"",
468 assert(auth->a_secret != NULL);
469 assert(strlen(auth->a_secret) > 0);
470 login_compute_md5(id, auth->a_secret, challenge,
471 challenge_len, expected_response_bin,
472 sizeof(expected_response_bin));
474 if (memcmp(response_bin, expected_response_bin,
475 sizeof(expected_response_bin)) != 0) {
476 login_send_error(request, 0x02, 0x01);
477 log_errx(1, "CHAP authentication failed for user \"%s\"",
481 keys_delete(request_keys);
489 login_send_chap_success(struct pdu *request,
490 const struct auth *auth)
492 struct pdu *response;
493 struct keys *request_keys, *response_keys;
494 struct iscsi_bhs_login_response *bhslr2;
495 const char *chap_i, *chap_c;
496 char *chap_r, *challenge, response_bin[MD5_DIGEST_LENGTH];
497 size_t challenge_len;
501 response = login_new_response(request);
502 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
503 bhslr2->bhslr_flags |= BHSLR_FLAGS_TRANSIT;
504 login_set_nsg(response, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
507 * Actually, one more thing: mutual authentication.
509 request_keys = keys_new();
510 keys_load(request_keys, request);
511 chap_i = keys_find(request_keys, "CHAP_I");
512 chap_c = keys_find(request_keys, "CHAP_C");
513 if (chap_i != NULL || chap_c != NULL) {
514 if (chap_i == NULL) {
515 login_send_error(request, 0x02, 0x07);
516 log_errx(1, "initiator requested target "
517 "authentication, but didn't send CHAP_I");
519 if (chap_c == NULL) {
520 login_send_error(request, 0x02, 0x07);
521 log_errx(1, "initiator requested target "
522 "authentication, but didn't send CHAP_C");
524 if (auth->a_auth_group->ag_type != AG_TYPE_CHAP_MUTUAL) {
525 login_send_error(request, 0x02, 0x01);
526 log_errx(1, "initiator requests target authentication "
527 "for user \"%s\", but mutual user/secret "
528 "is not set", auth->a_user);
531 id = strtoul(chap_i, NULL, 10);
532 error = login_hex2bin(chap_c, &challenge, &challenge_len);
534 login_send_error(request, 0x02, 0x07);
535 log_errx(1, "received CHAP Login PDU with malformed "
539 log_debugx("performing mutual authentication as user \"%s\"",
540 auth->a_mutual_user);
541 login_compute_md5(id, auth->a_mutual_secret, challenge,
542 challenge_len, response_bin, sizeof(response_bin));
544 chap_r = login_bin2hex(response_bin,
545 sizeof(response_bin));
546 response_keys = keys_new();
547 keys_add(response_keys, "CHAP_N", auth->a_mutual_user);
548 keys_add(response_keys, "CHAP_R", chap_r);
550 keys_save(response_keys, response);
551 keys_delete(response_keys);
553 log_debugx("initiator did not request target authentication");
556 keys_delete(request_keys);
558 pdu_delete(response);
562 login_chap(struct connection *conn, struct auth_group *ag)
564 const struct auth *auth;
566 char challenge_bin[LOGIN_CHALLENGE_LEN];
571 * Receive CHAP_A PDU.
573 log_debugx("beginning CHAP authentication; waiting for CHAP_A");
574 request = login_receive_chap_a(conn);
577 * Generate the challenge.
579 rv = RAND_bytes(challenge_bin, sizeof(challenge_bin));
581 login_send_error(request, 0x03, 0x02);
582 log_errx(1, "RAND_bytes failed: %s",
583 ERR_error_string(ERR_get_error(), NULL));
585 rv = RAND_bytes(&id, sizeof(id));
587 login_send_error(request, 0x03, 0x02);
588 log_errx(1, "RAND_bytes failed: %s",
589 ERR_error_string(ERR_get_error(), NULL));
593 * Send the challenge.
595 log_debugx("sending CHAP_C, binary challenge size is %zd bytes",
596 sizeof(challenge_bin));
597 login_send_chap_c(request, id, challenge_bin,
598 sizeof(challenge_bin));
602 * Receive CHAP_N/CHAP_R PDU and authenticate.
604 log_debugx("waiting for CHAP_N/CHAP_R");
605 request = login_receive_chap_r(conn, ag, id, challenge_bin,
606 sizeof(challenge_bin), &auth);
609 * Yay, authentication succeeded!
611 log_debugx("authentication succeeded for user \"%s\"; "
612 "transitioning to Negotiation Phase", auth->a_user);
613 login_send_chap_success(request, auth);
618 login_negotiate_key(struct pdu *request, const char *name,
619 const char *value, bool skipped_security, struct keys *response_keys)
622 struct connection *conn;
624 conn = request->pdu_connection;
626 if (strcmp(name, "InitiatorName") == 0) {
627 if (!skipped_security)
628 log_errx(1, "initiator resent InitiatorName");
629 } else if (strcmp(name, "SessionType") == 0) {
630 if (!skipped_security)
631 log_errx(1, "initiator resent SessionType");
632 } else if (strcmp(name, "TargetName") == 0) {
633 if (!skipped_security)
634 log_errx(1, "initiator resent TargetName");
635 } else if (strcmp(name, "InitiatorAlias") == 0) {
636 if (conn->conn_initiator_alias != NULL)
637 free(conn->conn_initiator_alias);
638 conn->conn_initiator_alias = checked_strdup(value);
639 } else if (strcmp(value, "Irrelevant") == 0) {
641 } else if (strcmp(name, "HeaderDigest") == 0) {
643 * We don't handle digests for discovery sessions.
645 if (conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
646 log_debugx("discovery session; digests disabled");
647 keys_add(response_keys, name, "None");
651 which = login_list_prefers(value, "CRC32C", "None");
654 log_debugx("initiator prefers CRC32C "
655 "for header digest; we'll use it");
656 conn->conn_header_digest = CONN_DIGEST_CRC32C;
657 keys_add(response_keys, name, "CRC32C");
660 log_debugx("initiator prefers not to do "
661 "header digest; we'll comply");
662 keys_add(response_keys, name, "None");
665 log_warnx("initiator sent unrecognized "
666 "HeaderDigest value \"%s\"; will use None", value);
667 keys_add(response_keys, name, "None");
670 } else if (strcmp(name, "DataDigest") == 0) {
671 if (conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
672 log_debugx("discovery session; digests disabled");
673 keys_add(response_keys, name, "None");
677 which = login_list_prefers(value, "CRC32C", "None");
680 log_debugx("initiator prefers CRC32C "
681 "for data digest; we'll use it");
682 conn->conn_data_digest = CONN_DIGEST_CRC32C;
683 keys_add(response_keys, name, "CRC32C");
686 log_debugx("initiator prefers not to do "
687 "data digest; we'll comply");
688 keys_add(response_keys, name, "None");
691 log_warnx("initiator sent unrecognized "
692 "DataDigest value \"%s\"; will use None", value);
693 keys_add(response_keys, name, "None");
696 } else if (strcmp(name, "MaxConnections") == 0) {
697 keys_add(response_keys, name, "1");
698 } else if (strcmp(name, "InitialR2T") == 0) {
699 keys_add(response_keys, name, "Yes");
700 } else if (strcmp(name, "ImmediateData") == 0) {
701 if (conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
702 log_debugx("discovery session; ImmediateData irrelevant");
703 keys_add(response_keys, name, "Irrelevant");
705 if (strcmp(value, "Yes") == 0) {
706 conn->conn_immediate_data = true;
707 keys_add(response_keys, name, "Yes");
709 conn->conn_immediate_data = false;
710 keys_add(response_keys, name, "No");
713 } else if (strcmp(name, "MaxRecvDataSegmentLength") == 0) {
714 tmp = strtoul(value, NULL, 10);
716 login_send_error(request, 0x02, 0x00);
717 log_errx(1, "received invalid "
718 "MaxRecvDataSegmentLength");
720 if (tmp > MAX_DATA_SEGMENT_LENGTH) {
721 log_debugx("capping MaxDataSegmentLength from %d to %d",
722 tmp, MAX_DATA_SEGMENT_LENGTH);
723 tmp = MAX_DATA_SEGMENT_LENGTH;
725 conn->conn_max_data_segment_length = tmp;
726 keys_add_int(response_keys, name, tmp);
727 } else if (strcmp(name, "MaxBurstLength") == 0) {
728 tmp = strtoul(value, NULL, 10);
730 login_send_error(request, 0x02, 0x00);
731 log_errx(1, "received invalid MaxBurstLength");
733 if (tmp > MAX_BURST_LENGTH) {
734 log_debugx("capping MaxBurstLength from %d to %d",
735 tmp, MAX_BURST_LENGTH);
736 tmp = MAX_BURST_LENGTH;
738 conn->conn_max_burst_length = tmp;
739 keys_add(response_keys, name, value);
740 } else if (strcmp(name, "FirstBurstLength") == 0) {
741 tmp = strtoul(value, NULL, 10);
743 login_send_error(request, 0x02, 0x00);
744 log_errx(1, "received invalid "
747 if (tmp > MAX_DATA_SEGMENT_LENGTH) {
748 log_debugx("capping FirstBurstLength from %d to %d",
749 tmp, MAX_DATA_SEGMENT_LENGTH);
750 tmp = MAX_DATA_SEGMENT_LENGTH;
753 * We don't pass the value to the kernel; it only enforces
754 * hardcoded limit anyway.
756 keys_add_int(response_keys, name, tmp);
757 } else if (strcmp(name, "DefaultTime2Wait") == 0) {
758 keys_add(response_keys, name, value);
759 } else if (strcmp(name, "DefaultTime2Retain") == 0) {
760 keys_add(response_keys, name, "0");
761 } else if (strcmp(name, "MaxOutstandingR2T") == 0) {
762 keys_add(response_keys, name, "1");
763 } else if (strcmp(name, "DataPDUInOrder") == 0) {
764 keys_add(response_keys, name, "Yes");
765 } else if (strcmp(name, "DataSequenceInOrder") == 0) {
766 keys_add(response_keys, name, "Yes");
767 } else if (strcmp(name, "ErrorRecoveryLevel") == 0) {
768 keys_add(response_keys, name, "0");
769 } else if (strcmp(name, "OFMarker") == 0) {
770 keys_add(response_keys, name, "No");
771 } else if (strcmp(name, "IFMarker") == 0) {
772 keys_add(response_keys, name, "No");
774 log_debugx("unknown key \"%s\"; responding "
775 "with NotUnderstood", name);
776 keys_add(response_keys, name, "NotUnderstood");
781 login_negotiate(struct connection *conn, struct pdu *request)
783 struct pdu *response;
784 struct iscsi_bhs_login_response *bhslr2;
785 struct keys *request_keys, *response_keys;
787 bool skipped_security;
789 if (request == NULL) {
790 log_debugx("beginning operational parameter negotiation; "
791 "waiting for Login PDU");
792 request = login_receive(conn, false);
793 skipped_security = false;
795 skipped_security = true;
797 request_keys = keys_new();
798 keys_load(request_keys, request);
800 response = login_new_response(request);
801 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
802 bhslr2->bhslr_flags |= BHSLR_FLAGS_TRANSIT;
803 bhslr2->bhslr_tsih = htons(0xbadd);
804 login_set_csg(response, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
805 login_set_nsg(response, BHSLR_STAGE_FULL_FEATURE_PHASE);
806 response_keys = keys_new();
807 for (i = 0; i < KEYS_MAX; i++) {
808 if (request_keys->keys_names[i] == NULL)
811 login_negotiate_key(request, request_keys->keys_names[i],
812 request_keys->keys_values[i], skipped_security,
816 log_debugx("operational parameter negotiation done; "
817 "transitioning to Full Feature Phase");
819 keys_save(response_keys, response);
821 pdu_delete(response);
822 keys_delete(response_keys);
824 keys_delete(request_keys);
828 login(struct connection *conn)
830 struct pdu *request, *response;
831 struct iscsi_bhs_login_request *bhslr;
832 struct iscsi_bhs_login_response *bhslr2;
833 struct keys *request_keys, *response_keys;
834 struct auth_group *ag;
835 const char *initiator_name, *initiator_alias, *session_type,
836 *target_name, *auth_method;
837 char *portal_group_tag;
841 * Handle the initial Login Request - figure out required authentication
842 * method and either transition to the next phase, if no authentication
843 * is required, or call appropriate authentication code.
845 log_debugx("beginning Login Phase; waiting for Login PDU");
846 request = login_receive(conn, true);
847 bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
848 if (bhslr->bhslr_tsih != 0) {
849 login_send_error(request, 0x02, 0x0a);
850 log_errx(1, "received Login PDU with non-zero TSIH");
853 memcpy(conn->conn_initiator_isid, bhslr->bhslr_isid,
854 sizeof(conn->conn_initiator_isid));
857 * XXX: Implement the C flag some day.
859 request_keys = keys_new();
860 keys_load(request_keys, request);
862 assert(conn->conn_initiator_name == NULL);
863 initiator_name = keys_find(request_keys, "InitiatorName");
864 if (initiator_name == NULL) {
865 login_send_error(request, 0x02, 0x07);
866 log_errx(1, "received Login PDU without InitiatorName");
868 if (valid_iscsi_name(initiator_name) == false) {
869 login_send_error(request, 0x02, 0x00);
870 log_errx(1, "received Login PDU with invalid InitiatorName");
872 conn->conn_initiator_name = checked_strdup(initiator_name);
873 log_set_peer_name(conn->conn_initiator_name);
875 * XXX: This doesn't work (does nothing) because of Capsicum.
877 setproctitle("%s (%s)", conn->conn_initiator_addr, conn->conn_initiator_name);
879 initiator_alias = keys_find(request_keys, "InitiatorAlias");
880 if (initiator_alias != NULL)
881 conn->conn_initiator_alias = checked_strdup(initiator_alias);
883 assert(conn->conn_session_type == CONN_SESSION_TYPE_NONE);
884 session_type = keys_find(request_keys, "SessionType");
885 if (session_type != NULL) {
886 if (strcmp(session_type, "Normal") == 0) {
887 conn->conn_session_type = CONN_SESSION_TYPE_NORMAL;
888 } else if (strcmp(session_type, "Discovery") == 0) {
889 conn->conn_session_type = CONN_SESSION_TYPE_DISCOVERY;
891 login_send_error(request, 0x02, 0x00);
892 log_errx(1, "received Login PDU with invalid "
893 "SessionType \"%s\"", session_type);
896 conn->conn_session_type = CONN_SESSION_TYPE_NORMAL;
898 assert(conn->conn_target == NULL);
899 if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
900 target_name = keys_find(request_keys, "TargetName");
901 if (target_name == NULL) {
902 login_send_error(request, 0x02, 0x07);
903 log_errx(1, "received Login PDU without TargetName");
907 target_find(conn->conn_portal->p_portal_group->pg_conf,
909 if (conn->conn_target == NULL) {
910 login_send_error(request, 0x02, 0x03);
911 log_errx(1, "requested target \"%s\" not found",
917 * At this point we know what kind of authentication we need.
919 if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
920 ag = conn->conn_target->t_auth_group;
921 if (ag->ag_name != NULL) {
922 log_debugx("initiator requests to connect "
923 "to target \"%s\"; auth-group \"%s\"",
924 conn->conn_target->t_name,
925 conn->conn_target->t_auth_group->ag_name);
927 log_debugx("initiator requests to connect "
928 "to target \"%s\"", conn->conn_target->t_name);
931 assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY);
932 ag = conn->conn_portal->p_portal_group->pg_discovery_auth_group;
933 if (ag->ag_name != NULL) {
934 log_debugx("initiator requests "
935 "discovery session; auth-group \"%s\"", ag->ag_name);
937 log_debugx("initiator requests discovery session");
942 * Enforce initiator-name and initiator-portal.
944 if (auth_name_defined(ag)) {
945 if (auth_name_find(ag, initiator_name) == NULL) {
946 login_send_error(request, 0x02, 0x02);
947 log_errx(1, "initiator does not match allowed "
950 log_debugx("initiator matches allowed initiator names");
952 log_debugx("auth-group does not define initiator name "
956 if (auth_portal_defined(ag)) {
957 if (auth_portal_find(ag, &conn->conn_initiator_sa) == NULL) {
958 login_send_error(request, 0x02, 0x02);
959 log_errx(1, "initiator does not match allowed "
960 "initiator portals");
962 log_debugx("initiator matches allowed initiator portals");
964 log_debugx("auth-group does not define initiator portal "
969 * Let's see if the initiator intends to do any kind of authentication
972 if (login_csg(request) == BHSLR_STAGE_OPERATIONAL_NEGOTIATION) {
973 if (ag->ag_type != AG_TYPE_NO_AUTHENTICATION) {
974 login_send_error(request, 0x02, 0x01);
975 log_errx(1, "initiator skipped the authentication, "
976 "but authentication is required");
979 keys_delete(request_keys);
981 log_debugx("initiator skipped the authentication, "
982 "and we don't need it; proceeding with negotiation");
983 login_negotiate(conn, request);
987 if (ag->ag_type == AG_TYPE_NO_AUTHENTICATION) {
989 * Initiator might want to to authenticate,
990 * but we don't need it.
992 log_debugx("authentication not required; "
993 "transitioning to operational parameter negotiation");
995 if ((bhslr->bhslr_flags & BHSLR_FLAGS_TRANSIT) == 0)
996 log_warnx("initiator did not set the \"T\" flag; "
997 "transitioning anyway");
999 response = login_new_response(request);
1000 bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
1001 bhslr2->bhslr_flags |= BHSLR_FLAGS_TRANSIT;
1002 login_set_nsg(response,
1003 BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
1004 response_keys = keys_new();
1006 * Required by Linux initiator.
1008 auth_method = keys_find(request_keys, "AuthMethod");
1009 if (auth_method != NULL &&
1010 login_list_contains(auth_method, "None"))
1011 keys_add(response_keys, "AuthMethod", "None");
1013 if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
1014 if (conn->conn_target->t_alias != NULL)
1015 keys_add(response_keys,
1016 "TargetAlias", conn->conn_target->t_alias);
1017 rv = asprintf(&portal_group_tag, "%d",
1018 conn->conn_portal->p_portal_group->pg_tag);
1020 log_err(1, "asprintf");
1021 keys_add(response_keys,
1022 "TargetPortalGroupTag", portal_group_tag);
1023 free(portal_group_tag);
1025 keys_save(response_keys, response);
1027 pdu_delete(response);
1028 keys_delete(response_keys);
1029 pdu_delete(request);
1030 keys_delete(request_keys);
1032 login_negotiate(conn, NULL);
1036 if (ag->ag_type == AG_TYPE_DENY) {
1037 login_send_error(request, 0x02, 0x01);
1038 log_errx(1, "auth-type is \"deny\"");
1041 if (ag->ag_type == AG_TYPE_UNKNOWN) {
1043 * This can happen with empty auth-group.
1045 login_send_error(request, 0x02, 0x01);
1046 log_errx(1, "auth-type not set, denying access");
1049 log_debugx("CHAP authentication required");
1051 auth_method = keys_find(request_keys, "AuthMethod");
1052 if (auth_method == NULL) {
1053 login_send_error(request, 0x02, 0x07);
1054 log_errx(1, "received Login PDU without AuthMethod");
1057 * XXX: This should be Reject, not just a login failure (5.3.2).
1059 if (login_list_contains(auth_method, "CHAP") == 0) {
1060 login_send_error(request, 0x02, 0x01);
1061 log_errx(1, "initiator requests unsupported AuthMethod \"%s\" "
1062 "instead of \"CHAP\"", auth_method);
1065 response = login_new_response(request);
1067 response_keys = keys_new();
1068 keys_add(response_keys, "AuthMethod", "CHAP");
1069 if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
1070 rv = asprintf(&portal_group_tag, "%d",
1071 conn->conn_portal->p_portal_group->pg_tag);
1073 log_err(1, "asprintf");
1074 keys_add(response_keys,
1075 "TargetPortalGroupTag", portal_group_tag);
1076 free(portal_group_tag);
1077 if (conn->conn_target->t_alias != NULL)
1078 keys_add(response_keys,
1079 "TargetAlias", conn->conn_target->t_alias);
1081 keys_save(response_keys, response);
1084 pdu_delete(response);
1085 keys_delete(response_keys);
1086 pdu_delete(request);
1087 keys_delete(request_keys);
1089 login_chap(conn, ag);
1091 login_negotiate(conn, NULL);