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
65int
66param_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
160int
161param_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
186iscsi_parameter_t *
187param_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
200char           *
201param_val(iscsi_parameter_t * head, const char *key)
202{
203	return param_val_which(head, key, 0);
204}
205
206char           *
207param_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
234static int
235param_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
254int
255param_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
269int
270param_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
294int
295param_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
317int
318param_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
336int
337param_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
350int
351param_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 */
378int
379param_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
388int
389driver_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' */
401static int
402find_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' */
437static void
438free_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 */
459static int
460param_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
668int
669param_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
915answer:
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				if (param->value_l->value) {
923					(void) strlcpy(param->answer_tx, param->value_l->value, sizeof(param->answer_tx));
924				} else {
925					iscsi_err(__FILE__, __LINE__, "param \"%s\" has NULL value_l->value\n", param->key);
926					param->answer_tx[0] = 0x0;
927				}
928			} else {
929				iscsi_err(__FILE__, __LINE__, "param \"%s\" has NULL value_l\n", param->key);
930				param->answer_tx[0] = 0x0;
931			}
932			goto add_answer;
933		}
934		/* Generate answer according to the parameter type */
935
936		switch (param->type) {
937
938		case ISCSI_PARAM_TYPE_BINARY_AND:
939			goto binary_or;
940
941		case ISCSI_PARAM_TYPE_BINARY_OR:
942binary_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));
949				goto add_answer;
950			}
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/
954									 * their offer */
955			} else {
956				(void) strlcpy(param->answer_tx, param->valid, sizeof(param->answer_tx));	/* answer with the only
957									 * value we support */
958			}
959			break;
960
961		case ISCSI_PARAM_TYPE_LIST:
962
963			/*
964			 * Use our default value if it's offered as one of the option
965			 * in the parameter list.
966			 *
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
972			 * for AuthMethod
973			 *
974			 * This fix is working well now, though is arguable. We should keep
975			 * this just to make us work with Cisco for now.
976			 */
977			if (strlen(param->dflt)) {
978				for (p1 = p2 = param->offer_rx; p2; p1 = p2 + 1) {
979
980					if ((p2 = strchr(p1, ',')) != NULL) {
981						strncpy(offer, p1, (unsigned)(p2 - p1));
982						offer[(int)(p2 - p1)] = 0x0;
983					} else {
984						(void) strlcpy(offer, p1, ISCSI_PARAM_MAX_LEN);
985					}
986
987					if (strcmp(param->dflt, offer) == 0) {
988						(void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx));
989						goto add_answer;
990					}
991				}
992			}
993			/* Find the first valid offer that we support */
994
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;
999				} else {
1000					(void) strlcpy(offer, p1, ISCSI_PARAM_MAX_LEN);
1001				}
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;
1007						} else {
1008							(void) strlcpy(valid, p3, ISCSI_PARAM_MAX_LEN);
1009						}
1010						if (strcmp(valid, offer) == 0) {
1011							(void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx));
1012							goto add_answer;
1013						}
1014					}
1015				} else {
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));
1018					goto add_answer;
1019				}
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);
1021			}
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));
1024			break;
1025
1026		case ISCSI_PARAM_TYPE_NUMERICAL_Z:
1027			goto numerical;
1028
1029		case ISCSI_PARAM_TYPE_NUMERICAL:
1030numerical:
1031			offer_i = iscsi_atoi(param->offer_rx);
1032			max_i = iscsi_atoi(param->valid);
1033			if (param->type == ISCSI_PARAM_TYPE_NUMERICAL_Z) {
1034				if (max_i == 0) {
1035					answer_i = offer_i;	/* we support anything,
1036								 * so return whatever
1037								 * they offered */
1038				} else if (offer_i == 0) {
1039					answer_i = max_i;	/* return only what we
1040								 * can support */
1041				} else if (offer_i > max_i) {
1042					answer_i = max_i;	/* we are the lower of
1043								 * the two */
1044				} else {
1045					answer_i = offer_i;	/* they are the lower of
1046								 * the two */
1047				}
1048			} else {
1049				if (offer_i > max_i) {
1050					answer_i = max_i;	/* we are the lower of
1051								 * the two */
1052				} else {
1053					answer_i = offer_i;	/* they are the lower of
1054								 * the two */
1055				}
1056			}
1057			(void) snprintf(param->answer_tx, sizeof(param->answer_tx), "%d", answer_i);
1058			goto add_answer;
1059
1060		default:
1061			goto next;
1062		}
1063add_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);
1065		goto next;
1066
1067
1068		/* Negotiate after receiving|sending an answer  */
1069
1070negotiate:
1071		switch (param->type) {
1072		case ISCSI_PARAM_TYPE_DECLARE_MULTI:
1073			goto declarative_negotiate;
1074		case ISCSI_PARAM_TYPE_DECLARATIVE:
1075declarative_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));
1084			} else {
1085				iscsi_err(__FILE__, __LINE__, "Invalid negotiation!?!?\n");
1086			}
1087			break;
1088		case ISCSI_PARAM_TYPE_BINARY_AND:
1089			goto binary_or_negotiate;
1090		case ISCSI_PARAM_TYPE_BINARY_OR:
1091binary_or_negotiate:
1092			if (outgoing) {
1093				(void) strlcpy(val1, param->offer_rx, ISCSI_PARAM_MAX_LEN);
1094				(void) strlcpy(val2, param->answer_tx, ISCSI_PARAM_MAX_LEN);
1095			} else {
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",
1106						    val1, key);
1107					PTP_ERROR;
1108				}
1109			}
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));
1113				} else {
1114					(void) strlcpy(param->negotiated, "No", sizeof(param->negotiated));
1115				}
1116			} else {
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));
1119				} else {
1120					(void) strlcpy(param->negotiated, "No", sizeof(param->negotiated));
1121				}
1122			}
1123			break;
1124		case ISCSI_PARAM_TYPE_NUMERICAL_Z:
1125			goto numerical_negotiate;
1126		case ISCSI_PARAM_TYPE_NUMERICAL:
1127numerical_negotiate:
1128			if (outgoing) {
1129				(void) strlcpy(val1, param->offer_rx, ISCSI_PARAM_MAX_LEN);
1130				(void) strlcpy(val2, param->answer_tx, ISCSI_PARAM_MAX_LEN);
1131			} else {
1132				(void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN);
1133				(void) strlcpy(val2, param->offer_tx, ISCSI_PARAM_MAX_LEN);
1134			}
1135			val1_i = iscsi_atoi(val1);
1136			val2_i = iscsi_atoi(val2);
1137			if (param->type == ISCSI_PARAM_TYPE_NUMERICAL_Z) {
1138				if (val1_i == 0) {
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;
1144				} else {
1145					negotiated_i = val1_i;
1146				}
1147			} else {
1148				if (val1_i > val2_i) {
1149					negotiated_i = val2_i;
1150				} else {
1151					negotiated_i = val1_i;
1152				}
1153			}
1154			(void) snprintf(param->negotiated, sizeof(param->negotiated), "%d", negotiated_i);
1155			break;
1156		case ISCSI_PARAM_TYPE_LIST:
1157			if (outgoing) {
1158				if (param->tx_offer) {
1159					iscsi_err(__FILE__, __LINE__, "we should not be here\n");	/* error - we're sending
1160										 * an offer */
1161					PTP_ERROR;
1162				} else if (param->tx_answer) {
1163					(void) strlcpy(val1, param->answer_tx, ISCSI_PARAM_MAX_LEN);	/* we're sending an
1164									 * answer */
1165				} else {
1166					iscsi_err(__FILE__, __LINE__, "unexpected error\n");
1167					PTP_ERROR;
1168				}
1169			} else {
1170				if (param->rx_offer) {
1171					iscsi_err(__FILE__, __LINE__, "we should not be here\n");	/* error - we received
1172										 * an offer */
1173					PTP_ERROR;
1174				} else if (param->rx_answer) {
1175					(void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN);	/* we received an answer */
1176				} else {
1177					iscsi_err(__FILE__, __LINE__, "unexpected error\n");
1178					PTP_ERROR;
1179				}
1180			}
1181
1182			/* Make sure incoming or outgoing answer is valid */
1183			/*
1184			 * None, Reject, Irrelevant and NotUnderstood are
1185			 * valid
1186			 */
1187			if ((strcmp(val1, "None") == 0) || (strcmp(val1, "Reject") == 0) ||
1188			    (strcmp(val1, "Irrelevant") == 0) || (strcmp(val1, "NotUnderstood") == 0)) {
1189				goto value_ok;
1190			}
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;
1196					} else {
1197						(void) strlcpy(valid, p3, ISCSI_PARAM_MAX_LEN);
1198					}
1199					if (strcmp(valid, val1) == 0) {
1200						goto value_ok;
1201					}
1202				}
1203			} else {
1204				iscsi_trace(TRACE_ISCSI_PARAM, "Valid list empty??\n");
1205				PTP_ERROR;
1206			}
1207			iscsi_err(__FILE__, __LINE__, "\"%s\" is not a valid value (must choose from \"%s\")\n", val1, param->valid);
1208			PTP_ERROR;
1209value_ok:
1210			(void) strlcpy(param->negotiated, val1, sizeof(param->negotiated));
1211			break;
1212		}
1213
1214		iscsi_trace(TRACE_ISCSI_PARAM, "negotiated \"%s\"=\"%s\"\n", param->key, param->negotiated);
1215
1216		/* For inquiries, we don't commit the value. */
1217
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);
1221			goto next;
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);
1225			goto next;
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);
1229			goto next;
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);
1233			goto next;
1234		}
1235		iscsi_trace(TRACE_ISCSI_PARAM, "automatically committing \"%s\"=\"%s\"\n", param->key, param->negotiated);
1236
1237		c = param->negotiated[19];
1238		param->negotiated[19] = 0x0;
1239#if ISCSI_DEBUG
1240		printf("* %25s:%20s *\n", param->key, param->negotiated);
1241#endif
1242		param->negotiated[19] = c;
1243
1244		if (param->reset) {
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");
1248				PTP_ERROR;
1249			}
1250			param->reset = 0;
1251		}
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) {
1255				}
1256				if ((item_ptr->next = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) {
1257					iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
1258					PTP_ERROR;
1259				}
1260				item_ptr = item_ptr->next;
1261				item_ptr->next = NULL;
1262			} else {
1263				item_ptr = param->value_l;
1264			}
1265		} else {
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");
1269				PTP_ERROR;
1270			}
1271			item_ptr = param->value_l;
1272			item_ptr->next = NULL;
1273		}
1274		(void) strlcpy(item_ptr->value, param->negotiated, sizeof(item_ptr->value));
1275next:
1276		continue;
1277	}
1278	if (!outgoing) {
1279		iscsi_trace(TRACE_ISCSI_PARAM, "generated %d bytes response\n", *text_len_out);
1280	}
1281#if ISCSI_DEBUG
1282	printf("**************************************************\n");
1283#endif
1284
1285	PTP_CLEANUP;
1286	return 0;
1287}
1288
1289void
1290set_session_parameters(iscsi_parameter_t * head,
1291		       iscsi_sess_param_t * sess_params)
1292{
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"));
1304}
1305