xref: /netbsd-src/external/bsd/iscsi/dist/src/lib/parameters.c (revision 31a77d8abb0a624ecf702bd9799d92e4be2e52ee)
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