a1d9e4bca37ab291ed537a5da74b1daba66bf56b
[mirror/scst/.git] / iscsi-scst / usr / iscsid.c
1 /*
2  *  Copyright (C) 2002 - 2003 Ardis Technolgies <roman@ardistech.com>
3  *  Copyright (C) 2007 - 2009 Vladislav Bolkhovitin
4  *  Copyright (C) 2007 - 2009 ID7 Ltd.
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  as published by the Free Software Foundation, version 2
9  *  of the License.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  *  GNU General Public License for more details.
15  */
16
17 #include <ctype.h>
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <netdb.h>
26
27 #include "iscsid.h"
28
29 static u32 ttt;
30
31 static u32 get_next_ttt(struct connection *conn __attribute__((unused)))
32 {
33         ttt += 1;
34         return (ttt == ISCSI_RESERVED_TAG) ? ++ttt : ttt;
35 }
36
37 static struct iscsi_key login_keys[] = {
38         {"InitiatorName",},
39         {"InitiatorAlias",},
40         {"SessionType",},
41         {"TargetName",},
42         {NULL, 0, 0, 0, 0, NULL},
43 };
44
45 char *text_key_find(struct connection *conn, char *searchKey)
46 {
47         char *data, *key, *value;
48         int keylen, datasize;
49
50         keylen = strlen(searchKey);
51         data = conn->req.data;
52         datasize = conn->req.datasize;
53
54         while (1) {
55                 for (key = data; datasize > 0 && *data != '='; data++, datasize--)
56                         ;
57                 if (!datasize)
58                         return NULL;
59                 data++;
60                 datasize--;
61
62                 for (value = data; datasize > 0 && *data != 0; data++, datasize--)
63                         ;
64                 if (!datasize)
65                         return NULL;
66                 data++;
67                 datasize--;
68
69                 if (keylen == value - key - 1
70                      && !strncmp(key, searchKey, keylen))
71                         return value;
72         }
73 }
74
75 static char *next_key(char **data, int *datasize, char **value)
76 {
77         char *key, *p, *q;
78         int size = *datasize;
79
80         key = p = *data;
81         for (; size > 0 && *p != '='; p++, size--)
82                 ;
83         if (!size)
84                 return NULL;
85         *p++ = 0;
86         size--;
87
88         for (q = p; size > 0 && *p != 0; p++, size--)
89                 ;
90         if (!size)
91                 return NULL;
92         p++;
93         size--;
94
95         *data = p;
96         *value = q;
97         *datasize = size;
98
99         return key;
100 }
101
102 static struct buf_segment *conn_alloc_buf_segment(struct connection *conn,
103                                                    size_t sz)
104 {
105         struct buf_segment *seg = malloc(sizeof *seg + sz);
106
107         if (seg) {
108                 seg->len = 0;
109                 memset(seg->data, 0x0, sz);
110                 list_add_tail(&seg->entry, &conn->rsp_buf_list);
111                 log_debug(2, "alloc'ed new buf_segment");
112         }
113
114         return seg;
115 }
116
117 void text_key_add(struct connection *conn, char *key, char *value)
118 {
119         struct buf_segment *seg;
120         int keylen = strlen(key);
121         int valuelen = strlen(value);
122         int len = keylen + valuelen + 2;
123         int off = 0;
124         int sz = 0;
125         int stage = 0;
126         size_t data_sz;
127
128         data_sz = (conn->state == STATE_FULL) ?
129                 conn->session_param[key_max_xmit_data_length].val :
130                 INCOMING_BUFSIZE;
131
132         seg = list_empty(&conn->rsp_buf_list) ? NULL :
133                 list_entry(conn->rsp_buf_list.q_back, struct buf_segment,
134                            entry);
135
136         while (len) {
137                 if (!seg || seg->len == data_sz) {
138                         seg = conn_alloc_buf_segment(conn, data_sz);
139                         if (!seg) {
140                                 log_error("Failed to alloc text buf segment\n");
141                                 conn_free_rsp_buf_list(conn);
142                                 break;
143                         }
144                 }
145                 switch (stage) {
146                 case 0:
147                         sz = min_t(int, data_sz - seg->len, keylen - off);
148                         strncpy(seg->data + seg->len, key + off, sz);
149                         if (sz == data_sz - seg->len) {
150                                 off += sz;
151                                 if (keylen - off == 0) {
152                                         off = 0;
153                                         stage++;
154                                 }
155                         } else {
156                                 off = 0;
157                                 stage++;
158                         }
159                         break;
160                 case 1:
161                         seg->data[seg->len] = '=';
162                         off = 0;
163                         sz = 1;
164                         stage++;
165                         break;
166                 case 2:
167                         sz = min_t(int, data_sz - seg->len, valuelen - off);
168                         strncpy(seg->data + seg->len, value + off, sz);
169                         off += sz;
170                         if (valuelen - off == 0) {
171                                 off = 0;
172                                 stage++;
173                         }
174                         break;
175                 case 3:
176                         seg->data[seg->len] = 0;
177                         sz = 1;
178                         break;
179                 }
180
181                 log_debug(2, "wrote: %s", seg->data + seg->len);
182
183                 seg->len += sz;
184                 len -= sz;
185         }
186 }
187
188 static void text_key_add_reject(struct connection *conn, char *key)
189 {
190         text_key_add(conn, key, "Reject");
191 }
192
193 static int account_empty(u32 tid, int dir)
194 {
195         char pass[ISCSI_NAME_LEN];
196
197         memset(pass, 0, sizeof(pass));
198         return config_account_query(tid, dir, pass, pass) < 0 ? 1 : 0;
199 }
200
201 static void text_scan_security(struct connection *conn)
202 {
203         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
204         char *key, *value, *data, *nextValue;
205         int datasize;
206
207         data = conn->req.data;
208         datasize = conn->req.datasize;
209
210         while ((key = next_key(&data, &datasize, &value))) {
211                 if (!(param_index_by_name(key, login_keys) < 0))
212                         ;
213                 else if (!strcmp(key, "AuthMethod")) {
214                         do {
215                                 nextValue = strchr(value, ',');
216                                 if (nextValue)
217                                         *nextValue++ = 0;
218
219                                 if (!strcmp(value, "None")) {
220                                         if (!account_empty(conn->tid, AUTH_DIR_INCOMING))
221                                                 continue;
222                                         conn->auth_method = AUTH_NONE;
223                                         text_key_add(conn, key, "None");
224                                         break;
225                                 } else if (!strcmp(value, "CHAP")) {
226                                         if (account_empty(conn->tid, AUTH_DIR_INCOMING))
227                                                 continue;
228                                         conn->auth_method = AUTH_CHAP;
229                                         text_key_add(conn, key, "CHAP");
230                                         break;
231                                 }
232                         } while ((value = nextValue));
233
234                         if (conn->auth_method == AUTH_UNKNOWN)
235                                 text_key_add_reject(conn, key);
236                 } else
237                         text_key_add(conn, key, "NotUnderstood");
238         }
239         if (conn->auth_method == AUTH_UNKNOWN) {
240                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
241                 rsp->status_detail = ISCSI_STATUS_AUTH_FAILED;
242                 conn->state = STATE_EXIT;
243         }
244         return;
245 }
246
247 static int login_check_reinstatement(struct connection *conn)
248 {
249         struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
250         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
251         struct session *session;
252         int res = 0;
253
254         /*
255          * We only check here to catch errors earlier. Actual session/connection
256          * reinstatement, if necessary, will be done in the kernel.
257          */
258
259         sBUG_ON(conn->sess != NULL);
260
261         session = session_find_name(conn->tid, conn->initiator, req->sid);
262         if (session != NULL) {
263                 if (req->sid.id.tsih == 0) {
264                         /* Kernel will do session reinstatement */
265                         log_debug(1, "Session sid %#" PRIx64 " reinstatement "
266                                 "detected (tid %d, initiator %s)", req->sid.id64,
267                                 conn->tid, conn->initiator);
268                 } else if (req->sid.id.tsih != session->sid.id.tsih) {
269                         log_error("TSIH for existing session sid %#" PRIx64
270                                 ") doesn't match (tid %d, initiator %s, sid requested "
271                                 "%#" PRIx64, session->sid.id64, conn->tid,
272                                 conn->initiator, req->sid.id64);
273                         /* Fail the login */
274                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
275                         rsp->status_detail = ISCSI_STATUS_SESSION_NOT_FOUND;
276                         conn->state = STATE_EXIT;
277                         res = -1;
278                         goto out;
279                 } else {
280                         struct connection *c = conn_find(session, conn->cid);
281                         if (c != NULL) {
282                                 /* Kernel will do connection reinstatement */
283                                 log_debug(1, "Conn %x reinstatement "
284                                         "detected (tid %d, sid %#" PRIx64
285                                         "initiator %s)", conn->cid, conn->tid,
286                                         req->sid.id64, conn->initiator);
287                                 conn->sess = session;
288                                 insque(&conn->clist, &session->conn_list);
289                         } else {
290                                 log_error("Only a single connection supported "
291                                         "(initiator %s)", conn->initiator);
292                                 /* Fail the login */
293                                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
294                                 rsp->status_detail = ISCSI_STATUS_TOO_MANY_CONN;
295                                 conn->state = STATE_EXIT;
296                                 res = -1;
297                                 goto out;
298                         }
299                 }
300         } else {
301                 if (req->sid.id.tsih != 0) {
302                         log_error("Requested TSIH not 0 (TSIH %d, tid %d, "
303                                 "initiator %s, sid requisted %#" PRIx64 ")",
304                                 req->sid.id.tsih, conn->tid, conn->initiator,
305                                 req->sid.id64);
306                         /* Fail the login */
307                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
308                         rsp->status_detail = ISCSI_STATUS_SESSION_NOT_FOUND;
309                         conn->state = STATE_EXIT;
310                         res = -1;
311                         goto out;
312                 } else
313                         log_debug(1, "New session sid %#" PRIx64 "(tid %d, "
314                                 "initiator %s)", req->sid.id64,
315                                 conn->tid, conn->initiator);
316         }
317
318 out:
319         return res;
320 }
321
322 static void text_scan_login(struct connection *conn)
323 {
324         char *key, *value, *data;
325         int datasize, idx;
326         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
327
328         data = conn->req.data;
329         datasize = conn->req.datasize;
330
331         while ((key = next_key(&data, &datasize, &value))) {
332                 if (!(param_index_by_name(key, login_keys) < 0))
333                         ;
334                 else if (!strcmp(key, "AuthMethod"))
335                         ;
336                 else if (!((idx = param_index_by_name(key, session_keys)) < 0)) {
337                         unsigned int val;
338                         char buf[32];
339
340                         if (idx == key_max_xmit_data_length) {
341                                 text_key_add(conn, key, "NotUnderstood");
342                                 continue;
343                         }
344                         if (idx == key_max_recv_data_length) {
345                                 conn->session_param[idx].key_state = KEY_STATE_DONE;
346                                 idx = key_max_xmit_data_length;
347                         };
348
349                         if (param_str_to_val(session_keys, idx, value, &val) < 0) {
350                                 if (conn->session_param[idx].key_state == KEY_STATE_START) {
351                                         text_key_add_reject(conn, key);
352                                         continue;
353                                 } else {
354                                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
355                                         rsp->status_detail = ISCSI_STATUS_INIT_ERR;
356                                         conn->state = STATE_EXIT;
357                                         goto out;
358                                 }
359                         }
360
361                         param_check_val(session_keys, idx, &val);
362                         param_set_val(session_keys, conn->session_param, idx, &val);
363
364                         switch (conn->session_param[idx].key_state) {
365                         case KEY_STATE_START:
366                                 if (iscsi_is_key_internal(idx)) {
367                                         conn->session_param[idx].key_state = KEY_STATE_DONE;
368                                         break;
369                                 }
370                                 memset(buf, 0, sizeof(buf));
371                                 param_val_to_str(session_keys, idx, val, buf);
372                                 text_key_add(conn, key, buf);
373                                 conn->session_param[idx].key_state = KEY_STATE_DONE_ADDED;
374                                 break;
375                         case KEY_STATE_REQUEST:
376                                 if (val != conn->session_param[idx].val) {
377                                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
378                                         rsp->status_detail = ISCSI_STATUS_INIT_ERR;
379                                         conn->state = STATE_EXIT;
380                                         log_warning("%s %u %u\n", key,
381                                                 val, conn->session_param[idx].val);
382                                         goto out;
383                                 }
384                                 conn->session_param[idx].key_state = KEY_STATE_DONE;
385                                 break;
386                         case KEY_STATE_DONE_ADDED:
387                         case KEY_STATE_DONE:
388                                 break;
389                         }
390                 } else
391                         text_key_add(conn, key, "NotUnderstood");
392         }
393
394 out:
395         return;
396 }
397
398 static int text_check_param(struct connection *conn)
399 {
400         struct iscsi_param *p = conn->session_param;
401         char buf[32];
402         int i, cnt;
403
404         for (i = 0, cnt = 0; session_keys[i].name; i++) {
405                 if (p[i].val != session_keys[i].rfc_def) {
406                         if (p[i].key_state == KEY_STATE_START) {
407                                 log_debug(1, "Key %s was not negotiated, use RFC "
408                                         "defined default %d",  session_keys[i].name,
409                                         session_keys[i].rfc_def);
410                                 p[i].val = session_keys[i].rfc_def;
411                                 continue;
412                         } else if (p[i].key_state == KEY_STATE_DONE_ADDED) {
413                                 log_debug(1, "Key %s was already added, val %d",
414                                         session_keys[i].name, p[i].val);
415                                 continue;
416                         }
417                         switch (conn->state) {
418                         case STATE_LOGIN_FULL:
419                         case STATE_SECURITY_FULL:
420                                 if (iscsi_is_key_internal(i)) {
421                                         p[i].key_state = KEY_STATE_DONE;
422                                         continue;
423                                 }
424                                 break;
425                         case STATE_LOGIN:
426                                 if (iscsi_is_key_internal(i))
427                                         continue;
428                                 memset(buf, 0, sizeof(buf));
429                                 param_val_to_str(session_keys, i, p[i].val, buf);
430                                 text_key_add(conn, session_keys[i].name, buf);
431                                 if (i == key_max_recv_data_length) {
432                                         p[i].key_state = KEY_STATE_DONE;
433                                         continue;
434                                 }
435                                 p[i].key_state = KEY_STATE_REQUEST;
436                                 break;
437                         default:
438                                 if (iscsi_is_key_internal(i))
439                                         continue;
440                         }
441                         cnt++;
442                 }
443         }
444
445         return cnt;
446 }
447
448 static void login_start(struct connection *conn)
449 {
450         struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
451         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
452         char *name, *alias, *session_type, *target_name;
453
454         conn->cid = be16_to_cpu(req->cid);
455         conn->sid.id64 = req->sid.id64;
456
457         name = text_key_find(conn, "InitiatorName");
458         if (!name) {
459                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
460                 rsp->status_detail = ISCSI_STATUS_MISSING_FIELDS;
461                 conn->state = STATE_EXIT;
462                 return;
463         }
464
465         conn->initiator = strdup(name);
466         if (conn->initiator == NULL) {
467                 log_error("Unable to duplicate initiator's name %s", name);
468                 rsp->status_class = ISCSI_STATUS_TARGET_ERR;
469                 rsp->status_detail = ISCSI_STATUS_NO_RESOURCES;
470                 conn->state = STATE_EXIT;
471                 return;
472         }
473
474         alias = text_key_find(conn, "InitiatorAlias");
475         session_type = text_key_find(conn, "SessionType");
476         target_name = text_key_find(conn, "TargetName");
477
478         conn->auth_method = -1;
479         conn->session_type = SESSION_NORMAL;
480
481         if (session_type) {
482                 if (!strcmp(session_type, "Discovery"))
483                         conn->session_type = SESSION_DISCOVERY;
484                 else if (strcmp(session_type, "Normal")) {
485                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
486                         rsp->status_detail = ISCSI_STATUS_INV_SESSION_TYPE;
487                         conn->state = STATE_EXIT;
488                         return;
489                 }
490         }
491
492         if (conn->session_type == SESSION_NORMAL) {
493                 struct target *target;
494                 int err;
495
496                 if (!target_name) {
497                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
498                         rsp->status_detail = ISCSI_STATUS_MISSING_FIELDS;
499                         conn->state = STATE_EXIT;
500                         return;
501                 }
502
503                 target = target_find_by_name(target_name);
504                 if (target == NULL) {
505                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
506                         rsp->status_detail = ISCSI_STATUS_TGT_NOT_FOUND;
507                         conn->state = STATE_EXIT;
508                         return;
509                 }
510
511                 if (!target->tgt_enabled) {
512                         log_debug(1, "Connect from %s to disabled target %s",
513                                 name, target_name);
514                         rsp->status_class = ISCSI_STATUS_TARGET_ERR;
515                         conn->state = STATE_CLOSE;
516                         return;
517                 }
518
519                 conn->tid = target->tid;
520                 if (config_initiator_access(conn->tid, conn->fd) ||
521                     isns_scn_access(conn->tid, conn->fd, name)) {
522                         log_info("Initiator %s not allowed to connect to "
523                                 "target %s", name, target_name);
524                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
525                         rsp->status_detail = ISCSI_STATUS_TGT_NOT_FOUND;
526                         conn->state = STATE_EXIT;
527                         return;
528                 }
529
530                 err = kernel_param_get(conn->tid, conn->sid.id64, key_session,
531                         conn->session_param);
532                 if (err == -ENOENT) {
533                         err = kernel_param_get(conn->tid, 0, key_session,
534                                 conn->session_param);
535                 }
536
537                 if (err != 0) {
538                         log_error("Can't get session param for session 0x%" PRIu64 
539                                 " (err %d): %s\n", conn->sid.id64, err,
540                                 strerror(-err));
541                         rsp->status_class = ISCSI_STATUS_TARGET_ERR;
542                         rsp->status_detail = ISCSI_STATUS_TARGET_ERROR;
543                         conn->state = STATE_EXIT;
544                         return;
545                 }
546
547                 if (login_check_reinstatement(conn) != 0)
548                         return;
549         }
550
551         conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn);
552         log_debug(1, "exp_cmd_sn %u, cmd_sn %u", conn->exp_cmd_sn, req->cmd_sn);
553         text_key_add(conn, "TargetPortalGroupTag", "1");
554         return;
555 }
556
557 static int login_finish(struct connection *conn)
558 {
559         int res = 0;
560
561         switch (conn->session_type) {
562         case SESSION_NORMAL:
563                 if (!conn->sess)
564                         res = session_create(conn);
565                 if (res == 0)
566                         conn->sid = conn->sess->sid;
567                 break;
568         case SESSION_DISCOVERY:
569                 /* set a dummy tsih value */
570                 conn->sid.id.tsih = 1;
571                 break;
572         }
573
574         return res;
575 }
576
577 static void cmnd_reject(struct connection *conn, u8 reason)
578 {
579         struct iscsi_reject_hdr *rej =
580                 (struct iscsi_reject_hdr *)&conn->rsp.bhs;
581         size_t data_sz = sizeof(struct iscsi_hdr);
582         struct buf_segment *seg;
583
584         conn_free_rsp_buf_list(conn);
585         seg = conn_alloc_buf_segment(conn, data_sz);
586
587         memset(rej, 0x0, sizeof *rej);
588         rej->opcode = ISCSI_OP_REJECT_MSG;
589         rej->reason = reason;
590         rej->ffffffff = ISCSI_RESERVED_TAG;
591         rej->flags |= ISCSI_FLG_FINAL;
592
593         rej->stat_sn = cpu_to_be32(conn->stat_sn++);
594         rej->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
595         rej->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
596
597         if (!seg) {
598                 log_error("Failed to alloc data segment for Reject PDU\n");
599                 return;
600         }
601
602         memcpy(seg->data, &conn->req.bhs, data_sz);
603         seg->len = data_sz;
604 }
605
606 static int cmnd_exec_auth(struct connection *conn)
607 {
608        int res;
609
610         switch (conn->auth_method) {
611         case AUTH_CHAP:
612                 res = cmnd_exec_auth_chap(conn);
613                 break;
614         case AUTH_NONE:
615                 res = 0;
616                 break;
617         default:
618                 log_error("Unknown auth. method %d", conn->auth_method);
619                 res = -3;
620         }
621
622         return res;
623 }
624
625 static void cmnd_exec_login(struct connection *conn)
626 {
627         struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
628         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
629         int stay = 0, nsg_disagree = 0;
630
631         memset(rsp, 0, BHS_SIZE);
632         if ((req->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_LOGIN_CMD ||
633             !(req->opcode & ISCSI_OP_IMMEDIATE)) {
634                 cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
635                 return;
636         }
637
638         rsp->opcode = ISCSI_OP_LOGIN_RSP;
639         rsp->max_version = ISCSI_VERSION;
640         rsp->active_version = ISCSI_VERSION;
641         rsp->itt = req->itt;
642
643         if (/*req->max_version < ISCSI_VERSION ||*/
644             req->min_version > ISCSI_VERSION) {
645                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
646                 rsp->status_detail = ISCSI_STATUS_NO_VERSION;
647                 conn->state = STATE_EXIT;
648                 return;
649         }
650
651         switch (req->flags & ISCSI_FLG_CSG_MASK) {
652         case ISCSI_FLG_CSG_SECURITY:
653                 log_debug(1, "Login request (security negotiation): %d", conn->state);
654                 rsp->flags = ISCSI_FLG_CSG_SECURITY;
655
656                 switch (conn->state) {
657                 case STATE_FREE:
658                         conn->state = STATE_SECURITY;
659                         login_start(conn);
660                         if (rsp->status_class)
661                                 return;
662                         //else fall through
663                 case STATE_SECURITY:
664                         text_scan_security(conn);
665                         if (rsp->status_class)
666                                 return;
667                         if (conn->auth_method != AUTH_NONE) {
668                                 conn->state = STATE_SECURITY_AUTH;
669                                 conn->auth_state = AUTH_STATE_START;
670                         }
671                         break;
672                 case STATE_SECURITY_AUTH:
673                         switch (cmnd_exec_auth(conn)) {
674                         case 0:
675                                 break;
676                         default:
677                         case -1:
678                                 goto init_err;
679                         case -2:
680                                 goto auth_err;
681                         }
682                         break;
683                 default:
684                         goto init_err;
685                 }
686
687                 break;
688         case ISCSI_FLG_CSG_LOGIN:
689                 log_debug(1, "Login request (operational negotiation): %d", conn->state);
690                 rsp->flags = ISCSI_FLG_CSG_LOGIN;
691
692                 switch (conn->state) {
693                 case STATE_FREE:
694                         conn->state = STATE_LOGIN;
695
696                         login_start(conn);
697                         if (!account_empty(conn->tid, AUTH_DIR_INCOMING))
698                                 goto auth_err;
699                         if (rsp->status_class)
700                                 return;
701                         text_scan_login(conn);
702                         if (rsp->status_class)
703                                 return;
704                         stay = text_check_param(conn);
705                         break;
706                 case STATE_LOGIN:
707                         text_scan_login(conn);
708                         if (rsp->status_class)
709                                 return;
710                         stay = text_check_param(conn);
711                         break;
712                 default:
713                         goto init_err;
714                 }
715                 break;
716         default:
717                 goto init_err;
718         }
719
720         if (rsp->status_class)
721                 return;
722         if (conn->state != STATE_SECURITY_AUTH && req->flags & ISCSI_FLG_TRANSIT) {
723                 int nsg = req->flags & ISCSI_FLG_NSG_MASK;
724
725                 switch (nsg) {
726                 case ISCSI_FLG_NSG_LOGIN:
727                         switch (conn->state) {
728                         case STATE_SECURITY:
729                         case STATE_SECURITY_DONE:
730                                 conn->state = STATE_SECURITY_LOGIN;
731                                 break;
732                         default:
733                                 goto init_err;
734                         }
735                         break;
736                 case ISCSI_FLG_NSG_FULL_FEATURE:
737                         switch (conn->state) {
738                         case STATE_SECURITY:
739                         case STATE_SECURITY_DONE:
740                                 if ((nsg_disagree = text_check_param(conn))) {
741                                         conn->state = STATE_LOGIN;
742                                         nsg = ISCSI_FLG_NSG_LOGIN;
743                                         break;
744                                 }
745                                 conn->state = STATE_SECURITY_FULL;
746                                 break;
747                         case STATE_LOGIN:
748                                 if (stay)
749                                         nsg = ISCSI_FLG_NSG_LOGIN;
750                                 else
751                                         conn->state = STATE_LOGIN_FULL;
752                                 break;
753                         default:
754                                 goto init_err;
755                         }
756                         if (!stay && !nsg_disagree) {
757                                 int err;
758                                 text_check_param(conn);
759                                 err = login_finish(conn);
760                                 if (err != 0) {
761                                         log_debug(1, "login_finish() failed: %d", err);
762                                         /* Make initiator retry later */
763                                         goto tgt_no_mem;
764                                 }
765                         }
766                         break;
767                 default:
768                         goto init_err;
769                 }
770                 rsp->flags |= nsg | (stay ? 0 : ISCSI_FLG_TRANSIT);
771         }
772
773         /*
774          * TODO: support Logical Text Data Segments > INCOMING_BUFSIZE (i.e.
775          * key=value pairs spanning several PDUs) during login phase
776          */
777         if (!list_empty(&conn->rsp_buf_list) &&
778             !list_length_is_one(&conn->rsp_buf_list)) {
779                 log_error("Target error: \'key=value\' pairs spanning several "
780                           "Login PDUs are not implemented, yet\n");
781                 goto target_err;
782         }
783
784         rsp->sid = conn->sid;
785         rsp->stat_sn = cpu_to_be32(conn->stat_sn++);
786         rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
787         rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
788         return;
789
790 init_err:
791         log_error("Initiator %s error", conn->initiator);
792         rsp->flags = 0;
793         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
794         rsp->status_detail = ISCSI_STATUS_INIT_ERR;
795         conn->state = STATE_EXIT;
796         return;
797
798 auth_err:
799         log_error("Authentication of initiator %s failed", conn->initiator);
800         rsp->flags = 0;
801         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
802         rsp->status_detail = ISCSI_STATUS_AUTH_FAILED;
803         conn->state = STATE_EXIT;
804         return;
805
806 target_err:
807         rsp->flags = 0;
808         rsp->status_class = ISCSI_STATUS_TARGET_ERR;
809         rsp->status_detail = ISCSI_STATUS_TARGET_ERROR;
810         conn->state = STATE_EXIT;
811         return;
812
813 tgt_no_mem:
814         rsp->flags = 0;
815         rsp->status_class = ISCSI_STATUS_TARGET_ERR;
816         rsp->status_detail = ISCSI_STATUS_NO_RESOURCES;
817         conn->state = STATE_EXIT;
818         return;
819 }
820
821 static void text_scan_text(struct connection *conn)
822 {
823         char *key, *value, *data;
824         int datasize;
825
826         data = conn->req.data;
827         datasize = conn->req.datasize;
828
829         while ((key = next_key(&data, &datasize, &value))) {
830                 if (!strcmp(key, "SendTargets")) {
831                         struct sockaddr_storage ss;
832                         socklen_t slen, blen;
833                         char *p, *addr, buf[NI_MAXHOST + 128];
834                         int suppress_ip6 = 0;
835
836                         if (value[0] == 0)
837                                 continue;
838
839                         p = addr = buf + 1;
840                         buf[0] = '[';
841                         blen = sizeof(buf) - 1;
842
843                         slen = sizeof(ss);
844
845                         getpeername(conn->fd, (struct sockaddr *) &ss, &slen);
846                         if (ss.ss_family == AF_INET)
847                                 suppress_ip6 = 1;
848                         else {
849                                 getnameinfo((struct sockaddr *) &ss, slen, p,
850                                             blen, NULL, 0, NI_NUMERICHOST);
851
852                                 if (strstr(p, "::ffff:") == p)
853                                         suppress_ip6 = 1;       // ipv4-mapped ipv6 ?
854                         }
855
856                         getsockname(conn->fd, (struct sockaddr *) &ss, &slen);
857                         slen = sizeof(ss);
858
859                         getnameinfo((struct sockaddr *) &ss, slen, p, blen,
860                                     NULL, 0, NI_NUMERICHOST);
861
862                         if (ss.ss_family == AF_INET6 && suppress_ip6) {
863                                 if (strstr(p, "::ffff:") != p) {
864                                         log_error("%s, %s:%d.", __FILE__,
865                                                   __func__, __LINE__);
866                                         suppress_ip6 = 0;
867                                 } else
868                                         addr += 7;
869                         }
870
871                         p += strlen(p);
872
873                         if (ss.ss_family == AF_INET6 && !suppress_ip6) {
874                                 *p++ = ']';
875                                 addr = buf;
876                         }
877
878                         sprintf(p, ":%d,1", server_port);
879                         target_list_build(conn, addr,
880                                           strcmp(value, "All") ? value : NULL);
881                 } else
882                         text_key_add(conn, key, "NotUnderstood");
883         }
884 }
885
886 static void cmnd_exec_text(struct connection *conn)
887 {
888         struct iscsi_text_req_hdr *req = (struct iscsi_text_req_hdr *)&conn->req.bhs;
889         struct iscsi_text_rsp_hdr *rsp = (struct iscsi_text_rsp_hdr *)&conn->rsp.bhs;
890
891         memset(rsp, 0, BHS_SIZE);
892
893         rsp->opcode = ISCSI_OP_TEXT_RSP;
894         rsp->itt = req->itt;
895         conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn);
896         if (!(req->opcode & ISCSI_OP_IMMEDIATE))
897                 conn->exp_cmd_sn++;
898
899         log_debug(1, "Text request: %d", conn->state);
900
901         if (req->ttt == ISCSI_RESERVED_TAG) {
902                 conn_free_rsp_buf_list(conn);
903                 text_scan_text(conn);
904                 if (!list_empty(&conn->rsp_buf_list) &&
905                     !list_length_is_one(&conn->rsp_buf_list))
906                         conn->ttt = get_next_ttt(conn);
907                 else
908                         conn->ttt = ISCSI_RESERVED_TAG;
909         } else if (list_empty(&conn->rsp_buf_list) || conn->ttt != req->ttt) {
910                 log_error("Rejecting unexpected text request. TTT recv %#x, "
911                           "expected %#x; %stext segments queued\n",
912                           req->ttt, conn->ttt, list_empty(&conn->rsp_buf_list) ?
913                           "no " : "");
914                 cmnd_reject(conn, ISCSI_REASON_INVALID_PDU_FIELD);
915                 return;
916         }
917
918         if (list_length_is_one(&conn->rsp_buf_list))
919                 rsp->flags = ISCSI_FLG_FINAL;
920         rsp->ttt = conn->ttt;
921
922         rsp->stat_sn = cpu_to_be32(conn->stat_sn++);
923         rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
924         rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
925 }
926
927 static void cmnd_exec_logout(struct connection *conn)
928 {
929         struct iscsi_logout_req_hdr *req = (struct iscsi_logout_req_hdr *)&conn->req.bhs;
930         struct iscsi_logout_rsp_hdr *rsp = (struct iscsi_logout_rsp_hdr *)&conn->rsp.bhs;
931
932         memset(rsp, 0, BHS_SIZE);
933         rsp->opcode = ISCSI_OP_LOGOUT_RSP;
934         rsp->flags = ISCSI_FLG_FINAL;
935         rsp->itt = req->itt;
936         conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn);
937         if (!(req->opcode & ISCSI_OP_IMMEDIATE))
938                 conn->exp_cmd_sn++;
939
940         rsp->stat_sn = cpu_to_be32(conn->stat_sn++);
941         rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
942         rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
943 }
944
945 int cmnd_execute(struct connection *conn)
946 {
947         int res = 1;
948         struct buf_segment *seg;
949         struct iscsi_login_rsp_hdr *login_rsp;
950
951         switch (conn->req.bhs.opcode & ISCSI_OPCODE_MASK) {
952         case ISCSI_OP_LOGIN_CMD:
953                 if (conn->state == STATE_FULL) {
954                         cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
955                         break;
956                 }
957                 cmnd_exec_login(conn);
958                 login_rsp = (struct iscsi_login_rsp_hdr *) &conn->rsp.bhs;
959                 if (login_rsp->status_class)
960                         conn_free_rsp_buf_list(conn);
961                 break;
962         case ISCSI_OP_TEXT_CMD:
963                 if (conn->state != STATE_FULL)
964                         cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
965                 else
966                         cmnd_exec_text(conn);
967                 break;
968         case ISCSI_OP_LOGOUT_CMD:
969                 if (conn->state != STATE_FULL)
970                         cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
971                 else
972                         cmnd_exec_logout(conn);
973                 cmnd_exec_logout(conn);
974                 break;
975         default:
976                 cmnd_reject(conn, ISCSI_REASON_UNSUPPORTED_COMMAND);
977                 res = 0;
978                 goto out;
979         }
980
981         if (!list_empty(&conn->rsp_buf_list)) {
982                 seg = list_entry(conn->rsp_buf_list.q_forw,
983                                  struct buf_segment, entry);
984                 list_del_init(&seg->entry);
985                 conn->rsp.datasize = seg->len;
986                 conn->rsp.data = seg->data;
987         } else {
988                 conn->rsp.datasize = 0;
989                 conn->rsp.data = NULL;
990         }
991
992         conn->rsp.bhs.ahslength = conn->rsp.ahssize / 4;
993         conn->rsp.bhs.datalength[0] = conn->rsp.datasize >> 16;
994         conn->rsp.bhs.datalength[1] = conn->rsp.datasize >> 8;
995         conn->rsp.bhs.datalength[2] = conn->rsp.datasize;
996         log_pdu(2, &conn->rsp);
997
998 out:
999         return res;
1000 }
1001
1002 void cmnd_finish(struct connection *conn)
1003 {
1004         struct buf_segment *seg;
1005
1006         if (conn->rsp.data) {
1007                 seg = container_of(conn->rsp.data, struct buf_segment, data);
1008                 list_del(&seg->entry);
1009                 free(seg);
1010                 conn->rsp.data = NULL;
1011         }
1012
1013         switch (conn->state) {
1014         case STATE_EXIT:
1015                 conn->state = STATE_CLOSE;
1016                 break;
1017         case STATE_SECURITY_LOGIN:
1018                 conn->state = STATE_LOGIN;
1019                 break;
1020         case STATE_SECURITY_FULL:
1021                 //fall through
1022         case STATE_LOGIN_FULL:
1023                 if (conn->session_type == SESSION_NORMAL)
1024                         conn->state = STATE_KERNEL;
1025                 else
1026                         conn->state = STATE_FULL;
1027                 break;
1028         }
1029 }