1 /*
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.
6 *
7 * Intel License Agreement
8 *
9 * Copyright (c) 2000, Intel Corporation
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * -Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 *
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
22 * distribution.
23 *
24 * -The name of Intel Corporation may not be used to endorse or
25 * promote products derived from this software without specific prior
26 * written permission.
27 *
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
39 * SUCH DAMAGE.
40 */
41 #include "config.h"
42 #include "compat.h"
43
44 #ifdef HAVE_CTYPE_H
45 #include <ctype.h>
46 #endif
47
48 #include <stdio.h>
49 #include <stdlib.h>
50
51 #ifdef HAVE_STRING_H
52 #include <string.h>
53 #endif
54
55 #ifdef HAVE_NETINET_IN_H
56 #include <netinet/in.h>
57 #endif
58
59 #include "iscsi-md5.h"
60 #include "iscsiutil.h"
61 #include "parameters.h"
62 #include "conffile.h"
63
64
65 int
param_list_add(iscsi_parameter_t ** head,int type,const char * key,const char * dflt,const char * valid)66 param_list_add(iscsi_parameter_t ** head, int type, const char *key, const char *dflt, const char *valid)
67 {
68 iscsi_parameter_t *param;
69
70 /* Allocated new parameter type */
71
72 if (*head == NULL) {
73 if ((*head = iscsi_malloc_atomic(sizeof(iscsi_parameter_t))) == NULL) {
74 iscsi_err(__FILE__, __LINE__, "out of memory\n");
75 return -1;
76 }
77 param = *head;
78 } else {
79 for (param = *head; param->next != NULL; param = param->next) {
80 }
81 if ((param->next = iscsi_malloc_atomic(sizeof(iscsi_parameter_t))) == NULL) {
82 iscsi_err(__FILE__, __LINE__, "out of memory\n");
83 return -1;
84 }
85 param = param->next;
86 }
87
88 /* Initilized parameter */
89
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 */
100
101 /* Allocated space for value list and set first item to default; and */
102 /* set offer and answer lists to NULL */
103
104 if ((param->value_l = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) {
105 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
106 return -1;
107 }
108 param->value_l->next = NULL;
109 (void) strlcpy(param->value_l->value, dflt, sizeof(param->value_l->value));
110
111 /* Arg check */
112
113 switch (type) {
114 case ISCSI_PARAM_TYPE_DECLARATIVE:
115 break;
116 case ISCSI_PARAM_TYPE_DECLARE_MULTI:
117 break;
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);
128 return -1;
129 }
130 break;
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);
141 return -1;
142 }
143 break;
144 case ISCSI_PARAM_TYPE_NUMERICAL:
145 break;
146 case ISCSI_PARAM_TYPE_NUMERICAL_Z:
147 break;
148 case ISCSI_PARAM_TYPE_LIST:
149 break;
150 default:
151 iscsi_err(__FILE__, __LINE__, "unknown parameter type %d\n", type);
152 return -1;
153 }
154
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);
157 return 0;
158 }
159
160 int
param_list_destroy(iscsi_parameter_t * head)161 param_list_destroy(iscsi_parameter_t * head)
162 {
163 iscsi_parameter_t *ptr, *tmp;
164 iscsi_parameter_value_t *item_ptr, *next;
165
166 for (ptr = head; ptr != NULL;) {
167 tmp = ptr;
168 ptr = ptr->next;
169 if (tmp->value_l) {
170 for (item_ptr = tmp->value_l; item_ptr != NULL; item_ptr = next) {
171 next = item_ptr->next;
172 /*
173 * iscsi_trace(TRACE_ISCSI_PARAM, "freeing \"%s\"
174 * (%p)\n", item_ptr->value, item_ptr);
175 */
176 iscsi_free_atomic(item_ptr);
177 }
178 }
179 /* iscsi_trace(TRACE_ISCSI_PARAM, "freeing %p\n", tmp); */
180 iscsi_free_atomic(tmp);
181 }
182 return 0;
183 }
184
185
186 iscsi_parameter_t *
param_get(iscsi_parameter_t * head,const char * key)187 param_get(iscsi_parameter_t * head, const char *key)
188 {
189 iscsi_parameter_t *ptr;
190
191 for (ptr = head; ptr != NULL; ptr = ptr->next) {
192 if (strcmp(ptr->key, key) == 0) {
193 return ptr;
194 }
195 }
196 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
197 return NULL;
198 }
199
200 char *
param_val(iscsi_parameter_t * head,const char * key)201 param_val(iscsi_parameter_t * head, const char *key)
202 {
203 return param_val_which(head, key, 0);
204 }
205
206 char *
param_val_which(iscsi_parameter_t * head,const char * key,int which)207 param_val_which(iscsi_parameter_t * head, const char *key, int which)
208 {
209 iscsi_parameter_t *ptr;
210 iscsi_parameter_value_t *item_ptr;
211 int i = 0;
212
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);
219 return NULL;
220 }
221 item_ptr = item_ptr->next;
222 }
223 if (item_ptr == NULL) {
224 iscsi_err(__FILE__, __LINE__, "item %d in value list is NULL\n", which);
225 return NULL;
226 }
227 return item_ptr->value;
228 }
229 }
230 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
231 return NULL;
232 }
233
234 static int
param_val_delete_all(iscsi_parameter_t * head,char * key)235 param_val_delete_all(iscsi_parameter_t * head, char *key)
236 {
237 iscsi_parameter_t *ptr;
238 iscsi_parameter_value_t *item_ptr, *next;
239
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);
245 }
246 ptr->value_l = NULL;
247 return 0;
248 }
249 }
250 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
251 return -1;
252 }
253
254 int
param_val_reset(iscsi_parameter_t * head,const char * key)255 param_val_reset(iscsi_parameter_t * head, const char *key)
256 {
257 iscsi_parameter_t *ptr;
258
259 for (ptr = head; ptr != NULL; ptr = ptr->next) {
260 if (strcmp(ptr->key, key) == 0) {
261 ptr->reset = 1;
262 return 0;
263 }
264 }
265 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
266 return -1;
267 }
268
269 int
param_atoi(iscsi_parameter_t * head,const char * key)270 param_atoi(iscsi_parameter_t * head, const char *key)
271 {
272 iscsi_parameter_t *ptr;
273 char *value;
274
275 for (ptr = head; ptr != NULL; ptr = ptr->next) {
276 if (strcmp(ptr->key, key) == 0) {
277 if (ptr->value_l) {
278 if ((value = param_val(head, key)) != NULL) {
279 return iscsi_atoi(value);
280 } else {
281 iscsi_err(__FILE__, __LINE__, "value is NULL\n");
282 return 0;
283 }
284 } else {
285 iscsi_err(__FILE__, __LINE__, "param \"%s\" has NULL value list\n", key);
286 return 0;
287 }
288 }
289 }
290 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
291 return 0;
292 }
293
294 int
param_equiv(iscsi_parameter_t * head,const char * key,const char * val)295 param_equiv(iscsi_parameter_t * head, const char *key, const char *val)
296 {
297 iscsi_parameter_t *ptr;
298 char *value;
299
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);
304 return 0;
305 }
306 if ((value = param_val(head, key)) == NULL) {
307 iscsi_err(__FILE__, __LINE__, "key \"%s\" value is NULL\n", key);
308 return 0;
309 }
310 return (strcmp(value, val) == 0);
311 }
312 }
313 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
314 return -1;
315 }
316
317 int
param_num_vals(iscsi_parameter_t * head,char * key)318 param_num_vals(iscsi_parameter_t * head, char *key)
319 {
320 iscsi_parameter_t *ptr;
321 iscsi_parameter_value_t *item_ptr;
322 int num = 0;
323
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) {
327 num++;
328 }
329 return num;
330 }
331 }
332 iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
333 return -1;
334 }
335
336 int
param_list_print(iscsi_parameter_t * head)337 param_list_print(iscsi_parameter_t * head)
338 {
339 iscsi_parameter_t *ptr;
340 iscsi_parameter_value_t *item_ptr;
341
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);
345 }
346 }
347 return 0;
348 }
349
350 int
param_text_print(char * text,uint32_t text_len)351 param_text_print(char *text, uint32_t text_len)
352 {
353 char key[256];
354 char *ptr, *eq, *value;
355
356 for (ptr = text; (uint32_t)(ptr - text) < text_len; ptr += (strlen(ptr) + 1)) {
357
358 /* Skip over any NULLs */
359
360 while (!(*ptr) && ((uint32_t)(ptr - text) < text_len))
361 ptr++;
362 if ((uint32_t)(ptr - text) >= text_len)
363 break;
364
365 if ((eq = strchr(ptr, '=')) == NULL) {
366 iscsi_err(__FILE__, __LINE__, "delimiter \'=\' not found in token \"%s\"\n", ptr);
367 return -1;
368 }
369 strncpy(key, ptr, (unsigned)(eq - ptr));
370 key[(int)(eq - ptr)] = 0x0;
371 value = eq + 1;
372 printf("\"%s\"=\"%s\"\n", key, value);
373 }
374 return 0;
375 }
376
377 /* ARGSUSED */
378 int
param_text_add(iscsi_parameter_t * head,const char * key,const char * value,char * text,int * len,int size,int offer)379 param_text_add(iscsi_parameter_t * head, const char *key, const char *value, char *text, int *len, int size, int offer)
380 {
381 int cc;
382
383 cc = snprintf(text + *len, (unsigned)(size - *len), "%s=%s", key, value);
384 *len += cc + 1;
385 return 0;
386 }
387
388 int
driver_atoi(const char * s)389 driver_atoi(const char *s)
390 {
391 int k = 0;
392
393 while (*s != 0x0 && *s >= '0' && *s <= '9') {
394 k = 10 * k + (*s - '0');
395 s++;
396 }
397 return k;
398 }
399
400 /* find the credentials for `user' and put them in `cred' */
401 static int
find_credentials(iscsi_cred_t * cred,char * user,const char * auth)402 find_credentials(iscsi_cred_t *cred, char *user, const char *auth)
403 {
404 conffile_t conf;
405 const char *authtype;
406 unsigned cc;
407 ent_t e;
408
409 (void) memset(&conf, 0x0, sizeof(conf));
410 (void) memset(&e, 0x0, sizeof(e));
411
412 if (!conffile_open(&conf, _PATH_ISCSI_PASSWD, "r", ":", "#")) {
413 iscsi_err(__FILE__, __LINE__, "can't open `%s'\n", _PATH_ISCSI_PASSWD);
414 exit(EXIT_FAILURE);
415 }
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);
425 return 1;
426 }
427 }
428 }
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);
432 return 0;
433 }
434
435 #if 0
436 /* free any storage allocated in `cred' */
437 static void
438 free_cred(iscsi_cred_t *cred)
439 {
440 if (cred) {
441 if (cred->user) {
442 iscsi_free_atomic(cred->user);
443 }
444 if (cred->auth_type) {
445 iscsi_free_atomic(cred->auth_type);
446 }
447 if (cred->shared_secret) {
448 iscsi_free_atomic(cred->shared_secret);
449 }
450 }
451 }
452 #endif
453
454 /* Security offering and check */
455 /*
456 * ret values: =0: succeed or no security >0: security negotiation in process
457 * <0: failed
458 */
459 static int
param_parse_security(iscsi_parameter_t * head,iscsi_parameter_t * param_in,iscsi_cred_t * cred,char * text_out,int * text_len_out,int textsize)460 param_parse_security(iscsi_parameter_t * head,
461 iscsi_parameter_t * param_in,
462 iscsi_cred_t *cred,
463 char *text_out, int *text_len_out, int textsize)
464 {
465
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;
472 int ret = 1;
473
474 if ((chapstring = iscsi_malloc(ISCSI_CHAP_STRING_LENGTH)) == NULL) {
475 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
476 return -1;
477 }
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);
482 return -1;
483 }
484 #define PPS_CLEANUP { if (chapstring != NULL) iscsi_free(chapstring);if (context != NULL) iscsi_free(context); }
485 #define PPS_ERROR { PPS_CLEANUP; return (-1); };
486
487 if (strcmp(param_in->key, "AuthMethod") == 0) {
488 if (param_in->rx_answer && strcmp(param_in->answer_rx, "None") == 0) {
489 PPS_CLEANUP;
490 return 0; /* Proposed None for
491 * Authentication */
492 }
493 if (param_in->rx_offer && strcmp(param_in->offer_rx, "None") == 0) {
494 PPS_CLEANUP;
495 return 0;
496 }
497 if (!param_in->rx_offer) {
498 param = param_get(head, "CHAP_A");
499 if (param == NULL)
500 PPS_ERROR;
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);
506 ret++;
507 }
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);
512
513 if ((param = param_get(head, "CHAP_I")) == NULL) {
514 PPS_ERROR;
515 }
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);
523
524 if ((param = param_get(head, "CHAP_C")) == NULL) {
525 PPS_ERROR;
526 }
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);
535 ret++;
536 }
537 } else if (strcmp(param_in->key, "CHAP_I") == 0) {
538
539 idData = driver_atoi((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx);
540 ret++;
541
542 } else if (strcmp(param_in->key, "CHAP_C") == 0) {
543
544 HexTextToData((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx, ISCSI_CHAP_STRING_LENGTH,
545 chapdata, ISCSI_CHAP_DATA_LENGTH);
546
547 if ((param = param_get(head, "CHAP_N")) == NULL) {
548 PPS_ERROR;
549 }
550 param->tx_offer = 1; /* sending an offer */
551 param->rx_offer = 0; /* reset */
552
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);
555 PPS_ERROR;
556 }
557
558 if (cred->user) {
559 (void) strlcpy(param->offer_tx, cred->user, sizeof(param->offer_tx));
560 } else {
561 iscsi_err(__FILE__, __LINE__, "no valid user credentials\n");
562 PPS_ERROR;
563 }
564
565 PARAM_TEXT_ADD(head, param->key, param->offer_tx,
566 text_out, text_len_out, textsize, 0, PPS_ERROR);
567
568 if ((param = param_get(head, "CHAP_R")) == NULL) {
569 PPS_ERROR;
570 }
571 param->tx_offer = 1; /* sending an offer */
572 param->rx_offer = 0; /* reset */
573 iSCSI_MD5Init(context);
574 iSCSI_MD5Update(context, &idData, 1);
575
576 if (cred->shared_secret == NULL) {
577 iscsi_err(__FILE__, __LINE__, "null shared secret\n");
578 PPS_ERROR;
579 } else {
580 iSCSI_MD5Update(context, (const uint8_t *)cred->shared_secret, strlen(cred->shared_secret));
581 }
582
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);
589
590 PARAM_TEXT_ADD(head, param->key, param->offer_tx,
591 text_out, text_len_out, textsize, 0, PPS_ERROR);
592
593 if (param_in->rx_offer) {
594
595 if ((param = param_get(head, "CHAP_I")) == NULL) {
596 PPS_ERROR;
597 }
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);
605
606 if ((param = param_get(head, "CHAP_C")) == NULL) {
607 PPS_ERROR;
608 }
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);
617 }
618 ret++;
619
620 } else if (strcmp(param_in->key, "CHAP_N") == 0) {
621 char *user;
622
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);
626 PPS_ERROR;
627 }
628 ret++;
629
630 } else if (strcmp(param_in->key, "CHAP_R") == 0) {
631
632 iSCSI_MD5Init(context);
633
634 iSCSI_MD5Update(context, &idData, 1);
635
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);
639
640 if (cred->shared_secret == NULL) {
641 iscsi_err(__FILE__, __LINE__, "Null shared secret in initiator\n");
642 PPS_ERROR;
643 } else {
644 iSCSI_MD5Update(context, (const uint8_t *)cred->shared_secret, strlen(cred->shared_secret));
645 }
646
647 iSCSI_MD5Update(context, chapdata, ISCSI_CHAP_DATA_LENGTH);
648 iSCSI_MD5Final(chapdata, context);
649
650 HexTextToData((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx, ISCSI_CHAP_STRING_LENGTH,
651 respdata, ISCSI_CHAP_DATA_LENGTH);
652
653 HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
654 param_in->offer_rx, ISCSI_CHAP_STRING_LENGTH);
655
656 if (memcmp(respdata, chapdata, ISCSI_CHAP_DATA_LENGTH) != 0) {
657 iscsi_err(__FILE__, __LINE__, "Initiator authentication failed %x %x\n", *chapdata, *respdata);
658 PPS_ERROR;
659 } else {
660 PPS_CLEANUP;
661 }
662 return 0;
663 }
664 PPS_CLEANUP;
665 return (ret);
666 }
667
668 int
param_text_parse(iscsi_parameter_t * head,iscsi_cred_t * cred,char * text_in,int text_len_in,char * text_out,int * text_len_out,int textsize,int outgoing)669 param_text_parse(iscsi_parameter_t * head,
670 iscsi_cred_t *cred,
671 char *text_in, int text_len_in,
672 char *text_out, int *text_len_out,
673 int textsize,
674 int outgoing)
675 {
676 static char *key = NULL;
677 char *value = NULL;
678 char *ptr, *eq;
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;
683 char *offer = NULL;
684 char *valid = NULL;
685 char *val1 = NULL;
686 char *val2 = NULL;
687 char *tmp_key = NULL;
688 char c;
689 int ret;
690
691 /*
692 * Whether incoming or outgoing, some of the params might be offers
693 * and some answers. Incoming
694 */
695 /*
696 * text has the potential for creating outgoing text - and this will
697 * happen when the incoming
698 */
699 /* text has offers that need an answer. */
700
701 iscsi_trace(TRACE_ISCSI_PARAM, "parsing %d %s bytes of text parameters\n", text_len_in, outgoing ? "outgoing" : "incoming");
702
703 if ((key = iscsi_malloc(ISCSI_PARAM_KEY_LEN)) == NULL) {
704 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
705 return -1;
706 }
707 if ((offer = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
708 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
709 if (key != NULL) {
710 iscsi_free(key);
711 }
712 return -1;
713 }
714 if ((valid = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
715 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
716 if (key != NULL) {
717 iscsi_free(key);
718 }
719 if (offer != NULL) {
720 iscsi_free(offer);
721 }
722 return -1;
723 }
724 if ((val1 = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
725 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
726 if (key != NULL) {
727 iscsi_free(key);
728 }
729 if (offer != NULL) {
730 iscsi_free(offer);
731 }
732 if (valid != NULL) {
733 iscsi_free(valid);
734 }
735 return -1;
736 }
737 if ((val2 = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
738 iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
739 if (key != NULL) {
740 iscsi_free(key);
741 }
742 if (offer != NULL) {
743 iscsi_free(offer);
744 }
745 if (valid != NULL) {
746 iscsi_free(valid);
747 }
748 if (val1 != NULL) {
749 iscsi_free(val1);
750 }
751 return -1;
752 }
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;}
760
761 if (!outgoing) {
762 *text_len_out = 0;
763 }
764
765 #if ISCSI_DEBUG
766 printf("**************************************************\n");
767 printf("* PARAMETERS NEGOTIATED *\n");
768 printf("* *\n");
769 #endif
770
771 for (ptr = text_in; ptr - text_in < text_len_in; ptr += (strlen(ptr) + 1)) {
772
773 /* Skip over any NULLs */
774
775 while (!(*ptr) && ((ptr - text_in) < text_len_in)) {
776 ptr++;
777 }
778 if ((ptr - text_in) >= text_len_in) {
779 break;
780 }
781
782 /* Extract <key>=<value> token from text_in */
783
784 if ((eq = strchr(ptr, '=')) == NULL) {
785 iscsi_err(__FILE__, __LINE__, "delimiter \'=\' not found in token \"%s\"\n", ptr);
786 } else {
787 if ((int)(eq - ptr) >= (ISCSI_PARAM_KEY_LEN - 1)) {
788 if (!outgoing) {
789 tmp_key = iscsi_malloc((unsigned)(eq - ptr));
790 if (tmp_key) {
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);
795 }
796 } else {
797 printf("ignoring \"%s\"\n", key);
798 }
799 goto next;
800 }
801 strncpy(key, ptr, (unsigned)(eq - ptr));
802 key[(int)(eq - ptr)] = 0x0;
803 value = eq + 1;
804 }
805
806 /* Find key in param list */
807
808 for (param = head; param != NULL; param = param->next) {
809 if (strcmp(param->key, key) == 0) {
810 break;
811 }
812 }
813 if (param == NULL) {
814 if (!outgoing) {
815 /* Key not understood. */
816 PARAM_TEXT_ADD(head, key, "NotUnderstood", text_out, text_len_out, textsize, 0, PTP_ERROR);
817 } else {
818 printf("ignoring \"%s\"\n", key);
819 }
820 goto next;
821 }
822 if (strlen(value) > ISCSI_PARAM_MAX_LEN) {
823 iscsi_err(__FILE__, __LINE__,
824 "strlen(value) %zu\n", strlen(value));
825 PTP_CLEANUP;
826 return -1;
827 }
828
829 /* We're sending|receiving an offer|answer */
830 if (outgoing) {
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);
839 goto negotiate;
840 } else {
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)) {
848 goto negotiate;
849 }
850 goto next;
851 }
852 } else {
853 if (param->tx_offer) {
854 param->rx_answer = 1; /* received an answer */
855 param->tx_answer = 0;
856 param->rx_offer = 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);
861
862 if ((ret = param_parse_security(head, param, cred,
863 text_out, text_len_out, textsize)) > 1) {
864 goto next;
865 } else if (ret == 0) {
866 /*
867 * FIX ME Happens in initiator code
868 * currently we ignore initiator
869 * authentication status See comments
870 * at the beginning of parse_security
871 */
872 goto negotiate;
873 } else if (ret == 1) {
874 goto negotiate;
875 } else {
876 PTP_CLEANUP;
877 }
878 return ISCSI_PARAM_STATUS_AUTH_FAILED;
879 } else {
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);
885
886 if ((ret = param_parse_security(head, param, cred,
887 text_out, text_len_out, textsize)) > 1) {
888 goto next;
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));
893 }
894 PTP_CLEANUP;
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));
900 }
901 }
902 /*
903 * Answer the offer if it is an inquiry or
904 * the type is not DECLARATIVE
905 */
906
907 if ((strcmp(param->offer_rx, "?") != 0) && ((param->type == ISCSI_PARAM_TYPE_DECLARATIVE) || (param->type == ISCSI_PARAM_TYPE_DECLARE_MULTI))) {
908 goto negotiate;
909 } else {
910 goto answer;
911 }
912 }
913 }
914
915 answer:
916
917 /* Answer with current value if this is an inquiry (<key>=?) */
918
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 (void) strlcpy(param->answer_tx, param->value_l->value, sizeof(param->answer_tx));
923 } else {
924 iscsi_err(__FILE__, __LINE__, "param \"%s\" has NULL value_l\n", param->key);
925 param->answer_tx[0] = 0x0;
926 }
927 goto add_answer;
928 }
929 /* Generate answer according to the parameter type */
930
931 switch (param->type) {
932
933 case ISCSI_PARAM_TYPE_BINARY_AND:
934 goto binary_or;
935
936 case ISCSI_PARAM_TYPE_BINARY_OR:
937 binary_or:
938 if (strcmp(value, "yes") != 0 &&
939 strcmp(value, "no") != 0 &&
940 strcmp(value, "Yes") != 0 &&
941 strcmp(value, "No") != 0) {
942 iscsi_err(__FILE__, __LINE__, "\"%s\" is not a valid binary value\n", value);
943 (void) strlcpy(param->answer_tx, "Reject", sizeof(param->answer_tx));
944 goto add_answer;
945 }
946 if (strchr(param->valid, ',') != NULL) {
947 (void) strlcpy(param->answer_tx, value, sizeof(param->answer_tx)); /* we accept both yes
948 * and no, so answer w/
949 * their offer */
950 } else {
951 (void) strlcpy(param->answer_tx, param->valid, sizeof(param->answer_tx)); /* answer with the only
952 * value we support */
953 }
954 break;
955
956 case ISCSI_PARAM_TYPE_LIST:
957
958 /*
959 * Use our default value if it's offered as one of the option
960 * in the parameter list.
961 *
962 * We need to do this at least for CHAP because cisco's initiator
963 * could be sending us a parameter value list with "CHAP,None",
964 * even when it doesn't set username/password in its configration
965 * file, in which case we should pick "None" as for no security instead
966 * of pick the first one on the value list. "None" is the default value
967 * for AuthMethod
968 *
969 * This fix is working well now, though is arguable. We should keep
970 * this just to make us work with Cisco for now.
971 */
972 if (strlen(param->dflt)) {
973 for (p1 = p2 = param->offer_rx; p2; p1 = p2 + 1) {
974
975 if ((p2 = strchr(p1, ',')) != NULL) {
976 strncpy(offer, p1, (unsigned)(p2 - p1));
977 offer[(int)(p2 - p1)] = 0x0;
978 } else {
979 (void) strlcpy(offer, p1, ISCSI_PARAM_MAX_LEN);
980 }
981
982 if (strcmp(param->dflt, offer) == 0) {
983 (void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx));
984 goto add_answer;
985 }
986 }
987 }
988 /* Find the first valid offer that we support */
989
990 for (p1 = p2 = param->offer_rx; p2; p1 = p2 + 1) {
991 if ((p2 = strchr(p1, ',')) != NULL) {
992 strncpy(offer, p1, (unsigned)(p2 - p1));
993 offer[p2 - p1] = 0x0;
994 } else {
995 (void) strlcpy(offer, p1, ISCSI_PARAM_MAX_LEN);
996 }
997 if (strlen(param->valid)) {
998 for (p3 = p4 = param->valid; p4; p3 = p4 + 1) {
999 if ((p4 = strchr(p3, ',')) != NULL) {
1000 strncpy(valid, p3, (unsigned)(p4 - p3));
1001 valid[(int)(p4 - p3)] = 0x0;
1002 } else {
1003 (void) strlcpy(valid, p3, ISCSI_PARAM_MAX_LEN);
1004 }
1005 if (strcmp(valid, offer) == 0) {
1006 (void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx));
1007 goto add_answer;
1008 }
1009 }
1010 } else {
1011 iscsi_trace(TRACE_ISCSI_PARAM, "Valid list empty. Answering with first in offer list\n");
1012 (void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx));
1013 goto add_answer;
1014 }
1015 iscsi_trace(TRACE_ISCSI_PARAM, "\"%s\" is not a valid offer for key \"%s\" (must choose from \"%s\")\n", offer, param->key, param->valid);
1016 }
1017 iscsi_trace(TRACE_ISCSI_PARAM, "No Valid offers: \"%s\" is added as value for key \"%s\")\n", "Reject", param->key);
1018 (void) strlcpy(param->answer_tx, "Reject", sizeof(param->answer_tx));
1019 break;
1020
1021 case ISCSI_PARAM_TYPE_NUMERICAL_Z:
1022 goto numerical;
1023
1024 case ISCSI_PARAM_TYPE_NUMERICAL:
1025 numerical:
1026 offer_i = iscsi_atoi(param->offer_rx);
1027 max_i = iscsi_atoi(param->valid);
1028 if (param->type == ISCSI_PARAM_TYPE_NUMERICAL_Z) {
1029 if (max_i == 0) {
1030 answer_i = offer_i; /* we support anything,
1031 * so return whatever
1032 * they offered */
1033 } else if (offer_i == 0) {
1034 answer_i = max_i; /* return only what we
1035 * can support */
1036 } else if (offer_i > max_i) {
1037 answer_i = max_i; /* we are the lower of
1038 * the two */
1039 } else {
1040 answer_i = offer_i; /* they are the lower of
1041 * the two */
1042 }
1043 } else {
1044 if (offer_i > max_i) {
1045 answer_i = max_i; /* we are the lower of
1046 * the two */
1047 } else {
1048 answer_i = offer_i; /* they are the lower of
1049 * the two */
1050 }
1051 }
1052 (void) snprintf(param->answer_tx, sizeof(param->answer_tx), "%d", answer_i);
1053 goto add_answer;
1054
1055 default:
1056 goto next;
1057 }
1058 add_answer: PARAM_TEXT_ADD(head, key, param->answer_tx, text_out, text_len_out, textsize, 0, PTP_ERROR);
1059 iscsi_trace(TRACE_ISCSI_PARAM, "answering \"%s\"=\"%s\"\n", param->key, param->answer_tx);
1060 goto next;
1061
1062
1063 /* Negotiate after receiving|sending an answer */
1064
1065 negotiate:
1066 switch (param->type) {
1067 case ISCSI_PARAM_TYPE_DECLARE_MULTI:
1068 goto declarative_negotiate;
1069 case ISCSI_PARAM_TYPE_DECLARATIVE:
1070 declarative_negotiate:
1071 if (param->tx_answer) {
1072 (void) strlcpy(param->negotiated, param->answer_tx, sizeof(param->negotiated));
1073 } else if (param->tx_offer) {
1074 (void) strlcpy(param->negotiated, param->offer_tx, sizeof(param->negotiated));
1075 } else if (param->rx_answer) {
1076 (void) strlcpy(param->negotiated, param->answer_rx, sizeof(param->negotiated));
1077 } else if (param->rx_offer) {
1078 (void) strlcpy(param->negotiated, param->offer_rx, sizeof(param->negotiated));
1079 } else {
1080 iscsi_err(__FILE__, __LINE__, "Invalid negotiation!?!?\n");
1081 }
1082 break;
1083 case ISCSI_PARAM_TYPE_BINARY_AND:
1084 goto binary_or_negotiate;
1085 case ISCSI_PARAM_TYPE_BINARY_OR:
1086 binary_or_negotiate:
1087 if (outgoing) {
1088 (void) strlcpy(val1, param->offer_rx, ISCSI_PARAM_MAX_LEN);
1089 (void) strlcpy(val2, param->answer_tx, ISCSI_PARAM_MAX_LEN);
1090 } else {
1091 (void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN);
1092 (void) strlcpy(val2, param->offer_tx, ISCSI_PARAM_MAX_LEN);
1093 /* Make sure the answer is valid */
1094 if (strcmp(val1, "Yes") != 0 &&
1095 strcmp(val1, "No") != 0 &&
1096 strcmp(val1, "yes") != 0 &&
1097 strcmp(val1, "no") != 0 &&
1098 strcmp(val1, "Irrelevant") != 0) {
1099 /* Invalid value returned as answer. */
1100 iscsi_err(__FILE__, __LINE__, "Invalid answer (%s) for key (%s)\n",
1101 val1, key);
1102 PTP_ERROR;
1103 }
1104 }
1105 if (param->type == ISCSI_PARAM_TYPE_BINARY_OR) {
1106 if (strcmp(val1, "yes") == 0 || strcmp(val2, "yes") == 0 || strcmp(val1, "Yes") == 0 || strcmp(val2, "Yes") == 0) {
1107 (void) strlcpy(param->negotiated, "Yes", sizeof(param->negotiated));
1108 } else {
1109 (void) strlcpy(param->negotiated, "No", sizeof(param->negotiated));
1110 }
1111 } else {
1112 if ((strcmp(val1, "yes") == 0 && strcmp(val2, "yes") == 0) || (strcmp(val1, "Yes") == 0 && strcmp(val2, "Yes") == 0)) {
1113 (void) strlcpy(param->negotiated, "Yes", sizeof(param->negotiated));
1114 } else {
1115 (void) strlcpy(param->negotiated, "No", sizeof(param->negotiated));
1116 }
1117 }
1118 break;
1119 case ISCSI_PARAM_TYPE_NUMERICAL_Z:
1120 goto numerical_negotiate;
1121 case ISCSI_PARAM_TYPE_NUMERICAL:
1122 numerical_negotiate:
1123 if (outgoing) {
1124 (void) strlcpy(val1, param->offer_rx, ISCSI_PARAM_MAX_LEN);
1125 (void) strlcpy(val2, param->answer_tx, ISCSI_PARAM_MAX_LEN);
1126 } else {
1127 (void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN);
1128 (void) strlcpy(val2, param->offer_tx, ISCSI_PARAM_MAX_LEN);
1129 }
1130 val1_i = iscsi_atoi(val1);
1131 val2_i = iscsi_atoi(val2);
1132 if (param->type == ISCSI_PARAM_TYPE_NUMERICAL_Z) {
1133 if (val1_i == 0) {
1134 negotiated_i = val2_i;
1135 } else if (val2_i == 0) {
1136 negotiated_i = val1_i;
1137 } else if (val1_i > val2_i) {
1138 negotiated_i = val2_i;
1139 } else {
1140 negotiated_i = val1_i;
1141 }
1142 } else {
1143 if (val1_i > val2_i) {
1144 negotiated_i = val2_i;
1145 } else {
1146 negotiated_i = val1_i;
1147 }
1148 }
1149 (void) snprintf(param->negotiated, sizeof(param->negotiated), "%d", negotiated_i);
1150 break;
1151 case ISCSI_PARAM_TYPE_LIST:
1152 if (outgoing) {
1153 if (param->tx_offer) {
1154 iscsi_err(__FILE__, __LINE__, "we should not be here\n"); /* error - we're sending
1155 * an offer */
1156 PTP_ERROR;
1157 } else if (param->tx_answer) {
1158 (void) strlcpy(val1, param->answer_tx, ISCSI_PARAM_MAX_LEN); /* we're sending an
1159 * answer */
1160 } else {
1161 iscsi_err(__FILE__, __LINE__, "unexpected error\n");
1162 PTP_ERROR;
1163 }
1164 } else {
1165 if (param->rx_offer) {
1166 iscsi_err(__FILE__, __LINE__, "we should not be here\n"); /* error - we received
1167 * an offer */
1168 PTP_ERROR;
1169 } else if (param->rx_answer) {
1170 (void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN); /* we received an answer */
1171 } else {
1172 iscsi_err(__FILE__, __LINE__, "unexpected error\n");
1173 PTP_ERROR;
1174 }
1175 }
1176
1177 /* Make sure incoming or outgoing answer is valid */
1178 /*
1179 * None, Reject, Irrelevant and NotUnderstood are
1180 * valid
1181 */
1182 if ((strcmp(val1, "None") == 0) || (strcmp(val1, "Reject") == 0) ||
1183 (strcmp(val1, "Irrelevant") == 0) || (strcmp(val1, "NotUnderstood") == 0)) {
1184 goto value_ok;
1185 }
1186 if (strlen(param->valid) > 0) {
1187 for (p3 = p4 = param->valid; p4; p3 = p4 + 1) {
1188 if ((p4 = strchr(p3, ',')) != NULL) {
1189 strncpy(valid, p3, (unsigned)(p4 - p3));
1190 valid[(int)(p4 - p3)] = 0x0;
1191 } else {
1192 (void) strlcpy(valid, p3, ISCSI_PARAM_MAX_LEN);
1193 }
1194 if (strcmp(valid, val1) == 0) {
1195 goto value_ok;
1196 }
1197 }
1198 } else {
1199 iscsi_trace(TRACE_ISCSI_PARAM, "Valid list empty??\n");
1200 PTP_ERROR;
1201 }
1202 iscsi_err(__FILE__, __LINE__, "\"%s\" is not a valid value (must choose from \"%s\")\n", val1, param->valid);
1203 PTP_ERROR;
1204 value_ok:
1205 (void) strlcpy(param->negotiated, val1, sizeof(param->negotiated));
1206 break;
1207 }
1208
1209 iscsi_trace(TRACE_ISCSI_PARAM, "negotiated \"%s\"=\"%s\"\n", param->key, param->negotiated);
1210
1211 /* For inquiries, we don't commit the value. */
1212
1213 if (param->tx_offer && strcmp(param->offer_tx, "?") == 0) {
1214 /* we're offering an inquiry */
1215 iscsi_trace(TRACE_ISCSI_PARAM, "sending an inquiry for \"%s\"\n", param->key);
1216 goto next;
1217 } else if (param->rx_offer && strcmp(param->offer_rx, "?") == 0) {
1218 /* we're receiving an inquiry */
1219 iscsi_trace(TRACE_ISCSI_PARAM, "received an inquiry for \"%s\"\n", param->key);
1220 goto next;
1221 } else if (param->tx_answer && strcmp(param->offer_rx, "?") == 0) {
1222 /* we're answering an inquiry */
1223 iscsi_trace(TRACE_ISCSI_PARAM, "answering an inquiry for \"%s\"\n", param->key);
1224 goto next;
1225 } else if (param->rx_answer && strcmp(param->offer_tx, "?") == 0) {
1226 /* we're receiving an answer for our inquiry */
1227 iscsi_trace(TRACE_ISCSI_PARAM, "received an answer for inquiry on \"%s\"\n", param->key);
1228 goto next;
1229 }
1230 iscsi_trace(TRACE_ISCSI_PARAM, "automatically committing \"%s\"=\"%s\"\n", param->key, param->negotiated);
1231
1232 c = param->negotiated[19];
1233 param->negotiated[19] = 0x0;
1234 #if ISCSI_DEBUG
1235 printf("* %25s:%20s *\n", param->key, param->negotiated);
1236 #endif
1237 param->negotiated[19] = c;
1238
1239 if (param->reset) {
1240 iscsi_trace(TRACE_ISCSI_PARAM, "deleting value list for \"%s\"\n", param->key);
1241 if (param_val_delete_all(head, param->key) != 0) {
1242 iscsi_err(__FILE__, __LINE__, "param_val_delete_all() failed\n");
1243 PTP_ERROR;
1244 }
1245 param->reset = 0;
1246 }
1247 if (param->value_l) {
1248 if (param->type == ISCSI_PARAM_TYPE_DECLARE_MULTI) {
1249 for (item_ptr = param->value_l; item_ptr->next != NULL; item_ptr = item_ptr->next) {
1250 }
1251 if ((item_ptr->next = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) {
1252 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
1253 PTP_ERROR;
1254 }
1255 item_ptr = item_ptr->next;
1256 item_ptr->next = NULL;
1257 } else {
1258 item_ptr = param->value_l;
1259 }
1260 } else {
1261 iscsi_trace(TRACE_ISCSI_PARAM, "allocating value ptr\n");
1262 if ((param->value_l = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) {
1263 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
1264 PTP_ERROR;
1265 }
1266 item_ptr = param->value_l;
1267 item_ptr->next = NULL;
1268 }
1269 (void) strlcpy(item_ptr->value, param->negotiated, sizeof(item_ptr->value));
1270 next:
1271 continue;
1272 }
1273 if (!outgoing) {
1274 iscsi_trace(TRACE_ISCSI_PARAM, "generated %d bytes response\n", *text_len_out);
1275 }
1276 #if ISCSI_DEBUG
1277 printf("**************************************************\n");
1278 #endif
1279
1280 PTP_CLEANUP;
1281 return 0;
1282 }
1283
1284 void
set_session_parameters(iscsi_parameter_t * head,iscsi_sess_param_t * sess_params)1285 set_session_parameters(iscsi_parameter_t * head,
1286 iscsi_sess_param_t * sess_params)
1287 {
1288 /* These parameters are standard and assuming that they are always */
1289 /* present in the list (head). */
1290 memset(sess_params, 0, sizeof(iscsi_sess_param_t));
1291 sess_params->max_burst_length = param_atoi(head, "MaxBurstLength");
1292 sess_params->first_burst_length = param_atoi(head, "FirstBurstLength");
1293 sess_params->max_dataseg_len =
1294 param_atoi(head, "MaxRecvDataSegmentLength");
1295 sess_params->header_digest = (param_equiv(head, "HeaderDigest", "Yes")) ? 1 : 0;
1296 sess_params->data_digest = (param_equiv(head, "DataDigest", "Yes")) ? 1 : 0;
1297 sess_params->initial_r2t = (param_equiv(head, "InitialR2T", "Yes"));
1298 sess_params->immediate_data = (param_equiv(head, "ImmediateData", "Yes"));
1299 }
1300