2 * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
3 * By downloading, copying, installing or using the software you agree
4 * to this license. If you do not agree to this license, do not
5 * download, install, copy or use the software.
7 * Intel License Agreement
9 * Copyright (c) 2000, Intel Corporation
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
16 * -Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
19 * -Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the
24 * -The name of Intel Corporation may not be used to endorse or
25 * promote products derived from this software without specific prior
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
35 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
36 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 #ifdef HAVE_NETINET_IN_H
56 #include <netinet/in.h>
59 #include "iscsi-md5.h"
60 #include "iscsiutil.h"
61 #include "parameters.h"
66 param_list_add(iscsi_parameter_t
** head
, int type
, const char *key
, const char *dflt
, const char *valid
)
68 iscsi_parameter_t
*param
;
70 /* Allocated new parameter type */
73 if ((*head
= iscsi_malloc_atomic(sizeof(iscsi_parameter_t
))) == NULL
) {
74 iscsi_err(__FILE__
, __LINE__
, "out of memory\n");
79 for (param
= *head
; param
->next
!= NULL
; param
= param
->next
) {
81 if ((param
->next
= iscsi_malloc_atomic(sizeof(iscsi_parameter_t
))) == NULL
) {
82 iscsi_err(__FILE__
, __LINE__
, "out of memory\n");
88 /* Initilized parameter */
90 param
->type
= type
; /* type */
91 (void) strlcpy(param
->key
, key
, sizeof(param
->key
));/* key */
92 (void) strlcpy(param
->dflt
, dflt
, sizeof(param
->dflt
)); /* default value */
93 (void) strlcpy(param
->valid
, valid
, sizeof(param
->valid
)); /* list of valid values */
94 param
->tx_offer
= 0; /* sent offer */
95 param
->rx_offer
= 0; /* received offer */
96 param
->tx_answer
= 0; /* sent answer */
97 param
->rx_answer
= 0; /* received answer */
98 param
->reset
= 0; /* used to erase value_l on next parse */
99 param
->next
= NULL
; /* terminate list */
101 /* Allocated space for value list and set first item to default; and */
102 /* set offer and answer lists to NULL */
104 if ((param
->value_l
= iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t
))) == NULL
) {
105 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc_atomic() failed\n");
108 param
->value_l
->next
= NULL
;
109 (void) strlcpy(param
->value_l
->value
, dflt
, sizeof(param
->value_l
->value
));
114 case ISCSI_PARAM_TYPE_DECLARATIVE
:
116 case ISCSI_PARAM_TYPE_DECLARE_MULTI
:
118 case ISCSI_PARAM_TYPE_BINARY_OR
:
119 if (strcmp(valid
, "Yes,No") != 0 &&
120 strcmp(valid
, "No,Yes") != 0 &&
121 strcmp(valid
, "No") != 0 &&
122 strcmp(valid
, "Yes") != 0 &&
123 strcmp(valid
, "yes,no") != 0 &&
124 strcmp(valid
, "no,yes") != 0 &&
125 strcmp(valid
, "no") != 0 &&
126 strcmp(valid
, "yes") != 0) {
127 iscsi_err(__FILE__
, __LINE__
, "bad <valid> field \"%s\" for ISCSI_PARAM_TYPE_BINARY\n", valid
);
131 case ISCSI_PARAM_TYPE_BINARY_AND
:
132 if (strcmp(valid
, "Yes,No") != 0 &&
133 strcmp(valid
, "No,Yes") != 0 &&
134 strcmp(valid
, "No") != 0 &&
135 strcmp(valid
, "Yes") != 0 &&
136 strcmp(valid
, "yes,no") != 0 &&
137 strcmp(valid
, "no,yes") != 0 &&
138 strcmp(valid
, "no") != 0 &&
139 strcmp(valid
, "yes") != 0) {
140 iscsi_err(__FILE__
, __LINE__
, "bad <valid> field \"%s\" for ISCSI_PARAM_TYPE_BINARY\n", valid
);
144 case ISCSI_PARAM_TYPE_NUMERICAL
:
146 case ISCSI_PARAM_TYPE_NUMERICAL_Z
:
148 case ISCSI_PARAM_TYPE_LIST
:
151 iscsi_err(__FILE__
, __LINE__
, "unknown parameter type %d\n", type
);
155 iscsi_trace(TRACE_ISCSI_PARAM
, "\"%s\": valid \"%s\", default \"%s\", current \"%s\"\n",
156 param
->key
, param
->valid
, param
->dflt
, param
->value_l
->value
);
161 param_list_destroy(iscsi_parameter_t
* head
)
163 iscsi_parameter_t
*ptr
, *tmp
;
164 iscsi_parameter_value_t
*item_ptr
, *next
;
166 for (ptr
= head
; ptr
!= NULL
;) {
170 for (item_ptr
= tmp
->value_l
; item_ptr
!= NULL
; item_ptr
= next
) {
171 next
= item_ptr
->next
;
173 * iscsi_trace(TRACE_ISCSI_PARAM, "freeing \"%s\"
174 * (%p)\n", item_ptr->value, item_ptr);
176 iscsi_free_atomic(item_ptr
);
179 /* iscsi_trace(TRACE_ISCSI_PARAM, "freeing %p\n", tmp); */
180 iscsi_free_atomic(tmp
);
187 param_get(iscsi_parameter_t
* head
, const char *key
)
189 iscsi_parameter_t
*ptr
;
191 for (ptr
= head
; ptr
!= NULL
; ptr
= ptr
->next
) {
192 if (strcmp(ptr
->key
, key
) == 0) {
196 iscsi_err(__FILE__
, __LINE__
, "key \"%s\" not found in param list\n", key
);
201 param_val(iscsi_parameter_t
* head
, const char *key
)
203 return param_val_which(head
, key
, 0);
207 param_val_which(iscsi_parameter_t
* head
, const char *key
, int which
)
209 iscsi_parameter_t
*ptr
;
210 iscsi_parameter_value_t
*item_ptr
;
213 for (ptr
= head
; ptr
!= NULL
; ptr
= ptr
->next
) {
214 if (strcmp(ptr
->key
, key
) == 0) {
215 item_ptr
= ptr
->value_l
;
216 for (i
= 0; i
!= which
; i
++) {
217 if (item_ptr
== NULL
) {
218 iscsi_err(__FILE__
, __LINE__
, "item %d in value list is NULL\n", i
);
221 item_ptr
= item_ptr
->next
;
223 if (item_ptr
== NULL
) {
224 iscsi_err(__FILE__
, __LINE__
, "item %d in value list is NULL\n", which
);
227 return item_ptr
->value
;
230 iscsi_err(__FILE__
, __LINE__
, "key \"%s\" not found in param list\n", key
);
235 param_val_delete_all(iscsi_parameter_t
* head
, char *key
)
237 iscsi_parameter_t
*ptr
;
238 iscsi_parameter_value_t
*item_ptr
, *next
;
240 for (ptr
= head
; ptr
!= NULL
; ptr
= ptr
->next
) {
241 if (strcmp(ptr
->key
, key
) == 0) {
242 for (item_ptr
= ptr
->value_l
; item_ptr
!= NULL
; item_ptr
= next
) {
243 next
= item_ptr
->next
;
244 iscsi_free_atomic(item_ptr
);
250 iscsi_err(__FILE__
, __LINE__
, "key \"%s\" not found in param list\n", key
);
255 param_val_reset(iscsi_parameter_t
* head
, const char *key
)
257 iscsi_parameter_t
*ptr
;
259 for (ptr
= head
; ptr
!= NULL
; ptr
= ptr
->next
) {
260 if (strcmp(ptr
->key
, key
) == 0) {
265 iscsi_err(__FILE__
, __LINE__
, "key \"%s\" not found in param list\n", key
);
270 param_atoi(iscsi_parameter_t
* head
, const char *key
)
272 iscsi_parameter_t
*ptr
;
275 for (ptr
= head
; ptr
!= NULL
; ptr
= ptr
->next
) {
276 if (strcmp(ptr
->key
, key
) == 0) {
278 if ((value
= param_val(head
, key
)) != NULL
) {
279 return iscsi_atoi(value
);
281 iscsi_err(__FILE__
, __LINE__
, "value is NULL\n");
285 iscsi_err(__FILE__
, __LINE__
, "param \"%s\" has NULL value list\n", key
);
290 iscsi_err(__FILE__
, __LINE__
, "key \"%s\" not found in param list\n", key
);
295 param_equiv(iscsi_parameter_t
* head
, const char *key
, const char *val
)
297 iscsi_parameter_t
*ptr
;
300 for (ptr
= head
; ptr
!= NULL
; ptr
= ptr
->next
) {
301 if (strcmp(ptr
->key
, key
) == 0) {
302 if (ptr
->value_l
== NULL
) {
303 iscsi_err(__FILE__
, __LINE__
, "param \"%s\" has NULL value list\n", key
);
306 if ((value
= param_val(head
, key
)) == NULL
) {
307 iscsi_err(__FILE__
, __LINE__
, "key \"%s\" value is NULL\n", key
);
310 return (strcmp(value
, val
) == 0);
313 iscsi_err(__FILE__
, __LINE__
, "key \"%s\" not found in param list\n", key
);
318 param_num_vals(iscsi_parameter_t
* head
, char *key
)
320 iscsi_parameter_t
*ptr
;
321 iscsi_parameter_value_t
*item_ptr
;
324 for (ptr
= head
; ptr
!= NULL
; ptr
= ptr
->next
) {
325 if (strcmp(ptr
->key
, key
) == 0) {
326 for (item_ptr
= ptr
->value_l
; item_ptr
!= NULL
; item_ptr
= item_ptr
->next
) {
332 iscsi_err(__FILE__
, __LINE__
, "key \"%s\" not found in param list\n", key
);
337 param_list_print(iscsi_parameter_t
* head
)
339 iscsi_parameter_t
*ptr
;
340 iscsi_parameter_value_t
*item_ptr
;
342 for (ptr
= head
; ptr
!= NULL
; ptr
= ptr
->next
) {
343 for (item_ptr
= ptr
->value_l
; item_ptr
!= NULL
; item_ptr
= item_ptr
->next
) {
344 printf("\"%s\"=\"%s\"\n", ptr
->key
, item_ptr
->value
);
351 param_text_print(char *text
, uint32_t text_len
)
354 char *ptr
, *eq
, *value
;
356 for (ptr
= text
; (uint32_t)(ptr
- text
) < text_len
; ptr
+= (strlen(ptr
) + 1)) {
358 /* Skip over any NULLs */
360 while (!(*ptr
) && ((uint32_t)(ptr
- text
) < text_len
))
362 if ((uint32_t)(ptr
- text
) >= text_len
)
365 if ((eq
= strchr(ptr
, '=')) == NULL
) {
366 iscsi_err(__FILE__
, __LINE__
, "delimiter \'=\' not found in token \"%s\"\n", ptr
);
369 strncpy(key
, ptr
, (unsigned)(eq
- ptr
));
370 key
[(int)(eq
- ptr
)] = 0x0;
372 printf("\"%s\"=\"%s\"\n", key
, value
);
379 param_text_add(iscsi_parameter_t
* head
, const char *key
, const char *value
, char *text
, int *len
, int size
, int offer
)
383 cc
= snprintf(text
+ *len
, (unsigned)(size
- *len
), "%s=%s", key
, value
);
389 driver_atoi(const char *s
)
393 while (*s
!= 0x0 && *s
>= '0' && *s
<= '9') {
394 k
= 10 * k
+ (*s
- '0');
400 /* find the credentials for `user' and put them in `cred' */
402 find_credentials(iscsi_cred_t
*cred
, char *user
, const char *auth
)
405 const char *authtype
;
409 (void) memset(&conf
, 0x0, sizeof(conf
));
410 (void) memset(&e
, 0x0, sizeof(e
));
412 if (!conffile_open(&conf
, _PATH_ISCSI_PASSWD
, "r", ":", "#")) {
413 iscsi_err(__FILE__
, __LINE__
, "can't open `%s'\n", _PATH_ISCSI_PASSWD
);
416 while (conffile_getent(&conf
, &e
)) {
417 if (strcasecmp(e
.sv
.v
[0], user
) == 0) {
418 authtype
= (e
.sv
.c
== 1) ? "none" : e
.sv
.v
[1];
419 cc
= strlen(authtype
);
420 if (auth
== NULL
|| (strncasecmp(authtype
, auth
, cc
) == 0 && cc
== strlen(auth
))) {
421 cred
->user
= strdup(e
.sv
.v
[0]);
422 cred
->auth_type
= strdup(authtype
);
423 cred
->shared_secret
= (e
.sv
.c
== 3) ? strdup(e
.sv
.v
[2]) : NULL
;
424 conffile_close(&conf
);
429 conffile_close(&conf
);
430 (void) fprintf(stderr
, "No matching user configuration entry for `%s' was found\n", user
);
431 (void) fprintf(stderr
, "Please add an entry for `%s' to `%s'\n", user
, _PATH_ISCSI_PASSWD
);
436 /* free any storage allocated in `cred' */
438 free_cred(iscsi_cred_t
*cred
)
442 iscsi_free_atomic(cred
->user
);
444 if (cred
->auth_type
) {
445 iscsi_free_atomic(cred
->auth_type
);
447 if (cred
->shared_secret
) {
448 iscsi_free_atomic(cred
->shared_secret
);
454 /* Security offering and check */
456 * ret values: =0: succeed or no security >0: security negotiation in process
460 param_parse_security(iscsi_parameter_t
* head
,
461 iscsi_parameter_t
* param_in
,
463 char *text_out
, int *text_len_out
, int textsize
)
466 static uint8_t idData
;
467 static uint8_t chapdata
[ISCSI_CHAP_DATA_LENGTH
];
468 static uint8_t respdata
[ISCSI_CHAP_DATA_LENGTH
];
469 char *chapstring
= NULL
;
470 iSCSI_MD5_CTX
*context
= NULL
;
471 iscsi_parameter_t
*param
= NULL
;
474 if ((chapstring
= iscsi_malloc(ISCSI_CHAP_STRING_LENGTH
)) == NULL
) {
475 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc() failed\n");
478 if ((context
= iscsi_malloc(sizeof(*context
))) == NULL
) {
479 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc() failed\n");
480 if (chapstring
!= NULL
)
481 iscsi_free(chapstring
);
484 #define PPS_CLEANUP { if (chapstring != NULL) iscsi_free(chapstring);if (context != NULL) iscsi_free(context); }
485 #define PPS_ERROR { PPS_CLEANUP; return (-1); };
487 if (strcmp(param_in
->key
, "AuthMethod") == 0) {
488 if (param_in
->rx_answer
&& strcmp(param_in
->answer_rx
, "None") == 0) {
490 return 0; /* Proposed None for
493 if (param_in
->rx_offer
&& strcmp(param_in
->offer_rx
, "None") == 0) {
497 if (!param_in
->rx_offer
) {
498 param
= param_get(head
, "CHAP_A");
501 param
->tx_offer
= 1; /* sending an offer */
502 param
->rx_offer
= 0; /* reset */
503 (void) strlcpy(param
->offer_tx
, param
->valid
, sizeof(param
->offer_tx
));
504 PARAM_TEXT_ADD(head
, param
->key
, param
->valid
,
505 text_out
, text_len_out
, textsize
, 0, PPS_ERROR
);
508 } else if (strcmp(param_in
->key
, "CHAP_A") == 0) {
509 if (param_in
->rx_offer
) {
510 PARAM_TEXT_ADD(head
, param_in
->key
, param_in
->offer_rx
,
511 text_out
, text_len_out
, textsize
, 0, PPS_ERROR
);
513 if ((param
= param_get(head
, "CHAP_I")) == NULL
) {
516 param
->tx_offer
= 1; /* sending an offer */
517 param
->rx_offer
= 0; /* reset */
518 GenRandomData(&idData
, 1);
519 (void) snprintf(chapstring
, ISCSI_CHAP_STRING_LENGTH
, "%d", idData
);
520 (void) strlcpy(param
->offer_tx
, chapstring
, sizeof(param
->offer_tx
));
521 PARAM_TEXT_ADD(head
, param
->key
, param
->offer_tx
,
522 text_out
, text_len_out
, textsize
, 0, PPS_ERROR
);
524 if ((param
= param_get(head
, "CHAP_C")) == NULL
) {
527 param
->tx_offer
= 1; /* sending an offer */
528 param
->rx_offer
= 0; /* reset */
529 GenRandomData(chapdata
, ISCSI_CHAP_DATA_LENGTH
);
530 HexDataToText(chapdata
, ISCSI_CHAP_DATA_LENGTH
,
531 chapstring
, ISCSI_CHAP_STRING_LENGTH
);
532 (void) strlcpy(param
->offer_tx
, chapstring
, sizeof(param
->offer_tx
));
533 PARAM_TEXT_ADD(head
, param
->key
, param
->offer_tx
,
534 text_out
, text_len_out
, textsize
, 0, PPS_ERROR
);
537 } else if (strcmp(param_in
->key
, "CHAP_I") == 0) {
539 idData
= driver_atoi((param_in
->rx_offer
) ? param_in
->offer_rx
: param_in
->answer_rx
);
542 } else if (strcmp(param_in
->key
, "CHAP_C") == 0) {
544 HexTextToData((param_in
->rx_offer
) ? param_in
->offer_rx
: param_in
->answer_rx
, ISCSI_CHAP_STRING_LENGTH
,
545 chapdata
, ISCSI_CHAP_DATA_LENGTH
);
547 if ((param
= param_get(head
, "CHAP_N")) == NULL
) {
550 param
->tx_offer
= 1; /* sending an offer */
551 param
->rx_offer
= 0; /* reset */
553 if (cred
->shared_secret
== NULL
&& !find_credentials(cred
, cred
->user
, "chap")) {
554 iscsi_err(__FILE__
, __LINE__
, "Unknown user `%s'\n", param_in
->offer_rx
);
559 (void) strlcpy(param
->offer_tx
, cred
->user
, sizeof(param
->offer_tx
));
561 iscsi_err(__FILE__
, __LINE__
, "no valid user credentials\n");
565 PARAM_TEXT_ADD(head
, param
->key
, param
->offer_tx
,
566 text_out
, text_len_out
, textsize
, 0, PPS_ERROR
);
568 if ((param
= param_get(head
, "CHAP_R")) == NULL
) {
571 param
->tx_offer
= 1; /* sending an offer */
572 param
->rx_offer
= 0; /* reset */
573 iSCSI_MD5Init(context
);
574 iSCSI_MD5Update(context
, &idData
, 1);
576 if (cred
->shared_secret
== NULL
) {
577 iscsi_err(__FILE__
, __LINE__
, "null shared secret\n");
580 iSCSI_MD5Update(context
, (const uint8_t *)cred
->shared_secret
, strlen(cred
->shared_secret
));
583 HexDataToText(chapdata
, ISCSI_CHAP_DATA_LENGTH
,
584 param
->offer_tx
, ISCSI_CHAP_STRING_LENGTH
);
585 iSCSI_MD5Update(context
, chapdata
, ISCSI_CHAP_DATA_LENGTH
);
586 iSCSI_MD5Final(chapdata
, context
);
587 HexDataToText(chapdata
, ISCSI_CHAP_DATA_LENGTH
,
588 param
->offer_tx
, ISCSI_CHAP_STRING_LENGTH
);
590 PARAM_TEXT_ADD(head
, param
->key
, param
->offer_tx
,
591 text_out
, text_len_out
, textsize
, 0, PPS_ERROR
);
593 if (param_in
->rx_offer
) {
595 if ((param
= param_get(head
, "CHAP_I")) == NULL
) {
598 param
->tx_offer
= 1; /* sending an offer */
599 param
->rx_offer
= 0; /* reset */
600 GenRandomData(&idData
, 1);
601 (void) snprintf(chapstring
, ISCSI_CHAP_STRING_LENGTH
, "%d", idData
);
602 (void) strlcpy(param
->offer_tx
, chapstring
, sizeof(param
->offer_tx
));
603 PARAM_TEXT_ADD(head
, param
->key
, param
->offer_tx
,
604 text_out
, text_len_out
, textsize
, 0, PPS_ERROR
);
606 if ((param
= param_get(head
, "CHAP_C")) == NULL
) {
609 param
->tx_offer
= 1; /* sending an offer */
610 param
->rx_offer
= 0; /* reset */
611 GenRandomData(chapdata
, ISCSI_CHAP_DATA_LENGTH
);
612 HexDataToText(chapdata
, ISCSI_CHAP_DATA_LENGTH
,
613 chapstring
, ISCSI_CHAP_STRING_LENGTH
);
614 (void) strlcpy(param
->offer_tx
, chapstring
, sizeof(param
->offer_tx
));
615 PARAM_TEXT_ADD(head
, param
->key
, param
->offer_tx
,
616 text_out
, text_len_out
, textsize
, 0, PPS_ERROR
);
620 } else if (strcmp(param_in
->key
, "CHAP_N") == 0) {
623 user
= (param_in
->rx_offer
) ? param_in
->offer_rx
: param_in
->answer_rx
;
624 if (!find_credentials(cred
, user
, "chap")) {
625 iscsi_err(__FILE__
, __LINE__
, "Unknown user `%s'\n", user
);
630 } else if (strcmp(param_in
->key
, "CHAP_R") == 0) {
632 iSCSI_MD5Init(context
);
634 iSCSI_MD5Update(context
, &idData
, 1);
636 HexDataToText(&idData
, 1, param_in
->offer_tx
, ISCSI_CHAP_STRING_LENGTH
);
637 HexDataToText(chapdata
, ISCSI_CHAP_DATA_LENGTH
,
638 chapstring
, ISCSI_CHAP_STRING_LENGTH
);
640 if (cred
->shared_secret
== NULL
) {
641 iscsi_err(__FILE__
, __LINE__
, "Null shared secret in initiator\n");
644 iSCSI_MD5Update(context
, (const uint8_t *)cred
->shared_secret
, strlen(cred
->shared_secret
));
647 iSCSI_MD5Update(context
, chapdata
, ISCSI_CHAP_DATA_LENGTH
);
648 iSCSI_MD5Final(chapdata
, context
);
650 HexTextToData((param_in
->rx_offer
) ? param_in
->offer_rx
: param_in
->answer_rx
, ISCSI_CHAP_STRING_LENGTH
,
651 respdata
, ISCSI_CHAP_DATA_LENGTH
);
653 HexDataToText(chapdata
, ISCSI_CHAP_DATA_LENGTH
,
654 param_in
->offer_rx
, ISCSI_CHAP_STRING_LENGTH
);
656 if (memcmp(respdata
, chapdata
, ISCSI_CHAP_DATA_LENGTH
) != 0) {
657 iscsi_err(__FILE__
, __LINE__
, "Initiator authentication failed %x %x\n", *chapdata
, *respdata
);
669 param_text_parse(iscsi_parameter_t
* head
,
671 char *text_in
, int text_len_in
,
672 char *text_out
, int *text_len_out
,
676 static char *key
= NULL
;
679 iscsi_parameter_t
*param
;
680 iscsi_parameter_value_t
*item_ptr
;
681 int offer_i
, answer_i
, max_i
, val1_i
, val2_i
, negotiated_i
;
682 char *p1
, *p2
, *p3
, *p4
;
687 char *tmp_key
= NULL
;
692 * Whether incoming or outgoing, some of the params might be offers
693 * and some answers. Incoming
696 * text has the potential for creating outgoing text - and this will
697 * happen when the incoming
699 /* text has offers that need an answer. */
701 iscsi_trace(TRACE_ISCSI_PARAM
, "parsing %d %s bytes of text parameters\n", text_len_in
, outgoing
? "outgoing" : "incoming");
703 if ((key
= iscsi_malloc(ISCSI_PARAM_KEY_LEN
)) == NULL
) {
704 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc() failed\n");
707 if ((offer
= iscsi_malloc(ISCSI_PARAM_MAX_LEN
)) == NULL
) {
708 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc() failed\n");
714 if ((valid
= iscsi_malloc(ISCSI_PARAM_MAX_LEN
)) == NULL
) {
715 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc() failed\n");
724 if ((val1
= iscsi_malloc(ISCSI_PARAM_MAX_LEN
)) == NULL
) {
725 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc() failed\n");
737 if ((val2
= iscsi_malloc(ISCSI_PARAM_MAX_LEN
)) == NULL
) {
738 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc() failed\n");
753 #define PTP_CLEANUP { if (key != NULL) iscsi_free(key); \
754 if (offer != NULL) iscsi_free(offer); \
755 if (valid != NULL) iscsi_free(valid); \
756 if (val1 != NULL) iscsi_free(val1); \
757 if (val2 != NULL) iscsi_free(val2); \
758 if (tmp_key != NULL) iscsi_free(tmp_key); }
759 #define PTP_ERROR {PTP_CLEANUP; return -1;}
766 printf("**************************************************\n");
767 printf("* PARAMETERS NEGOTIATED *\n");
771 for (ptr
= text_in
; ptr
- text_in
< text_len_in
; ptr
+= (strlen(ptr
) + 1)) {
773 /* Skip over any NULLs */
775 while (!(*ptr
) && ((ptr
- text_in
) < text_len_in
)) {
778 if ((ptr
- text_in
) >= text_len_in
) {
782 /* Extract <key>=<value> token from text_in */
784 if ((eq
= strchr(ptr
, '=')) == NULL
) {
785 iscsi_err(__FILE__
, __LINE__
, "delimiter \'=\' not found in token \"%s\"\n", ptr
);
787 if ((int)(eq
- ptr
) >= (ISCSI_PARAM_KEY_LEN
- 1)) {
789 tmp_key
= iscsi_malloc((unsigned)(eq
- ptr
));
791 strncpy(tmp_key
, ptr
, (unsigned)(eq
- ptr
));
792 tmp_key
[(int)(eq
- ptr
)] = 0x0;
793 /* Key not understood. */
794 PARAM_TEXT_ADD(head
, tmp_key
, "NotUnderstood", text_out
, text_len_out
, textsize
, 0, PTP_ERROR
);
797 printf("ignoring \"%s\"\n", key
);
801 strncpy(key
, ptr
, (unsigned)(eq
- ptr
));
802 key
[(int)(eq
- ptr
)] = 0x0;
806 /* Find key in param list */
808 for (param
= head
; param
!= NULL
; param
= param
->next
) {
809 if (strcmp(param
->key
, key
) == 0) {
815 /* Key not understood. */
816 PARAM_TEXT_ADD(head
, key
, "NotUnderstood", text_out
, text_len_out
, textsize
, 0, PTP_ERROR
);
818 printf("ignoring \"%s\"\n", key
);
822 if (strlen(value
) > ISCSI_PARAM_MAX_LEN
) {
823 iscsi_err(__FILE__
, __LINE__
,
824 "strlen(value) %u\n", strlen(value
));
829 /* We're sending|receiving an offer|answer */
831 if (param
->rx_offer
) {
832 param
->tx_answer
= 1; /* sending an answer */
833 param
->rx_answer
= 0; /* reset */
834 param
->tx_offer
= 0; /* reset */
835 param
->rx_offer
= 0; /* reset */
836 (void) strlcpy(param
->answer_tx
, value
, sizeof(param
->answer_tx
));
837 iscsi_trace(TRACE_ISCSI_PARAM
, "sending answer \"%s\"=\"%s\" for offer \"%s\"\n",
838 param
->key
, param
->answer_tx
, param
->offer_rx
);
841 param
->tx_offer
= 1; /* sending an offer */
842 param
->tx_answer
= 0;
843 param
->rx_answer
= 0;
844 (void) strlcpy(param
->offer_tx
, value
, sizeof(param
->offer_tx
));
845 iscsi_trace(TRACE_ISCSI_PARAM
, "sending offer \"%s\"=\"%s\"\n", param
->key
, param
->offer_tx
);
846 if ((param
->type
== ISCSI_PARAM_TYPE_DECLARATIVE
) ||
847 (param
->type
== ISCSI_PARAM_TYPE_DECLARE_MULTI
)) {
853 if (param
->tx_offer
) {
854 param
->rx_answer
= 1; /* received an answer */
855 param
->tx_answer
= 0;
857 param
->tx_offer
= 0; /* reset */
858 (void) strlcpy(param
->answer_rx
, value
, sizeof(param
->answer_rx
));
859 iscsi_trace(TRACE_ISCSI_PARAM
, "received answer \"%s\"=\"%s\" for offer \"%s\"\n",
860 param
->key
, param
->answer_rx
, param
->offer_tx
);
862 if ((ret
= param_parse_security(head
, param
, cred
,
863 text_out
, text_len_out
, textsize
)) > 1) {
865 } else if (ret
== 0) {
867 * FIX ME Happens in initiator code
868 * currently we ignore initiator
869 * authentication status See comments
870 * at the beginning of parse_security
873 } else if (ret
== 1) {
878 return ISCSI_PARAM_STATUS_AUTH_FAILED
;
880 param
->rx_offer
= 1; /* received an offer */
881 param
->rx_answer
= 0;
882 param
->tx_answer
= 0;
883 (void) strlcpy(param
->offer_rx
, value
, sizeof(param
->offer_rx
));
884 iscsi_trace(TRACE_ISCSI_PARAM
, "received offer \"%s\"=\"%s\"\n", param
->key
, param
->offer_rx
);
886 if ((ret
= param_parse_security(head
, param
, cred
,
887 text_out
, text_len_out
, textsize
)) > 1) {
889 } else if (ret
< 0) {
890 iscsi_parameter_t
*auth_result
;
891 if ((auth_result
= param_get(head
, "AuthResult")) != 0) {
892 (void) strlcpy(auth_result
->value_l
->value
, "Fail", sizeof(auth_result
->value_l
->value
));
895 return (ISCSI_PARAM_STATUS_AUTH_FAILED
);
896 } else if (ret
== 0) {
897 iscsi_parameter_t
*auth_result
;
898 if ((auth_result
= param_get(head
, "AuthResult")) != 0) {
899 (void) strlcpy(auth_result
->value_l
->value
, "Yes", sizeof(auth_result
->value_l
->value
));
903 * Answer the offer if it is an inquiry or
904 * the type is not DECLARATIVE
907 if ((strcmp(param
->offer_rx
, "?") != 0) && ((param
->type
== ISCSI_PARAM_TYPE_DECLARATIVE
) || (param
->type
== ISCSI_PARAM_TYPE_DECLARE_MULTI
))) {
917 /* Answer with current value if this is an inquiry (<key>=?) */
919 if (strcmp(value
, "?") == 0) {
920 iscsi_trace(TRACE_ISCSI_PARAM
, "got inquiry for param \"%s\"\n", param
->key
);
921 if (param
->value_l
) {
922 if (param
->value_l
->value
) {
923 (void) strlcpy(param
->answer_tx
, param
->value_l
->value
, sizeof(param
->answer_tx
));
925 iscsi_err(__FILE__
, __LINE__
, "param \"%s\" has NULL value_l->value\n", param
->key
);
926 param
->answer_tx
[0] = 0x0;
929 iscsi_err(__FILE__
, __LINE__
, "param \"%s\" has NULL value_l\n", param
->key
);
930 param
->answer_tx
[0] = 0x0;
934 /* Generate answer according to the parameter type */
936 switch (param
->type
) {
938 case ISCSI_PARAM_TYPE_BINARY_AND
:
941 case ISCSI_PARAM_TYPE_BINARY_OR
:
943 if (strcmp(value
, "yes") != 0 &&
944 strcmp(value
, "no") != 0 &&
945 strcmp(value
, "Yes") != 0 &&
946 strcmp(value
, "No") != 0) {
947 iscsi_err(__FILE__
, __LINE__
, "\"%s\" is not a valid binary value\n", value
);
948 (void) strlcpy(param
->answer_tx
, "Reject", sizeof(param
->answer_tx
));
951 if (strchr(param
->valid
, ',') != NULL
) {
952 (void) strlcpy(param
->answer_tx
, value
, sizeof(param
->answer_tx
)); /* we accept both yes
953 * and no, so answer w/
956 (void) strlcpy(param
->answer_tx
, param
->valid
, sizeof(param
->answer_tx
)); /* answer with the only
957 * value we support */
961 case ISCSI_PARAM_TYPE_LIST
:
964 * Use our default value if it's offered as one of the option
965 * in the parameter list.
967 * We need to do this at least for CHAP because cisco's initiator
968 * could be sending us a parameter value list with "CHAP,None",
969 * even when it doesn't set username/password in its configration
970 * file, in which case we should pick "None" as for no security instead
971 * of pick the first one on the value list. "None" is the default value
974 * This fix is working well now, though is arguable. We should keep
975 * this just to make us work with Cisco for now.
977 if (strlen(param
->dflt
)) {
978 for (p1
= p2
= param
->offer_rx
; p2
; p1
= p2
+ 1) {
980 if ((p2
= strchr(p1
, ',')) != NULL
) {
981 strncpy(offer
, p1
, (unsigned)(p2
- p1
));
982 offer
[(int)(p2
- p1
)] = 0x0;
984 (void) strlcpy(offer
, p1
, ISCSI_PARAM_MAX_LEN
);
987 if (strcmp(param
->dflt
, offer
) == 0) {
988 (void) strlcpy(param
->answer_tx
, offer
, sizeof(param
->answer_tx
));
993 /* Find the first valid offer that we support */
995 for (p1
= p2
= param
->offer_rx
; p2
; p1
= p2
+ 1) {
996 if ((p2
= strchr(p1
, ',')) != NULL
) {
997 strncpy(offer
, p1
, (unsigned)(p2
- p1
));
998 offer
[p2
- p1
] = 0x0;
1000 (void) strlcpy(offer
, p1
, ISCSI_PARAM_MAX_LEN
);
1002 if (strlen(param
->valid
)) {
1003 for (p3
= p4
= param
->valid
; p4
; p3
= p4
+ 1) {
1004 if ((p4
= strchr(p3
, ',')) != NULL
) {
1005 strncpy(valid
, p3
, (unsigned)(p4
- p3
));
1006 valid
[(int)(p4
- p3
)] = 0x0;
1008 (void) strlcpy(valid
, p3
, ISCSI_PARAM_MAX_LEN
);
1010 if (strcmp(valid
, offer
) == 0) {
1011 (void) strlcpy(param
->answer_tx
, offer
, sizeof(param
->answer_tx
));
1016 iscsi_trace(TRACE_ISCSI_PARAM
, "Valid list empty. Answering with first in offer list\n");
1017 (void) strlcpy(param
->answer_tx
, offer
, sizeof(param
->answer_tx
));
1020 iscsi_trace(TRACE_ISCSI_PARAM
, "\"%s\" is not a valid offer for key \"%s\" (must choose from \"%s\")\n", offer
, param
->key
, param
->valid
);
1022 iscsi_trace(TRACE_ISCSI_PARAM
, "No Valid offers: \"%s\" is added as value for key \"%s\")\n", "Reject", param
->key
);
1023 (void) strlcpy(param
->answer_tx
, "Reject", sizeof(param
->answer_tx
));
1026 case ISCSI_PARAM_TYPE_NUMERICAL_Z
:
1029 case ISCSI_PARAM_TYPE_NUMERICAL
:
1031 offer_i
= iscsi_atoi(param
->offer_rx
);
1032 max_i
= iscsi_atoi(param
->valid
);
1033 if (param
->type
== ISCSI_PARAM_TYPE_NUMERICAL_Z
) {
1035 answer_i
= offer_i
; /* we support anything,
1036 * so return whatever
1038 } else if (offer_i
== 0) {
1039 answer_i
= max_i
; /* return only what we
1041 } else if (offer_i
> max_i
) {
1042 answer_i
= max_i
; /* we are the lower of
1045 answer_i
= offer_i
; /* they are the lower of
1049 if (offer_i
> max_i
) {
1050 answer_i
= max_i
; /* we are the lower of
1053 answer_i
= offer_i
; /* they are the lower of
1057 (void) snprintf(param
->answer_tx
, sizeof(param
->answer_tx
), "%d", answer_i
);
1063 add_answer
: PARAM_TEXT_ADD(head
, key
, param
->answer_tx
, text_out
, text_len_out
, textsize
, 0, PTP_ERROR
);
1064 iscsi_trace(TRACE_ISCSI_PARAM
, "answering \"%s\"=\"%s\"\n", param
->key
, param
->answer_tx
);
1068 /* Negotiate after receiving|sending an answer */
1071 switch (param
->type
) {
1072 case ISCSI_PARAM_TYPE_DECLARE_MULTI
:
1073 goto declarative_negotiate
;
1074 case ISCSI_PARAM_TYPE_DECLARATIVE
:
1075 declarative_negotiate
:
1076 if (param
->tx_answer
) {
1077 (void) strlcpy(param
->negotiated
, param
->answer_tx
, sizeof(param
->negotiated
));
1078 } else if (param
->tx_offer
) {
1079 (void) strlcpy(param
->negotiated
, param
->offer_tx
, sizeof(param
->negotiated
));
1080 } else if (param
->rx_answer
) {
1081 (void) strlcpy(param
->negotiated
, param
->answer_rx
, sizeof(param
->negotiated
));
1082 } else if (param
->rx_offer
) {
1083 (void) strlcpy(param
->negotiated
, param
->offer_rx
, sizeof(param
->negotiated
));
1085 iscsi_err(__FILE__
, __LINE__
, "Invalid negotiation!?!?\n");
1088 case ISCSI_PARAM_TYPE_BINARY_AND
:
1089 goto binary_or_negotiate
;
1090 case ISCSI_PARAM_TYPE_BINARY_OR
:
1091 binary_or_negotiate
:
1093 (void) strlcpy(val1
, param
->offer_rx
, ISCSI_PARAM_MAX_LEN
);
1094 (void) strlcpy(val2
, param
->answer_tx
, ISCSI_PARAM_MAX_LEN
);
1096 (void) strlcpy(val1
, param
->answer_rx
, ISCSI_PARAM_MAX_LEN
);
1097 (void) strlcpy(val2
, param
->offer_tx
, ISCSI_PARAM_MAX_LEN
);
1098 /* Make sure the answer is valid */
1099 if (strcmp(val1
, "Yes") != 0 &&
1100 strcmp(val1
, "No") != 0 &&
1101 strcmp(val1
, "yes") != 0 &&
1102 strcmp(val1
, "no") != 0 &&
1103 strcmp(val1
, "Irrelevant") != 0) {
1104 /* Invalid value returned as answer. */
1105 iscsi_err(__FILE__
, __LINE__
, "Invalid answer (%s) for key (%s)\n",
1110 if (param
->type
== ISCSI_PARAM_TYPE_BINARY_OR
) {
1111 if (strcmp(val1
, "yes") == 0 || strcmp(val2
, "yes") == 0 || strcmp(val1
, "Yes") == 0 || strcmp(val2
, "Yes") == 0) {
1112 (void) strlcpy(param
->negotiated
, "Yes", sizeof(param
->negotiated
));
1114 (void) strlcpy(param
->negotiated
, "No", sizeof(param
->negotiated
));
1117 if ((strcmp(val1
, "yes") == 0 && strcmp(val2
, "yes") == 0) || (strcmp(val1
, "Yes") == 0 && strcmp(val2
, "Yes") == 0)) {
1118 (void) strlcpy(param
->negotiated
, "Yes", sizeof(param
->negotiated
));
1120 (void) strlcpy(param
->negotiated
, "No", sizeof(param
->negotiated
));
1124 case ISCSI_PARAM_TYPE_NUMERICAL_Z
:
1125 goto numerical_negotiate
;
1126 case ISCSI_PARAM_TYPE_NUMERICAL
:
1127 numerical_negotiate
:
1129 (void) strlcpy(val1
, param
->offer_rx
, ISCSI_PARAM_MAX_LEN
);
1130 (void) strlcpy(val2
, param
->answer_tx
, ISCSI_PARAM_MAX_LEN
);
1132 (void) strlcpy(val1
, param
->answer_rx
, ISCSI_PARAM_MAX_LEN
);
1133 (void) strlcpy(val2
, param
->offer_tx
, ISCSI_PARAM_MAX_LEN
);
1135 val1_i
= iscsi_atoi(val1
);
1136 val2_i
= iscsi_atoi(val2
);
1137 if (param
->type
== ISCSI_PARAM_TYPE_NUMERICAL_Z
) {
1139 negotiated_i
= val2_i
;
1140 } else if (val2_i
== 0) {
1141 negotiated_i
= val1_i
;
1142 } else if (val1_i
> val2_i
) {
1143 negotiated_i
= val2_i
;
1145 negotiated_i
= val1_i
;
1148 if (val1_i
> val2_i
) {
1149 negotiated_i
= val2_i
;
1151 negotiated_i
= val1_i
;
1154 (void) snprintf(param
->negotiated
, sizeof(param
->negotiated
), "%d", negotiated_i
);
1156 case ISCSI_PARAM_TYPE_LIST
:
1158 if (param
->tx_offer
) {
1159 iscsi_err(__FILE__
, __LINE__
, "we should not be here\n"); /* error - we're sending
1162 } else if (param
->tx_answer
) {
1163 (void) strlcpy(val1
, param
->answer_tx
, ISCSI_PARAM_MAX_LEN
); /* we're sending an
1166 iscsi_err(__FILE__
, __LINE__
, "unexpected error\n");
1170 if (param
->rx_offer
) {
1171 iscsi_err(__FILE__
, __LINE__
, "we should not be here\n"); /* error - we received
1174 } else if (param
->rx_answer
) {
1175 (void) strlcpy(val1
, param
->answer_rx
, ISCSI_PARAM_MAX_LEN
); /* we received an answer */
1177 iscsi_err(__FILE__
, __LINE__
, "unexpected error\n");
1182 /* Make sure incoming or outgoing answer is valid */
1184 * None, Reject, Irrelevant and NotUnderstood are
1187 if ((strcmp(val1
, "None") == 0) || (strcmp(val1
, "Reject") == 0) ||
1188 (strcmp(val1
, "Irrelevant") == 0) || (strcmp(val1
, "NotUnderstood") == 0)) {
1191 if (strlen(param
->valid
) > 0) {
1192 for (p3
= p4
= param
->valid
; p4
; p3
= p4
+ 1) {
1193 if ((p4
= strchr(p3
, ',')) != NULL
) {
1194 strncpy(valid
, p3
, (unsigned)(p4
- p3
));
1195 valid
[(int)(p4
- p3
)] = 0x0;
1197 (void) strlcpy(valid
, p3
, ISCSI_PARAM_MAX_LEN
);
1199 if (strcmp(valid
, val1
) == 0) {
1204 iscsi_trace(TRACE_ISCSI_PARAM
, "Valid list empty??\n");
1207 iscsi_err(__FILE__
, __LINE__
, "\"%s\" is not a valid value (must choose from \"%s\")\n", val1
, param
->valid
);
1210 (void) strlcpy(param
->negotiated
, val1
, sizeof(param
->negotiated
));
1214 iscsi_trace(TRACE_ISCSI_PARAM
, "negotiated \"%s\"=\"%s\"\n", param
->key
, param
->negotiated
);
1216 /* For inquiries, we don't commit the value. */
1218 if (param
->tx_offer
&& strcmp(param
->offer_tx
, "?") == 0) {
1219 /* we're offering an inquiry */
1220 iscsi_trace(TRACE_ISCSI_PARAM
, "sending an inquiry for \"%s\"\n", param
->key
);
1222 } else if (param
->rx_offer
&& strcmp(param
->offer_rx
, "?") == 0) {
1223 /* we're receiving an inquiry */
1224 iscsi_trace(TRACE_ISCSI_PARAM
, "received an inquiry for \"%s\"\n", param
->key
);
1226 } else if (param
->tx_answer
&& strcmp(param
->offer_rx
, "?") == 0) {
1227 /* we're answering an inquiry */
1228 iscsi_trace(TRACE_ISCSI_PARAM
, "answering an inquiry for \"%s\"\n", param
->key
);
1230 } else if (param
->rx_answer
&& strcmp(param
->offer_tx
, "?") == 0) {
1231 /* we're receiving an answer for our inquiry */
1232 iscsi_trace(TRACE_ISCSI_PARAM
, "received an answer for inquiry on \"%s\"\n", param
->key
);
1235 iscsi_trace(TRACE_ISCSI_PARAM
, "automatically committing \"%s\"=\"%s\"\n", param
->key
, param
->negotiated
);
1237 c
= param
->negotiated
[19];
1238 param
->negotiated
[19] = 0x0;
1240 printf("* %25s:%20s *\n", param
->key
, param
->negotiated
);
1242 param
->negotiated
[19] = c
;
1245 iscsi_trace(TRACE_ISCSI_PARAM
, "deleting value list for \"%s\"\n", param
->key
);
1246 if (param_val_delete_all(head
, param
->key
) != 0) {
1247 iscsi_err(__FILE__
, __LINE__
, "param_val_delete_all() failed\n");
1252 if (param
->value_l
) {
1253 if (param
->type
== ISCSI_PARAM_TYPE_DECLARE_MULTI
) {
1254 for (item_ptr
= param
->value_l
; item_ptr
->next
!= NULL
; item_ptr
= item_ptr
->next
) {
1256 if ((item_ptr
->next
= iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t
))) == NULL
) {
1257 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc_atomic() failed\n");
1260 item_ptr
= item_ptr
->next
;
1261 item_ptr
->next
= NULL
;
1263 item_ptr
= param
->value_l
;
1266 iscsi_trace(TRACE_ISCSI_PARAM
, "allocating value ptr\n");
1267 if ((param
->value_l
= iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t
))) == NULL
) {
1268 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc_atomic() failed\n");
1271 item_ptr
= param
->value_l
;
1272 item_ptr
->next
= NULL
;
1274 (void) strlcpy(item_ptr
->value
, param
->negotiated
, sizeof(item_ptr
->value
));
1279 iscsi_trace(TRACE_ISCSI_PARAM
, "generated %d bytes response\n", *text_len_out
);
1282 printf("**************************************************\n");
1290 set_session_parameters(iscsi_parameter_t
* head
,
1291 iscsi_sess_param_t
* sess_params
)
1293 /* These parameters are standard and assuming that they are always */
1294 /* present in the list (head). */
1295 memset(sess_params
, 0, sizeof(iscsi_sess_param_t
));
1296 sess_params
->max_burst_length
= param_atoi(head
, "MaxBurstLength");
1297 sess_params
->first_burst_length
= param_atoi(head
, "FirstBurstLength");
1298 sess_params
->max_dataseg_len
=
1299 param_atoi(head
, "MaxRecvDataSegmentLength");
1300 sess_params
->header_digest
= (param_equiv(head
, "HeaderDigest", "Yes")) ? 1 : 0;
1301 sess_params
->data_digest
= (param_equiv(head
, "DataDigest", "Yes")) ? 1 : 0;
1302 sess_params
->initial_r2t
= (param_equiv(head
, "InitialR2T", "Yes"));
1303 sess_params
->immediate_data
= (param_equiv(head
, "ImmediateData", "Yes"));