]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/iscsid/login.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / usr.sbin / iscsid / login.c
1 /*-
2  * Copyright (c) 2012 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Edward Tomasz Napierala under sponsorship
6  * from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
16  *
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
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 #include <sys/types.h>
33 #include <assert.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <netinet/in.h>
39 #include <openssl/err.h>
40 #include <openssl/md5.h>
41 #include <openssl/rand.h>
42
43 #include "iscsid.h"
44 #include "iscsi_proto.h"
45
46 static int
47 login_nsg(const struct pdu *response)
48 {
49         struct iscsi_bhs_login_response *bhslr;
50
51         bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs;
52
53         return (bhslr->bhslr_flags & 0x03);
54 }
55
56 static void
57 login_set_nsg(struct pdu *request, int nsg)
58 {
59         struct iscsi_bhs_login_request *bhslr;
60
61         assert(nsg == BHSLR_STAGE_SECURITY_NEGOTIATION ||
62             nsg == BHSLR_STAGE_OPERATIONAL_NEGOTIATION ||
63             nsg == BHSLR_STAGE_FULL_FEATURE_PHASE);
64
65         bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
66
67         bhslr->bhslr_flags &= 0xFC;
68         bhslr->bhslr_flags |= nsg;
69 }
70
71 static void
72 login_set_csg(struct pdu *request, int csg)
73 {
74         struct iscsi_bhs_login_request *bhslr;
75
76         assert(csg == BHSLR_STAGE_SECURITY_NEGOTIATION ||
77             csg == BHSLR_STAGE_OPERATIONAL_NEGOTIATION ||
78             csg == BHSLR_STAGE_FULL_FEATURE_PHASE);
79
80         bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
81
82         bhslr->bhslr_flags &= 0xF3;
83         bhslr->bhslr_flags |= csg << 2;
84 }
85
86 static const char *
87 login_target_error_str(int class, int detail)
88 {
89         static char msg[128];
90
91         /*
92          * RFC 3270, 10.13.5.  Status-Class and Status-Detail
93          */
94         switch (class) {
95         case 0x01:
96                 switch (detail) {
97                 case 0x01:
98                         return ("Target moved temporarily");
99                 case 0x02:
100                         return ("Target moved permanently");
101                 default:
102                         snprintf(msg, sizeof(msg), "unknown redirection; "
103                             "Status-Class 0x%x, Status-Detail 0x%x",
104                             class, detail);
105                         return (msg);
106                 }
107         case 0x02:
108                 switch (detail) {
109                 case 0x00:
110                         return ("Initiator error");
111                 case 0x01:
112                         return ("Authentication failure");
113                 case 0x02:
114                         return ("Authorization failure");
115                 case 0x03:
116                         return ("Not found");
117                 case 0x04:
118                         return ("Target removed");
119                 case 0x05:
120                         return ("Unsupported version");
121                 case 0x06:
122                         return ("Too many connections");
123                 case 0x07:
124                         return ("Missing parameter");
125                 case 0x08:
126                         return ("Can't include in session");
127                 case 0x09:
128                         return ("Session type not supported");
129                 case 0x0a:
130                         return ("Session does not exist");
131                 case 0x0b:
132                         return ("Invalid during login");
133                 default:
134                         snprintf(msg, sizeof(msg), "unknown initiator error; "
135                             "Status-Class 0x%x, Status-Detail 0x%x",
136                             class, detail);
137                         return (msg);
138                 }
139         case 0x03:
140                 switch (detail) {
141                 case 0x00:
142                         return ("Target error");
143                 case 0x01:
144                         return ("Service unavailable");
145                 case 0x02:
146                         return ("Out of resources");
147                 default:
148                         snprintf(msg, sizeof(msg), "unknown target error; "
149                             "Status-Class 0x%x, Status-Detail 0x%x",
150                             class, detail);
151                         return (msg);
152                 }
153         default:
154                 snprintf(msg, sizeof(msg), "unknown error; "
155                     "Status-Class 0x%x, Status-Detail 0x%x",
156                     class, detail);
157                 return (msg);
158         }
159 }
160
161 static struct pdu *
162 login_receive(struct connection *conn, bool initial)
163 {
164         struct pdu *response;
165         struct iscsi_bhs_login_response *bhslr;
166         const char *errorstr;
167
168         response = pdu_new(conn);
169         pdu_receive(response);
170         if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_LOGIN_RESPONSE) {
171                 log_errx(1, "protocol error: received invalid opcode 0x%x",
172                     response->pdu_bhs->bhs_opcode);
173         }
174         bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs;
175         /*
176          * XXX: Implement the C flag some day.
177          */
178         if ((bhslr->bhslr_flags & BHSLR_FLAGS_CONTINUE) != 0)
179                 log_errx(1, "received Login PDU with unsupported \"C\" flag");
180         if (bhslr->bhslr_version_max != 0x00)
181                 log_errx(1, "received Login PDU with unsupported "
182                     "Version-max 0x%x", bhslr->bhslr_version_max);
183         if (bhslr->bhslr_version_active != 0x00)
184                 log_errx(1, "received Login PDU with unsupported "
185                     "Version-active 0x%x", bhslr->bhslr_version_active);
186         if (bhslr->bhslr_status_class != 0) {
187                 errorstr = login_target_error_str(bhslr->bhslr_status_class,
188                     bhslr->bhslr_status_detail);
189                 fail(conn, errorstr);
190                 log_errx(1, "target returned error: %s", errorstr);
191         }
192 #if 0
193         if (response->pdu_data_len == 0)
194                 log_errx(1, "received Login PDU with empty data segment");
195 #endif
196         if (initial == false &&
197             ntohl(bhslr->bhslr_statsn) != conn->conn_statsn + 1) {
198                 /*
199                  * It's a warning, not an error, to work around what seems
200                  * to be bug in NetBSD iSCSI target.
201                  */
202                 log_warnx("received Login PDU with wrong StatSN: "
203                     "is %d, should be %d", ntohl(bhslr->bhslr_statsn),
204                     conn->conn_statsn + 1);
205         }
206         conn->conn_statsn = ntohl(bhslr->bhslr_statsn);
207
208         return (response);
209 }
210
211 static struct pdu *
212 login_new_request(struct connection *conn)
213 {
214         struct pdu *request;
215         struct iscsi_bhs_login_request *bhslr;
216
217         request = pdu_new(conn);
218         bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
219         bhslr->bhslr_opcode = ISCSI_BHS_OPCODE_LOGIN_REQUEST |
220             ISCSI_BHS_OPCODE_IMMEDIATE;
221         bhslr->bhslr_flags = BHSLR_FLAGS_TRANSIT;
222         login_set_csg(request, BHSLR_STAGE_SECURITY_NEGOTIATION);
223         login_set_nsg(request, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
224         memcpy(bhslr->bhslr_isid, &conn->conn_isid, sizeof(bhslr->bhslr_isid));
225         bhslr->bhslr_initiator_task_tag = 0;
226         bhslr->bhslr_cmdsn = 0;
227         bhslr->bhslr_expstatsn = htonl(conn->conn_statsn + 1);
228
229         return (request);
230 }
231
232 static int
233 login_list_prefers(const char *list,
234     const char *choice1, const char *choice2)
235 {
236         char *tofree, *str, *token;
237
238         tofree = str = checked_strdup(list);
239
240         while ((token = strsep(&str, ",")) != NULL) {
241                 if (strcmp(token, choice1) == 0) {
242                         free(tofree);
243                         return (1);
244                 }
245                 if (strcmp(token, choice2) == 0) {
246                         free(tofree);
247                         return (2);
248                 }
249         }
250         free(tofree);
251         return (-1);
252 }
253
254 static int
255 login_hex2int(const char hex)
256 {
257         switch (hex) {
258         case '0':
259                 return (0x00);
260         case '1':
261                 return (0x01);
262         case '2':
263                 return (0x02);
264         case '3':
265                 return (0x03);
266         case '4':
267                 return (0x04);
268         case '5':
269                 return (0x05);
270         case '6':
271                 return (0x06);
272         case '7':
273                 return (0x07);
274         case '8':
275                 return (0x08);
276         case '9':
277                 return (0x09);
278         case 'a':
279         case 'A':
280                 return (0x0a);
281         case 'b':
282         case 'B':
283                 return (0x0b);
284         case 'c':
285         case 'C':
286                 return (0x0c);
287         case 'd':
288         case 'D':
289                 return (0x0d);
290         case 'e':
291         case 'E':
292                 return (0x0e);
293         case 'f':
294         case 'F':
295                 return (0x0f);
296         default:
297                 return (-1);
298         }
299 }
300
301 /*
302  * XXX: Review this _carefully_.
303  */
304 static int
305 login_hex2bin(const char *hex, char **binp, size_t *bin_lenp)
306 {
307         int i, hex_len, nibble;
308         bool lo = true; /* As opposed to 'hi'. */
309         char *bin;
310         size_t bin_off, bin_len;
311
312         if (strncasecmp(hex, "0x", strlen("0x")) != 0) {
313                 log_warnx("malformed variable, should start with \"0x\"");
314                 return (-1);
315         }
316
317         hex += strlen("0x");
318         hex_len = strlen(hex);
319         if (hex_len < 1) {
320                 log_warnx("malformed variable; doesn't contain anything "
321                     "but \"0x\"");
322                 return (-1);
323         }
324
325         bin_len = hex_len / 2 + hex_len % 2;
326         bin = calloc(bin_len, 1);
327         if (bin == NULL)
328                 log_err(1, "calloc");
329
330         bin_off = bin_len - 1;
331         for (i = hex_len - 1; i >= 0; i--) {
332                 nibble = login_hex2int(hex[i]);
333                 if (nibble < 0) {
334                         log_warnx("malformed variable, invalid char \"%c\"",
335                             hex[i]);
336                         return (-1);
337                 }
338
339                 assert(bin_off < bin_len);
340                 if (lo) {
341                         bin[bin_off] = nibble;
342                         lo = false;
343                 } else {
344                         bin[bin_off] |= nibble << 4;
345                         bin_off--;
346                         lo = true;
347                 }
348         }
349
350         *binp = bin;
351         *bin_lenp = bin_len;
352         return (0);
353 }
354
355 static char *
356 login_bin2hex(const char *bin, size_t bin_len)
357 {
358         unsigned char *hex, *tmp, ch;
359         size_t hex_len;
360         size_t i;
361
362         hex_len = bin_len * 2 + 3; /* +2 for "0x", +1 for '\0'. */
363         hex = malloc(hex_len);
364         if (hex == NULL)
365                 log_err(1, "malloc");
366
367         tmp = hex;
368         tmp += sprintf(tmp, "0x");
369         for (i = 0; i < bin_len; i++) {
370                 ch = bin[i];
371                 tmp += sprintf(tmp, "%02x", ch);
372         }
373
374         return (hex);
375 }
376
377 static void
378 login_compute_md5(const char id, const char *secret,
379     const void *challenge, size_t challenge_len, void *response,
380     size_t response_len)
381 {
382         MD5_CTX ctx;
383         int rv;
384
385         assert(response_len == MD5_DIGEST_LENGTH);
386
387         MD5_Init(&ctx);
388         MD5_Update(&ctx, &id, sizeof(id));
389         MD5_Update(&ctx, secret, strlen(secret));
390         MD5_Update(&ctx, challenge, challenge_len);
391         rv = MD5_Final(response, &ctx);
392         if (rv != 1)
393                 log_errx(1, "MD5_Final");
394 }
395
396 static void
397 login_negotiate_key(struct connection *conn, const char *name,
398     const char *value)
399 {
400         int which, tmp;
401
402         if (strcmp(name, "TargetAlias") == 0) {
403                 strlcpy(conn->conn_target_alias, value,
404                     sizeof(conn->conn_target_alias));
405         } else if (strcmp(value, "Irrelevant") == 0) {
406                 /* Ignore. */
407         } else if (strcmp(name, "HeaderDigest") == 0) {
408                 which = login_list_prefers(value, "CRC32C", "None");
409                 switch (which) {
410                 case 1:
411                         log_debugx("target prefers CRC32C "
412                             "for header digest; we'll use it");
413                         conn->conn_header_digest = CONN_DIGEST_CRC32C;
414                         break;
415                 case 2:
416                         log_debugx("target prefers not to do "
417                             "header digest; we'll comply");
418                         break;
419                 default:
420                         log_warnx("target sent unrecognized "
421                             "HeaderDigest value \"%s\"; will use None", value);
422                         break;
423                 }
424         } else if (strcmp(name, "DataDigest") == 0) {
425                 which = login_list_prefers(value, "CRC32C", "None");
426                 switch (which) {
427                 case 1:
428                         log_debugx("target prefers CRC32C "
429                             "for data digest; we'll use it");
430                         conn->conn_data_digest = CONN_DIGEST_CRC32C;
431                         break;
432                 case 2:
433                         log_debugx("target prefers not to do "
434                             "data digest; we'll comply");
435                         break;
436                 default:
437                         log_warnx("target sent unrecognized "
438                             "DataDigest value \"%s\"; will use None", value);
439                         break;
440                 }
441         } else if (strcmp(name, "MaxConnections") == 0) {
442                 /* Ignore. */
443         } else if (strcmp(name, "InitialR2T") == 0) {
444                 if (strcmp(value, "Yes") == 0)
445                         conn->conn_initial_r2t = true;
446                 else
447                         conn->conn_initial_r2t = false;
448         } else if (strcmp(name, "ImmediateData") == 0) {
449                 if (strcmp(value, "Yes") == 0)
450                         conn->conn_immediate_data = true;
451                 else
452                         conn->conn_immediate_data = false;
453         } else if (strcmp(name, "MaxRecvDataSegmentLength") == 0) {
454                 tmp = strtoul(value, NULL, 10);
455                 if (tmp <= 0)
456                         log_errx(1, "received invalid "
457                             "MaxRecvDataSegmentLength");
458                 conn->conn_max_data_segment_length = tmp;
459         } else if (strcmp(name, "MaxBurstLength") == 0) {
460                 if (conn->conn_immediate_data) {
461                         tmp = strtoul(value, NULL, 10);
462                         if (tmp <= 0)
463                                 log_errx(1, "received invalid MaxBurstLength");
464                         conn->conn_max_burst_length = tmp;
465                 }
466         } else if (strcmp(name, "FirstBurstLength") == 0) {
467                 tmp = strtoul(value, NULL, 10);
468                 if (tmp <= 0)
469                         log_errx(1, "received invalid FirstBurstLength");
470                 conn->conn_first_burst_length = tmp;
471         } else if (strcmp(name, "DefaultTime2Wait") == 0) {
472                 /* Ignore */
473         } else if (strcmp(name, "DefaultTime2Retain") == 0) {
474                 /* Ignore */
475         } else if (strcmp(name, "MaxOutstandingR2T") == 0) {
476                 /* Ignore */
477         } else if (strcmp(name, "DataPDUInOrder") == 0) {
478                 /* Ignore */
479         } else if (strcmp(name, "DataSequenceInOrder") == 0) {
480                 /* Ignore */
481         } else if (strcmp(name, "ErrorRecoveryLevel") == 0) {
482                 /* Ignore */
483         } else if (strcmp(name, "OFMarker") == 0) {
484                 /* Ignore */
485         } else if (strcmp(name, "IFMarker") == 0) {
486                 /* Ignore */
487         } else if (strcmp(name, "TargetPortalGroupTag") == 0) {
488                 /* Ignore */
489         } else {
490                 log_debugx("unknown key \"%s\"; ignoring",  name);
491         }
492 }
493
494 static void
495 login_negotiate(struct connection *conn)
496 {
497         struct pdu *request, *response;
498         struct keys *request_keys, *response_keys;
499         struct iscsi_bhs_login_response *bhslr;
500         int i;
501
502         log_debugx("beginning parameter negotiation");
503         request = login_new_request(conn);
504         login_set_csg(request, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
505         login_set_nsg(request, BHSLR_STAGE_FULL_FEATURE_PHASE);
506         request_keys = keys_new();
507
508         /*
509          * The following keys are irrelevant for discovery sessions.
510          */
511         if (conn->conn_conf.isc_discovery == 0) {
512                 if (conn->conn_conf.isc_header_digest != 0)
513                         keys_add(request_keys, "HeaderDigest", "CRC32C");
514                 else
515                         keys_add(request_keys, "HeaderDigest", "None");
516                 if (conn->conn_conf.isc_data_digest != 0)
517                         keys_add(request_keys, "DataDigest", "CRC32C");
518                 else
519                         keys_add(request_keys, "DataDigest", "None");
520
521                 keys_add(request_keys, "ImmediateData", "Yes");
522                 keys_add_int(request_keys, "MaxBurstLength",
523                     ISCSI_MAX_DATA_SEGMENT_LENGTH);
524                 keys_add_int(request_keys, "FirstBurstLength",
525                     ISCSI_MAX_DATA_SEGMENT_LENGTH);
526                 keys_add(request_keys, "InitialR2T", "Yes");
527         } else {
528                 keys_add(request_keys, "HeaderDigest", "None");
529                 keys_add(request_keys, "DataDigest", "None");
530         }
531
532         keys_add_int(request_keys, "MaxRecvDataSegmentLength",
533             ISCSI_MAX_DATA_SEGMENT_LENGTH);
534         keys_add(request_keys, "DefaultTime2Wait", "0");
535         keys_add(request_keys, "DefaultTime2Retain", "0");
536         keys_add(request_keys, "ErrorRecoveryLevel", "0");
537         keys_add(request_keys, "MaxOutstandingR2T", "1");
538         keys_save(request_keys, request);
539         keys_delete(request_keys);
540         request_keys = NULL;
541         pdu_send(request);
542         pdu_delete(request);
543         request = NULL;
544
545         response = login_receive(conn, false);
546         response_keys = keys_new();
547         keys_load(response_keys, response);
548         for (i = 0; i < KEYS_MAX; i++) {
549                 if (response_keys->keys_names[i] == NULL)
550                         break;
551
552                 login_negotiate_key(conn,
553                     response_keys->keys_names[i], response_keys->keys_values[i]);
554         }
555
556         bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs;
557         if ((bhslr->bhslr_flags & BHSLR_FLAGS_TRANSIT) == 0)
558                 log_warnx("received final login response "
559                     "without the \"T\" flag");
560         else if (login_nsg(response) != BHSLR_STAGE_FULL_FEATURE_PHASE)
561                 log_warnx("received final login response with wrong NSG 0x%x",
562                     login_nsg(response));
563
564         log_debugx("parameter negotiation done; "
565             "transitioning to Full Feature phase");
566
567         keys_delete(response_keys);
568         pdu_delete(response);
569 }
570
571 static void
572 login_send_chap_a(struct connection *conn)
573 {
574         struct pdu *request;
575         struct keys *request_keys;
576
577         request = login_new_request(conn);
578         request_keys = keys_new();
579         keys_add(request_keys, "CHAP_A", "5");
580         keys_save(request_keys, request);
581         keys_delete(request_keys);
582         pdu_send(request);
583         pdu_delete(request);
584 }
585
586 static void
587 login_send_chap_r(struct pdu *response)
588 {
589         struct connection *conn;
590         struct pdu *request;
591         struct keys *request_keys, *response_keys;
592         const char *chap_a, *chap_c, *chap_i;
593         char *chap_r, *challenge, response_bin[MD5_DIGEST_LENGTH];
594         size_t challenge_len;
595         int error, rv;
596         unsigned char id;
597         char *mutual_chap_c, mutual_chap_i[4];
598
599         /*
600          * As in the rest of the initiator, 'request' means
601          * 'initiator -> target', and 'response' means 'target -> initiator',
602          *
603          * So, here the 'response' from the target is the packet that contains
604          * CHAP challenge; our CHAP response goes into 'request'.
605          */
606
607         conn = response->pdu_connection;
608
609         response_keys = keys_new();
610         keys_load(response_keys, response);
611
612         /*
613          * First, compute the response.
614          */
615         chap_a = keys_find(response_keys, "CHAP_A");
616         if (chap_a == NULL)
617                 log_errx(1, "received CHAP packet without CHAP_A");
618         chap_c = keys_find(response_keys, "CHAP_C");
619         if (chap_c == NULL)
620                 log_errx(1, "received CHAP packet without CHAP_C");
621         chap_i = keys_find(response_keys, "CHAP_I");
622         if (chap_i == NULL)
623                 log_errx(1, "received CHAP packet without CHAP_I");
624
625         if (strcmp(chap_a, "5") != 0)
626                 log_errx(1, "received CHAP packet "
627                     "with unsupported CHAP_A \"%s\"", chap_a);
628         id = strtoul(chap_i, NULL, 10);
629         error = login_hex2bin(chap_c, &challenge, &challenge_len);
630         if (error != 0)
631                 log_errx(1, "received CHAP packet with malformed CHAP_C");
632         login_compute_md5(id, conn->conn_conf.isc_secret,
633             challenge, challenge_len, response_bin, sizeof(response_bin));
634         free(challenge);
635         chap_r = login_bin2hex(response_bin, sizeof(response_bin));
636
637         keys_delete(response_keys);
638
639         request = login_new_request(conn);
640         request_keys = keys_new();
641         keys_add(request_keys, "CHAP_N", conn->conn_conf.isc_user);
642         keys_add(request_keys, "CHAP_R", chap_r);
643         free(chap_r);
644
645         /*
646          * If we want mutual authentication, we're expected to send
647          * our CHAP_I/CHAP_C now.
648          */
649         if (conn->conn_conf.isc_mutual_user[0] != '\0') {
650                 log_debugx("requesting mutual authentication; "
651                     "binary challenge size is %zd bytes",
652                     sizeof(conn->conn_mutual_challenge));
653
654                 rv = RAND_bytes(conn->conn_mutual_challenge,
655                     sizeof(conn->conn_mutual_challenge));
656                 if (rv != 1) {
657                         log_errx(1, "RAND_bytes failed: %s",
658                             ERR_error_string(ERR_get_error(), NULL));
659                 }
660                 rv = RAND_bytes(&conn->conn_mutual_id,
661                     sizeof(conn->conn_mutual_id));
662                 if (rv != 1) {
663                         log_errx(1, "RAND_bytes failed: %s",
664                             ERR_error_string(ERR_get_error(), NULL));
665                 }
666                 mutual_chap_c = login_bin2hex(conn->conn_mutual_challenge,
667                     sizeof(conn->conn_mutual_challenge));
668                 snprintf(mutual_chap_i, sizeof(mutual_chap_i),
669                     "%d", conn->conn_mutual_id);
670                 keys_add(request_keys, "CHAP_I", mutual_chap_i);
671                 keys_add(request_keys, "CHAP_C", mutual_chap_c);
672                 free(mutual_chap_c);
673         }
674
675         keys_save(request_keys, request);
676         keys_delete(request_keys);
677         pdu_send(request);
678         pdu_delete(request);
679 }
680
681 static void
682 login_verify_mutual(const struct pdu *response)
683 {
684         struct connection *conn;
685         struct keys *response_keys;
686         const char *chap_n, *chap_r;
687         char *response_bin, expected_response_bin[MD5_DIGEST_LENGTH];
688         size_t response_bin_len;
689         int error;
690
691         conn = response->pdu_connection;
692
693         response_keys = keys_new();
694         keys_load(response_keys, response);
695
696         chap_n = keys_find(response_keys, "CHAP_N");
697         if (chap_n == NULL)
698                 log_errx(1, "received CHAP Response PDU without CHAP_N");
699         chap_r = keys_find(response_keys, "CHAP_R");
700         if (chap_r == NULL)
701                 log_errx(1, "received CHAP Response PDU without CHAP_R");
702         error = login_hex2bin(chap_r, &response_bin, &response_bin_len);
703         if (error != 0)
704                 log_errx(1, "received CHAP Response PDU with malformed CHAP_R");
705
706         if (strcmp(chap_n, conn->conn_conf.isc_mutual_user) != 0) {
707                 fail(conn, "Mutual CHAP failed");
708                 log_errx(1, "mutual CHAP authentication failed: wrong user");
709         }
710
711         login_compute_md5(conn->conn_mutual_id,
712             conn->conn_conf.isc_mutual_secret, conn->conn_mutual_challenge,
713             sizeof(conn->conn_mutual_challenge), expected_response_bin,
714             sizeof(expected_response_bin));
715
716         if (memcmp(response_bin, expected_response_bin,
717             sizeof(expected_response_bin)) != 0) {
718                 fail(conn, "Mutual CHAP failed");
719                 log_errx(1, "mutual CHAP authentication failed: wrong secret");
720         }
721
722         keys_delete(response_keys);
723         free(response_bin);
724
725         log_debugx("mutual CHAP authentication succeeded");
726 }
727
728 static void
729 login_chap(struct connection *conn)
730 {
731         struct pdu *response;
732
733         log_debugx("beginning CHAP authentication; sending CHAP_A");
734         login_send_chap_a(conn);
735
736         log_debugx("waiting for CHAP_A/CHAP_C/CHAP_I");
737         response = login_receive(conn, false);
738
739         log_debugx("sending CHAP_N/CHAP_R");
740         login_send_chap_r(response);
741         pdu_delete(response);
742
743         /*
744          * XXX: Make sure this is not susceptible to MITM.
745          */
746
747         log_debugx("waiting for CHAP result");
748         response = login_receive(conn, false);
749         if (conn->conn_conf.isc_mutual_user[0] != '\0')
750                 login_verify_mutual(response);
751         pdu_delete(response);
752
753         log_debugx("CHAP authentication done");
754 }
755
756 static void
757 login_create_isid(struct connection *conn)
758 {
759         int rv;
760
761         /*
762          * RFC 3720, 10.12.5: 10b, "Random" ISID.
763          *
764          */
765         conn->conn_isid[0] = 0x80; 
766
767         rv = RAND_bytes(&conn->conn_isid[1], 3);
768         if (rv != 1) {
769                 log_errx(1, "RAND_bytes failed: %s",
770                     ERR_error_string(ERR_get_error(), NULL));
771         }
772 }
773
774 void
775 login(struct connection *conn)
776 {
777         struct pdu *request, *response;
778         struct keys *request_keys, *response_keys;
779         struct iscsi_bhs_login_request *bhslr;
780         struct iscsi_bhs_login_response *bhslr2;
781         const char *auth_method;
782         int i;
783
784         login_create_isid(conn);
785
786         log_debugx("beginning Login phase; sending Login PDU");
787         request = login_new_request(conn);
788
789         bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
790         bhslr->bhslr_flags |= BHSLR_FLAGS_TRANSIT;
791
792         request_keys = keys_new();
793         if (conn->conn_conf.isc_mutual_user[0] != '\0') {
794                 keys_add(request_keys, "AuthMethod", "CHAP");
795         } else if (conn->conn_conf.isc_user[0] != '\0') {
796                 /*
797                  * Give target a chance to skip authentication if it
798                  * doesn't feel like it.
799                  *
800                  * None is first, CHAP second; this is to work around
801                  * what seems to be LIO (Linux target) bug: otherwise,
802                  * if target is configured with no authentication,
803                  * and we are configured to authenticate, the target
804                  * will erroneously respond with AuthMethod=CHAP
805                  * instead of AuthMethod=None, and will subsequently
806                  * fail the connection.  This usually happens with
807                  * Discovery sessions, which default to no authentication.
808                  */
809                 keys_add(request_keys, "AuthMethod", "None,CHAP");
810         } else {
811                 keys_add(request_keys, "AuthMethod", "None");
812         }
813         keys_add(request_keys, "InitiatorName",
814             conn->conn_conf.isc_initiator);
815         if (conn->conn_conf.isc_initiator_alias[0] != '\0') {
816                 keys_add(request_keys, "InitiatorAlias",
817                     conn->conn_conf.isc_initiator_alias);
818         }
819         if (conn->conn_conf.isc_discovery == 0) {
820                 keys_add(request_keys, "SessionType", "Normal");
821                 keys_add(request_keys,
822                     "TargetName", conn->conn_conf.isc_target);
823         } else {
824                 keys_add(request_keys, "SessionType", "Discovery");
825         }
826         keys_save(request_keys, request);
827         keys_delete(request_keys);
828         pdu_send(request);
829         pdu_delete(request);
830
831         response = login_receive(conn, true);
832
833         response_keys = keys_new();
834         keys_load(response_keys, response);
835
836         for (i = 0; i < KEYS_MAX; i++) {
837                 if (response_keys->keys_names[i] == NULL)
838                         break;
839
840                 /*
841                  * Not interested in AuthMethod at this point; we only need
842                  * to parse things such as TargetAlias.
843                  *
844                  * XXX: This is somewhat ugly.  We should have a way to apply
845                  *      all the keys to the session and use that by default
846                  *      instead of discarding them.
847                  */
848                 if (strcmp(response_keys->keys_names[i], "AuthMethod") == 0)
849                         continue;
850
851                 login_negotiate_key(conn,
852                     response_keys->keys_names[i], response_keys->keys_values[i]);
853         }
854
855         bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
856         if ((bhslr2->bhslr_flags & BHSLR_FLAGS_TRANSIT) != 0 &&
857             login_nsg(response) == BHSLR_STAGE_OPERATIONAL_NEGOTIATION) {
858                 if (conn->conn_conf.isc_mutual_user[0] != '\0') {
859                         log_errx(1, "target requested transition "
860                             "to operational negotiation, but we require "
861                             "mutual CHAP");
862                 }
863
864                 log_debugx("target requested transition "
865                     "to operational negotiation");
866                 keys_delete(response_keys);
867                 pdu_delete(response);
868                 login_negotiate(conn);
869                 return;
870         }
871
872         auth_method = keys_find(response_keys, "AuthMethod");
873         if (auth_method == NULL)
874                 log_errx(1, "received response without AuthMethod");
875         if (strcmp(auth_method, "None") == 0) {
876                 if (conn->conn_conf.isc_mutual_user[0] != '\0') {
877                         log_errx(1, "target does not require authantication, "
878                             "but we require mutual CHAP");
879                 }
880
881                 log_debugx("target does not require authentication");
882                 keys_delete(response_keys);
883                 pdu_delete(response);
884                 login_negotiate(conn);
885                 return;
886         }
887
888         if (strcmp(auth_method, "CHAP") != 0) {
889                 fail(conn, "Unsupported AuthMethod");
890                 log_errx(1, "received response "
891                     "with unsupported AuthMethod \"%s\"", auth_method);
892         }
893
894         if (conn->conn_conf.isc_user[0] == '\0' ||
895             conn->conn_conf.isc_secret[0] == '\0') {
896                 fail(conn, "Authentication required");
897                 log_errx(1, "target requests CHAP authentication, but we don't "
898                     "have user and secret");
899         }
900
901         keys_delete(response_keys);
902         response_keys = NULL;
903         pdu_delete(response);
904         response = NULL;
905
906         login_chap(conn);
907         login_negotiate(conn);
908 }