xref: /netbsd-src/external/bsd/iscsi/dist/src/lib/parameters.c (revision 31a77d8abb0a624ecf702bd9799d92e4be2e52ee)
1b6364952Sagc /*
2b6364952Sagc  * IMPORTANT:  READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
3b6364952Sagc  * By downloading, copying, installing or using the software you agree
4b6364952Sagc  * to this license.  If you do not agree to this license, do not
5b6364952Sagc  * download, install, copy or use the software.
6b6364952Sagc  *
7b6364952Sagc  * Intel License Agreement
8b6364952Sagc  *
9b6364952Sagc  * Copyright (c) 2000, Intel Corporation
10b6364952Sagc  * All rights reserved.
11b6364952Sagc  *
12b6364952Sagc  * Redistribution and use in source and binary forms, with or without
13b6364952Sagc  * modification, are permitted provided that the following conditions
14b6364952Sagc  * are met:
15b6364952Sagc  *
16b6364952Sagc  * -Redistributions of source code must retain the above copyright
17b6364952Sagc  *  notice, this list of conditions and the following disclaimer.
18b6364952Sagc  *
19b6364952Sagc  * -Redistributions in binary form must reproduce the above copyright
20b6364952Sagc  *  notice, this list of conditions and the following disclaimer in the
21b6364952Sagc  *  documentation and/or other materials provided with the
22b6364952Sagc  *  distribution.
23b6364952Sagc  *
24b6364952Sagc  * -The name of Intel Corporation may not be used to endorse or
25b6364952Sagc  *  promote products derived from this software without specific prior
26b6364952Sagc  *  written permission.
27b6364952Sagc  *
28b6364952Sagc  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29b6364952Sagc  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30b6364952Sagc  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31b6364952Sagc  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL INTEL
32b6364952Sagc  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33b6364952Sagc  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34b6364952Sagc  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
35b6364952Sagc  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
36b6364952Sagc  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37b6364952Sagc  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38b6364952Sagc  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39b6364952Sagc  * SUCH DAMAGE.
40b6364952Sagc  */
41b6364952Sagc #include "config.h"
42b6364952Sagc #include "compat.h"
43b6364952Sagc 
44b6364952Sagc #ifdef HAVE_CTYPE_H
45b6364952Sagc #include <ctype.h>
46b6364952Sagc #endif
47b6364952Sagc 
48b6364952Sagc #include <stdio.h>
49b6364952Sagc #include <stdlib.h>
50b6364952Sagc 
51b6364952Sagc #ifdef HAVE_STRING_H
52b6364952Sagc #include <string.h>
53b6364952Sagc #endif
54b6364952Sagc 
55b6364952Sagc #ifdef HAVE_NETINET_IN_H
56b6364952Sagc #include <netinet/in.h>
57b6364952Sagc #endif
58b6364952Sagc 
59b6364952Sagc #include "iscsi-md5.h"
60b6364952Sagc #include "iscsiutil.h"
61b6364952Sagc #include "parameters.h"
62b6364952Sagc #include "conffile.h"
63b6364952Sagc 
64b6364952Sagc 
65b6364952Sagc int
param_list_add(iscsi_parameter_t ** head,int type,const char * key,const char * dflt,const char * valid)66b6364952Sagc param_list_add(iscsi_parameter_t ** head, int type, const char *key, const char *dflt, const char *valid)
67b6364952Sagc {
68b6364952Sagc 	iscsi_parameter_t *param;
69b6364952Sagc 
70b6364952Sagc 	/* Allocated new parameter type */
71b6364952Sagc 
72b6364952Sagc 	if (*head == NULL) {
73b6364952Sagc 		if ((*head = iscsi_malloc_atomic(sizeof(iscsi_parameter_t))) == NULL) {
745e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "out of memory\n");
75b6364952Sagc 			return -1;
76b6364952Sagc 		}
77b6364952Sagc 		param = *head;
78b6364952Sagc 	} else {
79b6364952Sagc 		for (param = *head; param->next != NULL; param = param->next) {
80b6364952Sagc 		}
81b6364952Sagc 		if ((param->next = iscsi_malloc_atomic(sizeof(iscsi_parameter_t))) == NULL) {
825e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "out of memory\n");
83b6364952Sagc 			return -1;
84b6364952Sagc 		}
85b6364952Sagc 		param = param->next;
86b6364952Sagc 	}
87b6364952Sagc 
88b6364952Sagc 	/* Initilized parameter */
89b6364952Sagc 
90b6364952Sagc 	param->type = type;	/* type */
91b6364952Sagc 	(void) strlcpy(param->key, key, sizeof(param->key));/* key */
92b6364952Sagc 	(void) strlcpy(param->dflt, dflt, sizeof(param->dflt));	/* default value */
93b6364952Sagc 	(void) strlcpy(param->valid, valid, sizeof(param->valid));	/* list of valid values */
94b6364952Sagc 	param->tx_offer = 0;	/* sent offer */
95b6364952Sagc 	param->rx_offer = 0;	/* received offer */
96b6364952Sagc 	param->tx_answer = 0;	/* sent answer */
97b6364952Sagc 	param->rx_answer = 0;	/* received answer */
98b6364952Sagc 	param->reset = 0;	/* used to erase value_l on next parse */
99b6364952Sagc 	param->next = NULL;	/* terminate list */
100b6364952Sagc 
101b6364952Sagc 	/* Allocated space for value list and set first item to default; and */
102b6364952Sagc 	/* set offer and answer lists to NULL */
103b6364952Sagc 
104b6364952Sagc 	if ((param->value_l = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) {
1055e01dafbSagc 		iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
106b6364952Sagc 		return -1;
107b6364952Sagc 	}
108b6364952Sagc 	param->value_l->next = NULL;
109b6364952Sagc 	(void) strlcpy(param->value_l->value, dflt, sizeof(param->value_l->value));
110b6364952Sagc 
111b6364952Sagc 	/* Arg check */
112b6364952Sagc 
113b6364952Sagc 	switch (type) {
114b6364952Sagc 	case ISCSI_PARAM_TYPE_DECLARATIVE:
115b6364952Sagc 		break;
116b6364952Sagc 	case ISCSI_PARAM_TYPE_DECLARE_MULTI:
117b6364952Sagc 		break;
118b6364952Sagc 	case ISCSI_PARAM_TYPE_BINARY_OR:
119b6364952Sagc 		if (strcmp(valid, "Yes,No") != 0 &&
120b6364952Sagc 		    strcmp(valid, "No,Yes") != 0 &&
121b6364952Sagc 		    strcmp(valid, "No") != 0 &&
122b6364952Sagc 		    strcmp(valid, "Yes") != 0 &&
123b6364952Sagc 		    strcmp(valid, "yes,no") != 0 &&
124b6364952Sagc 		    strcmp(valid, "no,yes") != 0 &&
125b6364952Sagc 		    strcmp(valid, "no") != 0 &&
126b6364952Sagc 		    strcmp(valid, "yes") != 0) {
1275e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "bad <valid> field \"%s\" for ISCSI_PARAM_TYPE_BINARY\n", valid);
128b6364952Sagc 			return -1;
129b6364952Sagc 		}
130b6364952Sagc 		break;
131b6364952Sagc 	case ISCSI_PARAM_TYPE_BINARY_AND:
132b6364952Sagc 		if (strcmp(valid, "Yes,No") != 0 &&
133b6364952Sagc 		    strcmp(valid, "No,Yes") != 0 &&
134b6364952Sagc 		    strcmp(valid, "No") != 0 &&
135b6364952Sagc 		    strcmp(valid, "Yes") != 0 &&
136b6364952Sagc 		    strcmp(valid, "yes,no") != 0 &&
137b6364952Sagc 		    strcmp(valid, "no,yes") != 0 &&
138b6364952Sagc 		    strcmp(valid, "no") != 0 &&
139b6364952Sagc 		    strcmp(valid, "yes") != 0) {
1405e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "bad <valid> field \"%s\" for ISCSI_PARAM_TYPE_BINARY\n", valid);
141b6364952Sagc 			return -1;
142b6364952Sagc 		}
143b6364952Sagc 		break;
144b6364952Sagc 	case ISCSI_PARAM_TYPE_NUMERICAL:
145b6364952Sagc 		break;
146b6364952Sagc 	case ISCSI_PARAM_TYPE_NUMERICAL_Z:
147b6364952Sagc 		break;
148b6364952Sagc 	case ISCSI_PARAM_TYPE_LIST:
149b6364952Sagc 		break;
150b6364952Sagc 	default:
1515e01dafbSagc 		iscsi_err(__FILE__, __LINE__, "unknown parameter type %d\n", type);
152b6364952Sagc 		return -1;
153b6364952Sagc 	}
154b6364952Sagc 
1555e01dafbSagc 	iscsi_trace(TRACE_ISCSI_PARAM, "\"%s\": valid \"%s\", default \"%s\", current \"%s\"\n",
156b6364952Sagc 	      param->key, param->valid, param->dflt, param->value_l->value);
157b6364952Sagc 		return 0;
158b6364952Sagc }
159b6364952Sagc 
160b6364952Sagc int
param_list_destroy(iscsi_parameter_t * head)161b6364952Sagc param_list_destroy(iscsi_parameter_t * head)
162b6364952Sagc {
163b6364952Sagc 	iscsi_parameter_t *ptr, *tmp;
164b6364952Sagc 	iscsi_parameter_value_t *item_ptr, *next;
165b6364952Sagc 
166b6364952Sagc 	for (ptr = head; ptr != NULL;) {
167b6364952Sagc 		tmp = ptr;
168b6364952Sagc 		ptr = ptr->next;
169b6364952Sagc 		if (tmp->value_l) {
170b6364952Sagc 			for (item_ptr = tmp->value_l; item_ptr != NULL; item_ptr = next) {
171b6364952Sagc 				next = item_ptr->next;
172b6364952Sagc 				/*
1735e01dafbSagc 				 * iscsi_trace(TRACE_ISCSI_PARAM, "freeing \"%s\"
174b6364952Sagc 				 * (%p)\n", item_ptr->value, item_ptr);
175b6364952Sagc 				 */
176b6364952Sagc 				iscsi_free_atomic(item_ptr);
177b6364952Sagc 			}
178b6364952Sagc 		}
1795e01dafbSagc 		/* iscsi_trace(TRACE_ISCSI_PARAM, "freeing %p\n", tmp); */
180b6364952Sagc 		iscsi_free_atomic(tmp);
181b6364952Sagc 	}
182b6364952Sagc 	return 0;
183b6364952Sagc }
184b6364952Sagc 
185b6364952Sagc 
186b6364952Sagc iscsi_parameter_t *
param_get(iscsi_parameter_t * head,const char * key)187b6364952Sagc param_get(iscsi_parameter_t * head, const char *key)
188b6364952Sagc {
189b6364952Sagc 	iscsi_parameter_t *ptr;
190b6364952Sagc 
191b6364952Sagc 	for (ptr = head; ptr != NULL; ptr = ptr->next) {
192b6364952Sagc 		if (strcmp(ptr->key, key) == 0) {
193b6364952Sagc 			return ptr;
194b6364952Sagc 		}
195b6364952Sagc 	}
1965e01dafbSagc 	iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
197b6364952Sagc 	return NULL;
198b6364952Sagc }
199b6364952Sagc 
200b6364952Sagc char           *
param_val(iscsi_parameter_t * head,const char * key)201b6364952Sagc param_val(iscsi_parameter_t * head, const char *key)
202b6364952Sagc {
203b6364952Sagc 	return param_val_which(head, key, 0);
204b6364952Sagc }
205b6364952Sagc 
206b6364952Sagc char           *
param_val_which(iscsi_parameter_t * head,const char * key,int which)207b6364952Sagc param_val_which(iscsi_parameter_t * head, const char *key, int which)
208b6364952Sagc {
209b6364952Sagc 	iscsi_parameter_t *ptr;
210b6364952Sagc 	iscsi_parameter_value_t *item_ptr;
211b6364952Sagc 	int             i = 0;
212b6364952Sagc 
213b6364952Sagc 	for (ptr = head; ptr != NULL; ptr = ptr->next) {
214b6364952Sagc 		if (strcmp(ptr->key, key) == 0) {
215b6364952Sagc 			item_ptr = ptr->value_l;
216b6364952Sagc 			for (i = 0; i != which; i++) {
217b6364952Sagc 				if (item_ptr == NULL) {
2185e01dafbSagc 					iscsi_err(__FILE__, __LINE__, "item %d in value list is NULL\n", i);
219b6364952Sagc 					return NULL;
220b6364952Sagc 				}
221b6364952Sagc 				item_ptr = item_ptr->next;
222b6364952Sagc 			}
223b6364952Sagc 			if (item_ptr == NULL) {
2245e01dafbSagc 				iscsi_err(__FILE__, __LINE__, "item %d in value list is NULL\n", which);
225b6364952Sagc 				return NULL;
226b6364952Sagc 			}
227b6364952Sagc 			return item_ptr->value;
228b6364952Sagc 		}
229b6364952Sagc 	}
2305e01dafbSagc 	iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
231b6364952Sagc 	return NULL;
232b6364952Sagc }
233b6364952Sagc 
234b6364952Sagc static int
param_val_delete_all(iscsi_parameter_t * head,char * key)235b6364952Sagc param_val_delete_all(iscsi_parameter_t * head, char *key)
236b6364952Sagc {
237b6364952Sagc 	iscsi_parameter_t *ptr;
238b6364952Sagc 	iscsi_parameter_value_t *item_ptr, *next;
239b6364952Sagc 
240b6364952Sagc 	for (ptr = head; ptr != NULL; ptr = ptr->next) {
241b6364952Sagc 		if (strcmp(ptr->key, key) == 0) {
242b6364952Sagc 			for (item_ptr = ptr->value_l; item_ptr != NULL; item_ptr = next) {
243b6364952Sagc 				next = item_ptr->next;
244b6364952Sagc 				iscsi_free_atomic(item_ptr);
245b6364952Sagc 			}
246b6364952Sagc 			ptr->value_l = NULL;
247b6364952Sagc 			return 0;
248b6364952Sagc 		}
249b6364952Sagc 	}
2505e01dafbSagc 	iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
251b6364952Sagc 	return -1;
252b6364952Sagc }
253b6364952Sagc 
254b6364952Sagc int
param_val_reset(iscsi_parameter_t * head,const char * key)255b6364952Sagc param_val_reset(iscsi_parameter_t * head, const char *key)
256b6364952Sagc {
257b6364952Sagc 	iscsi_parameter_t *ptr;
258b6364952Sagc 
259b6364952Sagc 	for (ptr = head; ptr != NULL; ptr = ptr->next) {
260b6364952Sagc 		if (strcmp(ptr->key, key) == 0) {
261b6364952Sagc 			ptr->reset = 1;
262b6364952Sagc 			return 0;
263b6364952Sagc 		}
264b6364952Sagc 	}
2655e01dafbSagc 	iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
266b6364952Sagc 	return -1;
267b6364952Sagc }
268b6364952Sagc 
269b6364952Sagc int
param_atoi(iscsi_parameter_t * head,const char * key)270b6364952Sagc param_atoi(iscsi_parameter_t * head, const char *key)
271b6364952Sagc {
272b6364952Sagc 	iscsi_parameter_t *ptr;
273b6364952Sagc 	char           *value;
274b6364952Sagc 
275b6364952Sagc 	for (ptr = head; ptr != NULL; ptr = ptr->next) {
276b6364952Sagc 		if (strcmp(ptr->key, key) == 0) {
277b6364952Sagc 			if (ptr->value_l) {
278b6364952Sagc 				if ((value = param_val(head, key)) != NULL) {
279b6364952Sagc 					return iscsi_atoi(value);
280b6364952Sagc 				} else {
2815e01dafbSagc 					iscsi_err(__FILE__, __LINE__, "value is NULL\n");
282b6364952Sagc 					return 0;
283b6364952Sagc 				}
284b6364952Sagc 			} else {
2855e01dafbSagc 				iscsi_err(__FILE__, __LINE__, "param \"%s\" has NULL value list\n", key);
286b6364952Sagc 				return 0;
287b6364952Sagc 			}
288b6364952Sagc 		}
289b6364952Sagc 	}
2905e01dafbSagc 	iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
291b6364952Sagc 	return 0;
292b6364952Sagc }
293b6364952Sagc 
294b6364952Sagc int
param_equiv(iscsi_parameter_t * head,const char * key,const char * val)295b6364952Sagc param_equiv(iscsi_parameter_t * head, const char *key, const char *val)
296b6364952Sagc {
297b6364952Sagc 	iscsi_parameter_t *ptr;
298b6364952Sagc 	char           *value;
299b6364952Sagc 
300b6364952Sagc 	for (ptr = head; ptr != NULL; ptr = ptr->next) {
301b6364952Sagc 		if (strcmp(ptr->key, key) == 0) {
302b6364952Sagc 			if (ptr->value_l == NULL) {
3035e01dafbSagc 				iscsi_err(__FILE__, __LINE__, "param \"%s\" has NULL value list\n", key);
304b6364952Sagc 				return 0;
305b6364952Sagc 			}
306b6364952Sagc 			if ((value = param_val(head, key)) == NULL) {
3075e01dafbSagc 				iscsi_err(__FILE__, __LINE__, "key \"%s\" value is NULL\n", key);
308b6364952Sagc 				return 0;
309b6364952Sagc 			}
310b6364952Sagc 			return (strcmp(value, val) == 0);
311b6364952Sagc 		}
312b6364952Sagc 	}
3135e01dafbSagc 	iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
314b6364952Sagc 	return -1;
315b6364952Sagc }
316b6364952Sagc 
317b6364952Sagc int
param_num_vals(iscsi_parameter_t * head,char * key)318b6364952Sagc param_num_vals(iscsi_parameter_t * head, char *key)
319b6364952Sagc {
320b6364952Sagc 	iscsi_parameter_t *ptr;
321b6364952Sagc 	iscsi_parameter_value_t *item_ptr;
322b6364952Sagc 	int             num = 0;
323b6364952Sagc 
324b6364952Sagc 	for (ptr = head; ptr != NULL; ptr = ptr->next) {
325b6364952Sagc 		if (strcmp(ptr->key, key) == 0) {
326b6364952Sagc 			for (item_ptr = ptr->value_l; item_ptr != NULL; item_ptr = item_ptr->next) {
327b6364952Sagc 				num++;
328b6364952Sagc 			}
329b6364952Sagc 			return num;
330b6364952Sagc 		}
331b6364952Sagc 	}
3325e01dafbSagc 	iscsi_err(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key);
333b6364952Sagc 	return -1;
334b6364952Sagc }
335b6364952Sagc 
336b6364952Sagc int
param_list_print(iscsi_parameter_t * head)337b6364952Sagc param_list_print(iscsi_parameter_t * head)
338b6364952Sagc {
339b6364952Sagc 	iscsi_parameter_t *ptr;
340b6364952Sagc 	iscsi_parameter_value_t *item_ptr;
341b6364952Sagc 
342b6364952Sagc 	for (ptr = head; ptr != NULL; ptr = ptr->next) {
343b6364952Sagc 		for (item_ptr = ptr->value_l; item_ptr != NULL; item_ptr = item_ptr->next) {
344b6364952Sagc 			printf("\"%s\"=\"%s\"\n", ptr->key, item_ptr->value);
345b6364952Sagc 		}
346b6364952Sagc 	}
347b6364952Sagc 	return 0;
348b6364952Sagc }
349b6364952Sagc 
350b6364952Sagc int
param_text_print(char * text,uint32_t text_len)351b6364952Sagc param_text_print(char *text, uint32_t text_len)
352b6364952Sagc {
353b6364952Sagc 	char            key[256];
354b6364952Sagc 	char           *ptr, *eq, *value;
355b6364952Sagc 
356b6364952Sagc 	for (ptr = text; (uint32_t)(ptr - text) < text_len; ptr += (strlen(ptr) + 1)) {
357b6364952Sagc 
358b6364952Sagc 		/* Skip over any NULLs */
359b6364952Sagc 
360b6364952Sagc 		while (!(*ptr) && ((uint32_t)(ptr - text) < text_len))
361b6364952Sagc 			ptr++;
362b6364952Sagc 		if ((uint32_t)(ptr - text) >= text_len)
363b6364952Sagc 			break;
364b6364952Sagc 
365b6364952Sagc 		if ((eq = strchr(ptr, '=')) == NULL) {
3665e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "delimiter \'=\' not found in token \"%s\"\n", ptr);
367b6364952Sagc 			return -1;
368b6364952Sagc 		}
369b6364952Sagc 		strncpy(key, ptr, (unsigned)(eq - ptr));
370b6364952Sagc 		key[(int)(eq - ptr)] = 0x0;
371b6364952Sagc 		value = eq + 1;
372b6364952Sagc 		printf("\"%s\"=\"%s\"\n", key, value);
373b6364952Sagc 	}
374b6364952Sagc 	return 0;
375b6364952Sagc }
376b6364952Sagc 
377b6364952Sagc /* ARGSUSED */
378b6364952Sagc int
param_text_add(iscsi_parameter_t * head,const char * key,const char * value,char * text,int * len,int size,int offer)379b6364952Sagc param_text_add(iscsi_parameter_t * head, const char *key, const char *value, char *text, int *len, int size, int offer)
380b6364952Sagc {
381b6364952Sagc 	int	cc;
382b6364952Sagc 
383b6364952Sagc 	cc = snprintf(text + *len, (unsigned)(size - *len), "%s=%s", key, value);
384b6364952Sagc 	*len += cc + 1;
385b6364952Sagc 	return 0;
386b6364952Sagc }
387b6364952Sagc 
388b6364952Sagc int
driver_atoi(const char * s)389b6364952Sagc driver_atoi(const char *s)
390b6364952Sagc {
391b6364952Sagc 	int             k = 0;
392b6364952Sagc 
393b6364952Sagc 	while (*s != 0x0 && *s >= '0' && *s <= '9') {
394b6364952Sagc 		k = 10 * k + (*s - '0');
395b6364952Sagc 		s++;
396b6364952Sagc 	}
397b6364952Sagc 	return k;
398b6364952Sagc }
399b6364952Sagc 
400b6364952Sagc /* find the credentials for `user' and put them in `cred' */
401b6364952Sagc static int
find_credentials(iscsi_cred_t * cred,char * user,const char * auth)402b6364952Sagc find_credentials(iscsi_cred_t *cred, char *user, const char *auth)
403b6364952Sagc {
404b6364952Sagc 	conffile_t	 conf;
405b6364952Sagc 	const char	*authtype;
406b6364952Sagc 	unsigned	 cc;
407b6364952Sagc 	ent_t	 	 e;
408b6364952Sagc 
409b6364952Sagc 	(void) memset(&conf, 0x0, sizeof(conf));
410b6364952Sagc 	(void) memset(&e, 0x0, sizeof(e));
411b6364952Sagc 
412b6364952Sagc 	if (!conffile_open(&conf, _PATH_ISCSI_PASSWD, "r", ":", "#")) {
4135e01dafbSagc 		iscsi_err(__FILE__, __LINE__, "can't open `%s'\n", _PATH_ISCSI_PASSWD);
414b6364952Sagc 		exit(EXIT_FAILURE);
415b6364952Sagc 	}
416b6364952Sagc 	while (conffile_getent(&conf, &e)) {
417b6364952Sagc 		if (strcasecmp(e.sv.v[0], user) == 0) {
418b6364952Sagc 			authtype = (e.sv.c == 1) ? "none" : e.sv.v[1];
419b6364952Sagc 			cc = strlen(authtype);
420b6364952Sagc 			if (auth == NULL || (strncasecmp(authtype, auth, cc) == 0 && cc == strlen(auth))) {
421b6364952Sagc 				cred->user = strdup(e.sv.v[0]);
422b6364952Sagc 				cred->auth_type = strdup(authtype);
423b6364952Sagc 				cred->shared_secret = (e.sv.c == 3) ? strdup(e.sv.v[2]) : NULL;
424b6364952Sagc 				conffile_close(&conf);
425b6364952Sagc 				return 1;
426b6364952Sagc 			}
427b6364952Sagc 		}
428b6364952Sagc 	}
429b6364952Sagc 	conffile_close(&conf);
430b6364952Sagc 	(void) fprintf(stderr, "No matching user configuration entry for `%s' was found\n", user);
431b6364952Sagc 	(void) fprintf(stderr, "Please add an entry for `%s' to `%s'\n", user, _PATH_ISCSI_PASSWD);
432b6364952Sagc 	return 0;
433b6364952Sagc }
434b6364952Sagc 
435b6364952Sagc #if 0
436b6364952Sagc /* free any storage allocated in `cred' */
437b6364952Sagc static void
438b6364952Sagc free_cred(iscsi_cred_t *cred)
439b6364952Sagc {
440b6364952Sagc 	if (cred) {
441b6364952Sagc 		if (cred->user) {
442b6364952Sagc 			iscsi_free_atomic(cred->user);
443b6364952Sagc 		}
444b6364952Sagc 		if (cred->auth_type) {
445b6364952Sagc 			iscsi_free_atomic(cred->auth_type);
446b6364952Sagc 		}
447b6364952Sagc 		if (cred->shared_secret) {
448b6364952Sagc 			iscsi_free_atomic(cred->shared_secret);
449b6364952Sagc 		}
450b6364952Sagc 	}
451b6364952Sagc }
452b6364952Sagc #endif
453b6364952Sagc 
454b6364952Sagc /* Security offering and check */
455b6364952Sagc /*
456b6364952Sagc  * ret values: =0: succeed or no security >0: security negotiation in process
457b6364952Sagc  * <0: failed
458b6364952Sagc  */
459b6364952Sagc 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)460b6364952Sagc param_parse_security(iscsi_parameter_t * head,
461b6364952Sagc 		     iscsi_parameter_t * param_in,
462b6364952Sagc 		     iscsi_cred_t *cred,
463b6364952Sagc 		     char *text_out, int *text_len_out, int textsize)
464b6364952Sagc {
465b6364952Sagc 
466b6364952Sagc 	static uint8_t idData;
467b6364952Sagc 	static uint8_t chapdata[ISCSI_CHAP_DATA_LENGTH];
468b6364952Sagc 	static uint8_t respdata[ISCSI_CHAP_DATA_LENGTH];
469b6364952Sagc 	char           *chapstring = NULL;
470b6364952Sagc 	iSCSI_MD5_CTX   *context = NULL;
471b6364952Sagc 	iscsi_parameter_t *param = NULL;
472b6364952Sagc 	int             ret = 1;
473b6364952Sagc 
474b6364952Sagc 	if ((chapstring = iscsi_malloc(ISCSI_CHAP_STRING_LENGTH)) == NULL) {
4755e01dafbSagc 		iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
476b6364952Sagc 		return -1;
477b6364952Sagc 	}
478b6364952Sagc 	if ((context = iscsi_malloc(sizeof(*context))) == NULL) {
4795e01dafbSagc 		iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
480b6364952Sagc 		if (chapstring != NULL)
481b6364952Sagc 			iscsi_free(chapstring);
482b6364952Sagc 		return -1;
483b6364952Sagc 	}
484b6364952Sagc #define PPS_CLEANUP { if (chapstring != NULL) iscsi_free(chapstring);if (context != NULL) iscsi_free(context); }
485b6364952Sagc #define PPS_ERROR { PPS_CLEANUP; return (-1); };
486b6364952Sagc 
487b6364952Sagc 	if (strcmp(param_in->key, "AuthMethod") == 0) {
488b6364952Sagc 		if (param_in->rx_answer && strcmp(param_in->answer_rx, "None") == 0) {
489b6364952Sagc 			PPS_CLEANUP;
490b6364952Sagc 			return 0;	/* Proposed None for
491b6364952Sagc 					 * Authentication */
492b6364952Sagc 		}
493b6364952Sagc 		if (param_in->rx_offer && strcmp(param_in->offer_rx, "None") == 0) {
494b6364952Sagc 			PPS_CLEANUP;
495b6364952Sagc 			return 0;
496b6364952Sagc 		}
497b6364952Sagc 		if (!param_in->rx_offer) {
498b6364952Sagc 			param = param_get(head, "CHAP_A");
499b6364952Sagc 			if (param == NULL)
500b6364952Sagc 				PPS_ERROR;
501b6364952Sagc 			param->tx_offer = 1;	/* sending an offer */
502b6364952Sagc 			param->rx_offer = 0;	/* reset */
503b6364952Sagc 			(void) strlcpy(param->offer_tx, param->valid, sizeof(param->offer_tx));
504b6364952Sagc 			PARAM_TEXT_ADD(head, param->key, param->valid,
505b6364952Sagc 				      text_out, text_len_out, textsize, 0, PPS_ERROR);
506b6364952Sagc 			ret++;
507b6364952Sagc 		}
508b6364952Sagc 	} else if (strcmp(param_in->key, "CHAP_A") == 0) {
509b6364952Sagc 		if (param_in->rx_offer) {
510b6364952Sagc 			PARAM_TEXT_ADD(head, param_in->key, param_in->offer_rx,
511b6364952Sagc 				      text_out, text_len_out, textsize, 0, PPS_ERROR);
512b6364952Sagc 
513b6364952Sagc 			if ((param = param_get(head, "CHAP_I")) == NULL) {
514b6364952Sagc 				PPS_ERROR;
515b6364952Sagc 			}
516b6364952Sagc 			param->tx_offer = 1;	/* sending an offer */
517b6364952Sagc 			param->rx_offer = 0;	/* reset */
518b6364952Sagc 			GenRandomData(&idData, 1);
519b6364952Sagc 			(void) snprintf(chapstring, ISCSI_CHAP_STRING_LENGTH, "%d", idData);
520b6364952Sagc 			(void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx));
521b6364952Sagc 			PARAM_TEXT_ADD(head, param->key, param->offer_tx,
522b6364952Sagc 				      text_out, text_len_out, textsize, 0, PPS_ERROR);
523b6364952Sagc 
524b6364952Sagc 			if ((param = param_get(head, "CHAP_C")) == NULL) {
525b6364952Sagc 				PPS_ERROR;
526b6364952Sagc 			}
527b6364952Sagc 			param->tx_offer = 1;	/* sending an offer */
528b6364952Sagc 			param->rx_offer = 0;	/* reset */
529b6364952Sagc 			GenRandomData(chapdata, ISCSI_CHAP_DATA_LENGTH);
530b6364952Sagc 			HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
531b6364952Sagc 				      chapstring, ISCSI_CHAP_STRING_LENGTH);
532b6364952Sagc 			(void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx));
533b6364952Sagc 			PARAM_TEXT_ADD(head, param->key, param->offer_tx,
534b6364952Sagc 				      text_out, text_len_out, textsize, 0, PPS_ERROR);
535b6364952Sagc 			ret++;
536b6364952Sagc 		}
537b6364952Sagc 	} else if (strcmp(param_in->key, "CHAP_I") == 0) {
538b6364952Sagc 
539b6364952Sagc 		idData = driver_atoi((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx);
540b6364952Sagc 		ret++;
541b6364952Sagc 
542b6364952Sagc 	} else if (strcmp(param_in->key, "CHAP_C") == 0) {
543b6364952Sagc 
544b6364952Sagc 		HexTextToData((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx, ISCSI_CHAP_STRING_LENGTH,
545b6364952Sagc 				      chapdata, ISCSI_CHAP_DATA_LENGTH);
546b6364952Sagc 
547b6364952Sagc 		if ((param = param_get(head, "CHAP_N")) == NULL) {
548b6364952Sagc 			PPS_ERROR;
549b6364952Sagc 		}
550b6364952Sagc 		param->tx_offer = 1;	/* sending an offer */
551b6364952Sagc 		param->rx_offer = 0;	/* reset */
552b6364952Sagc 
553b6364952Sagc 		if (cred->shared_secret == NULL && !find_credentials(cred, cred->user, "chap")) {
5545e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "Unknown user `%s'\n", param_in->offer_rx);
555b6364952Sagc 			PPS_ERROR;
556b6364952Sagc 		}
557b6364952Sagc 
558b6364952Sagc 		if (cred->user) {
559b6364952Sagc 			(void) strlcpy(param->offer_tx, cred->user, sizeof(param->offer_tx));
560b6364952Sagc 		} else {
5615e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "no valid user credentials\n");
562b6364952Sagc 			PPS_ERROR;
563b6364952Sagc 		}
564b6364952Sagc 
565b6364952Sagc 		PARAM_TEXT_ADD(head, param->key, param->offer_tx,
566b6364952Sagc 				    text_out, text_len_out, textsize, 0, PPS_ERROR);
567b6364952Sagc 
568b6364952Sagc 		if ((param = param_get(head, "CHAP_R")) == NULL) {
569b6364952Sagc 			PPS_ERROR;
570b6364952Sagc 		}
571b6364952Sagc 		param->tx_offer = 1;	/* sending an offer */
572b6364952Sagc 		param->rx_offer = 0;	/* reset */
573b6364952Sagc 		iSCSI_MD5Init(context);
574b6364952Sagc 		iSCSI_MD5Update(context, &idData, 1);
575b6364952Sagc 
576b6364952Sagc 		if (cred->shared_secret == NULL) {
5775e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "null shared secret\n");
578b6364952Sagc 			PPS_ERROR;
579b6364952Sagc 		} else {
580b6364952Sagc 			iSCSI_MD5Update(context, (const uint8_t *)cred->shared_secret, strlen(cred->shared_secret));
581b6364952Sagc 		}
582b6364952Sagc 
583b6364952Sagc 		HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
584b6364952Sagc 			      param->offer_tx, ISCSI_CHAP_STRING_LENGTH);
585b6364952Sagc 		iSCSI_MD5Update(context, chapdata, ISCSI_CHAP_DATA_LENGTH);
586b6364952Sagc 		iSCSI_MD5Final(chapdata, context);
587b6364952Sagc 		HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
588b6364952Sagc 			      param->offer_tx, ISCSI_CHAP_STRING_LENGTH);
589b6364952Sagc 
590b6364952Sagc 		PARAM_TEXT_ADD(head, param->key, param->offer_tx,
591b6364952Sagc 				    text_out, text_len_out, textsize, 0, PPS_ERROR);
592b6364952Sagc 
593b6364952Sagc 		if (param_in->rx_offer) {
594b6364952Sagc 
595b6364952Sagc 			if ((param = param_get(head, "CHAP_I")) == NULL) {
596b6364952Sagc 				PPS_ERROR;
597b6364952Sagc 			}
598b6364952Sagc 			param->tx_offer = 1;	/* sending an offer */
599b6364952Sagc 			param->rx_offer = 0;	/* reset */
600b6364952Sagc 			GenRandomData(&idData, 1);
601b6364952Sagc 			(void) snprintf(chapstring, ISCSI_CHAP_STRING_LENGTH, "%d", idData);
602b6364952Sagc 			(void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx));
603b6364952Sagc 			PARAM_TEXT_ADD(head, param->key, param->offer_tx,
604b6364952Sagc 				      text_out, text_len_out, textsize, 0, PPS_ERROR);
605b6364952Sagc 
606b6364952Sagc 			if ((param = param_get(head, "CHAP_C")) == NULL) {
607b6364952Sagc 				PPS_ERROR;
608b6364952Sagc 			}
609b6364952Sagc 			param->tx_offer = 1;	/* sending an offer */
610b6364952Sagc 			param->rx_offer = 0;	/* reset */
611b6364952Sagc 			GenRandomData(chapdata, ISCSI_CHAP_DATA_LENGTH);
612b6364952Sagc 			HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
613b6364952Sagc 				      chapstring, ISCSI_CHAP_STRING_LENGTH);
614b6364952Sagc 			(void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx));
615b6364952Sagc 			PARAM_TEXT_ADD(head, param->key, param->offer_tx,
616b6364952Sagc 				      text_out, text_len_out, textsize, 0, PPS_ERROR);
617b6364952Sagc 		}
618b6364952Sagc 		ret++;
619b6364952Sagc 
620b6364952Sagc 	} else if (strcmp(param_in->key, "CHAP_N") == 0) {
621b6364952Sagc 		char	*user;
622b6364952Sagc 
623b6364952Sagc 		user = (param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx;
624b6364952Sagc 		if (!find_credentials(cred, user, "chap")) {
6255e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "Unknown user `%s'\n", user);
626b6364952Sagc 			PPS_ERROR;
627b6364952Sagc 		}
628b6364952Sagc 		ret++;
629b6364952Sagc 
630b6364952Sagc 	} else if (strcmp(param_in->key, "CHAP_R") == 0) {
631b6364952Sagc 
632b6364952Sagc 		iSCSI_MD5Init(context);
633b6364952Sagc 
634b6364952Sagc 		iSCSI_MD5Update(context, &idData, 1);
635b6364952Sagc 
636b6364952Sagc 		HexDataToText(&idData, 1, param_in->offer_tx, ISCSI_CHAP_STRING_LENGTH);
637b6364952Sagc 		HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
638b6364952Sagc 			      chapstring, ISCSI_CHAP_STRING_LENGTH);
639b6364952Sagc 
640b6364952Sagc 		if (cred->shared_secret == NULL) {
6415e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "Null shared secret in initiator\n");
642b6364952Sagc 			PPS_ERROR;
643b6364952Sagc 		} else {
644b6364952Sagc 			iSCSI_MD5Update(context, (const uint8_t *)cred->shared_secret, strlen(cred->shared_secret));
645b6364952Sagc 		}
646b6364952Sagc 
647b6364952Sagc 		iSCSI_MD5Update(context, chapdata, ISCSI_CHAP_DATA_LENGTH);
648b6364952Sagc 		iSCSI_MD5Final(chapdata, context);
649b6364952Sagc 
650b6364952Sagc 		HexTextToData((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx, ISCSI_CHAP_STRING_LENGTH,
651b6364952Sagc 				      respdata, ISCSI_CHAP_DATA_LENGTH);
652b6364952Sagc 
653b6364952Sagc 		HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH,
654b6364952Sagc 			      param_in->offer_rx, ISCSI_CHAP_STRING_LENGTH);
655b6364952Sagc 
656b6364952Sagc 		if (memcmp(respdata, chapdata, ISCSI_CHAP_DATA_LENGTH) != 0) {
6575e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "Initiator authentication failed %x %x\n", *chapdata, *respdata);
658b6364952Sagc 			PPS_ERROR;
659b6364952Sagc 		} else {
660b6364952Sagc 			PPS_CLEANUP;
661b6364952Sagc 		}
662b6364952Sagc 		return 0;
663b6364952Sagc 	}
664b6364952Sagc 	PPS_CLEANUP;
665b6364952Sagc 	return (ret);
666b6364952Sagc }
667b6364952Sagc 
668b6364952Sagc 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)669b6364952Sagc param_text_parse(iscsi_parameter_t * head,
670b6364952Sagc 		 iscsi_cred_t *cred,
671b6364952Sagc 		 char *text_in, int text_len_in,
672b6364952Sagc 		 char *text_out, int *text_len_out,
673b6364952Sagc 		 int textsize,
674b6364952Sagc 		 int outgoing)
675b6364952Sagc {
676b6364952Sagc 	static char    *key = NULL;
677b6364952Sagc 	char           *value = NULL;
678b6364952Sagc 	char           *ptr, *eq;
679b6364952Sagc 	iscsi_parameter_t *param;
680b6364952Sagc 	iscsi_parameter_value_t *item_ptr;
681b6364952Sagc 	int             offer_i, answer_i, max_i, val1_i, val2_i, negotiated_i;
682b6364952Sagc 	char           *p1, *p2, *p3, *p4;
683b6364952Sagc 	char           *offer = NULL;
684b6364952Sagc 	char           *valid = NULL;
685b6364952Sagc 	char           *val1 = NULL;
686b6364952Sagc 	char           *val2 = NULL;
687b6364952Sagc 	char           *tmp_key = NULL;
688b6364952Sagc 	char            c;
689b6364952Sagc 	int             ret;
690b6364952Sagc 
691b6364952Sagc 	/*
692b6364952Sagc 	 * Whether incoming or outgoing, some of the params might be offers
693b6364952Sagc 	 * and some answers.  Incoming
694b6364952Sagc 	 */
695b6364952Sagc 	/*
696b6364952Sagc 	 * text has the potential for creating outgoing text - and this will
697b6364952Sagc 	 * happen when the incoming
698b6364952Sagc 	 */
699b6364952Sagc 	/* text has offers that need an answer. */
700b6364952Sagc 
7015e01dafbSagc 	iscsi_trace(TRACE_ISCSI_PARAM, "parsing %d %s bytes of text parameters\n", text_len_in, outgoing ? "outgoing" : "incoming");
702b6364952Sagc 
703b6364952Sagc 	if ((key = iscsi_malloc(ISCSI_PARAM_KEY_LEN)) == NULL) {
7045e01dafbSagc 		iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
705b6364952Sagc 		return -1;
706b6364952Sagc 	}
707b6364952Sagc 	if ((offer = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
7085e01dafbSagc 		iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
709b6364952Sagc 		if (key != NULL) {
710b6364952Sagc 			iscsi_free(key);
711b6364952Sagc 		}
712b6364952Sagc 		return -1;
713b6364952Sagc 	}
714b6364952Sagc 	if ((valid = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
7155e01dafbSagc 		iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
716b6364952Sagc 		if (key != NULL) {
717b6364952Sagc 			iscsi_free(key);
718b6364952Sagc 		}
719b6364952Sagc 		if (offer != NULL) {
720b6364952Sagc 			iscsi_free(offer);
721b6364952Sagc 		}
722b6364952Sagc 		return -1;
723b6364952Sagc 	}
724b6364952Sagc 	if ((val1 = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
7255e01dafbSagc 		iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
726b6364952Sagc 		if (key != NULL) {
727b6364952Sagc 			iscsi_free(key);
728b6364952Sagc 		}
729b6364952Sagc 		if (offer != NULL) {
730b6364952Sagc 			iscsi_free(offer);
731b6364952Sagc 		}
732b6364952Sagc 		if (valid != NULL) {
733b6364952Sagc 			iscsi_free(valid);
734b6364952Sagc 		}
735b6364952Sagc 		return -1;
736b6364952Sagc 	}
737b6364952Sagc 	if ((val2 = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) {
7385e01dafbSagc 		iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
739b6364952Sagc 		if (key != NULL) {
740b6364952Sagc 			iscsi_free(key);
741b6364952Sagc 		}
742b6364952Sagc 		if (offer != NULL) {
743b6364952Sagc 			iscsi_free(offer);
744b6364952Sagc 		}
745b6364952Sagc 		if (valid != NULL) {
746b6364952Sagc 			iscsi_free(valid);
747b6364952Sagc 		}
748b6364952Sagc 		if (val1 != NULL) {
749b6364952Sagc 			iscsi_free(val1);
750b6364952Sagc 		}
751b6364952Sagc 		return -1;
752b6364952Sagc 	}
753b6364952Sagc #define PTP_CLEANUP { if (key != NULL) iscsi_free(key);    \
754b6364952Sagc     if (offer != NULL) iscsi_free(offer);                    \
755b6364952Sagc     if (valid != NULL) iscsi_free(valid);                    \
756b6364952Sagc     if (val1 != NULL) iscsi_free(val1);                      \
757b6364952Sagc     if (val2 != NULL) iscsi_free(val2);						 \
758b6364952Sagc     if (tmp_key != NULL) iscsi_free(tmp_key); }
759b6364952Sagc #define PTP_ERROR {PTP_CLEANUP; return -1;}
760b6364952Sagc 
761b6364952Sagc 	if (!outgoing) {
762b6364952Sagc 		*text_len_out = 0;
763b6364952Sagc 	}
764b6364952Sagc 
765b6364952Sagc #if ISCSI_DEBUG
766b6364952Sagc 	printf("**************************************************\n");
767b6364952Sagc 	printf("*              PARAMETERS NEGOTIATED             *\n");
768b6364952Sagc 	printf("*                                                *\n");
769b6364952Sagc #endif
770b6364952Sagc 
771b6364952Sagc 	for (ptr = text_in; ptr - text_in < text_len_in; ptr += (strlen(ptr) + 1)) {
772b6364952Sagc 
773b6364952Sagc 		/* Skip over any NULLs */
774b6364952Sagc 
775b6364952Sagc 		while (!(*ptr) && ((ptr - text_in) < text_len_in)) {
776b6364952Sagc 			ptr++;
777b6364952Sagc 		}
778b6364952Sagc 		if ((ptr - text_in) >= text_len_in) {
779b6364952Sagc 			break;
780b6364952Sagc 		}
781b6364952Sagc 
782b6364952Sagc 		/* Extract <key>=<value> token from text_in */
783b6364952Sagc 
784b6364952Sagc 		if ((eq = strchr(ptr, '=')) == NULL) {
7855e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "delimiter \'=\' not found in token \"%s\"\n", ptr);
786b6364952Sagc 		} else {
787b6364952Sagc 			if ((int)(eq - ptr) >= (ISCSI_PARAM_KEY_LEN - 1)) {
788b6364952Sagc 				if (!outgoing) {
789b6364952Sagc 					tmp_key = iscsi_malloc((unsigned)(eq - ptr));
790b6364952Sagc 					if (tmp_key) {
791b6364952Sagc 						strncpy(tmp_key, ptr, (unsigned)(eq - ptr));
792b6364952Sagc 						tmp_key[(int)(eq - ptr)] = 0x0;
793b6364952Sagc 						/* Key not understood. */
794b6364952Sagc 						PARAM_TEXT_ADD(head, tmp_key, "NotUnderstood", text_out, text_len_out, textsize, 0, PTP_ERROR);
795b6364952Sagc 					}
796b6364952Sagc 				} else {
797b6364952Sagc 					printf("ignoring \"%s\"\n", key);
798b6364952Sagc 				}
799b6364952Sagc 				goto next;
800b6364952Sagc 			}
801b6364952Sagc 			strncpy(key, ptr, (unsigned)(eq - ptr));
802b6364952Sagc 			key[(int)(eq - ptr)] = 0x0;
803b6364952Sagc 			value = eq + 1;
804b6364952Sagc 		}
805b6364952Sagc 
806b6364952Sagc 		/* Find key in param list */
807b6364952Sagc 
808b6364952Sagc 		for (param = head; param != NULL; param = param->next) {
809b6364952Sagc 			if (strcmp(param->key, key) == 0) {
810b6364952Sagc 				break;
811b6364952Sagc 			}
812b6364952Sagc 		}
813b6364952Sagc 		if (param == NULL) {
814b6364952Sagc 			if (!outgoing) {
815b6364952Sagc 				/* Key not understood. */
816b6364952Sagc 				PARAM_TEXT_ADD(head, key, "NotUnderstood", text_out, text_len_out, textsize, 0, PTP_ERROR);
817b6364952Sagc 			} else {
818b6364952Sagc 				printf("ignoring \"%s\"\n", key);
819b6364952Sagc 			}
820b6364952Sagc 			goto next;
821b6364952Sagc 		}
8225e01dafbSagc 		if (strlen(value) > ISCSI_PARAM_MAX_LEN) {
8235e01dafbSagc 			iscsi_err(__FILE__, __LINE__,
824*93f9555bSjoerg 				"strlen(value) %zu\n", strlen(value));
8255e01dafbSagc 			PTP_CLEANUP;
8265e01dafbSagc 			return -1;
8275e01dafbSagc 		}
828b6364952Sagc 
829b6364952Sagc 		/* We're sending|receiving an offer|answer  */
830b6364952Sagc 		if (outgoing) {
831b6364952Sagc 			if (param->rx_offer) {
832b6364952Sagc 				param->tx_answer = 1;	/* sending an answer */
833b6364952Sagc 				param->rx_answer = 0; /* reset */
834b6364952Sagc 				param->tx_offer = 0; /* reset */
835b6364952Sagc 				param->rx_offer = 0; /* reset */
836b6364952Sagc 				(void) strlcpy(param->answer_tx, value, sizeof(param->answer_tx));
8375e01dafbSagc 				iscsi_trace(TRACE_ISCSI_PARAM, "sending answer \"%s\"=\"%s\" for offer \"%s\"\n",
838b6364952Sagc 				      param->key, param->answer_tx, param->offer_rx);
839b6364952Sagc 				goto negotiate;
840b6364952Sagc 			} else {
841b6364952Sagc 				param->tx_offer = 1;	/* sending an offer */
842b6364952Sagc 				param->tx_answer = 0;
843b6364952Sagc 				param->rx_answer = 0;
844b6364952Sagc 				(void) strlcpy(param->offer_tx, value, sizeof(param->offer_tx));
8455e01dafbSagc 				iscsi_trace(TRACE_ISCSI_PARAM, "sending offer \"%s\"=\"%s\"\n", param->key, param->offer_tx);
846b6364952Sagc 				if ((param->type == ISCSI_PARAM_TYPE_DECLARATIVE) ||
847b6364952Sagc 				    (param->type == ISCSI_PARAM_TYPE_DECLARE_MULTI)) {
848b6364952Sagc 					goto negotiate;
849b6364952Sagc 				}
850b6364952Sagc 				goto next;
851b6364952Sagc 			}
852b6364952Sagc 		} else {
853b6364952Sagc 			if (param->tx_offer) {
854b6364952Sagc 				param->rx_answer = 1;	/* received an answer */
855b6364952Sagc 				param->tx_answer = 0;
856b6364952Sagc 				param->rx_offer = 0;
857b6364952Sagc 				param->tx_offer = 0;	/* reset */
858b6364952Sagc 				(void) strlcpy(param->answer_rx, value, sizeof(param->answer_rx));
8595e01dafbSagc 				iscsi_trace(TRACE_ISCSI_PARAM, "received answer \"%s\"=\"%s\" for offer \"%s\"\n",
860b6364952Sagc 				      param->key, param->answer_rx, param->offer_tx);
861b6364952Sagc 
862b6364952Sagc 				if ((ret = param_parse_security(head, param, cred,
863b6364952Sagc 					       text_out, text_len_out, textsize)) > 1) {
864b6364952Sagc 					goto next;
865b6364952Sagc 				} else if (ret == 0) {
866b6364952Sagc 					/*
867b6364952Sagc 					 * FIX ME Happens in initiator code
868b6364952Sagc 					 * currently we ignore initiator
869b6364952Sagc 					 * authentication status See comments
870b6364952Sagc 					 * at the beginning of parse_security
871b6364952Sagc 					 */
872b6364952Sagc 					goto negotiate;
873b6364952Sagc 				} else if (ret == 1) {
874b6364952Sagc 					goto negotiate;
875b6364952Sagc 				} else {
876b6364952Sagc 					PTP_CLEANUP;
877b6364952Sagc 				}
878b6364952Sagc 				return ISCSI_PARAM_STATUS_AUTH_FAILED;
879b6364952Sagc 			} else {
880b6364952Sagc 				param->rx_offer = 1;	/* received an offer */
881b6364952Sagc 				param->rx_answer = 0;
882b6364952Sagc 				param->tx_answer = 0;
883b6364952Sagc 				(void) strlcpy(param->offer_rx, value, sizeof(param->offer_rx));
8845e01dafbSagc 				iscsi_trace(TRACE_ISCSI_PARAM, "received offer \"%s\"=\"%s\"\n", param->key, param->offer_rx);
885b6364952Sagc 
886b6364952Sagc 				if ((ret = param_parse_security(head, param, cred,
887b6364952Sagc 					       text_out, text_len_out, textsize)) > 1) {
888b6364952Sagc 					goto next;
889b6364952Sagc 				} else if (ret < 0) {
890b6364952Sagc 					iscsi_parameter_t *auth_result;
891b6364952Sagc 					if ((auth_result = param_get(head, "AuthResult")) != 0) {
892b6364952Sagc 						(void) strlcpy(auth_result->value_l->value, "Fail", sizeof(auth_result->value_l->value));
893b6364952Sagc 					}
894b6364952Sagc 					PTP_CLEANUP;
895b6364952Sagc 					return (ISCSI_PARAM_STATUS_AUTH_FAILED);
896b6364952Sagc 				} else if (ret == 0) {
897b6364952Sagc 					iscsi_parameter_t *auth_result;
898b6364952Sagc 					if ((auth_result = param_get(head, "AuthResult")) != 0) {
899b6364952Sagc 						(void) strlcpy(auth_result->value_l->value, "Yes", sizeof(auth_result->value_l->value));
900b6364952Sagc 					}
901b6364952Sagc 				}
902b6364952Sagc 				/*
903b6364952Sagc 				 * Answer the offer if it is an inquiry or
904b6364952Sagc 				 * the type is not DECLARATIVE
905b6364952Sagc 				 */
906b6364952Sagc 
907b6364952Sagc 				if ((strcmp(param->offer_rx, "?") != 0) && ((param->type == ISCSI_PARAM_TYPE_DECLARATIVE) || (param->type == ISCSI_PARAM_TYPE_DECLARE_MULTI))) {
908b6364952Sagc 					goto negotiate;
909b6364952Sagc 				} else {
910b6364952Sagc 					goto answer;
911b6364952Sagc 				}
912b6364952Sagc 			}
913b6364952Sagc 		}
914b6364952Sagc 
915b6364952Sagc answer:
916b6364952Sagc 
917b6364952Sagc 		/* Answer with current value if this is an inquiry (<key>=?) */
918b6364952Sagc 
919b6364952Sagc 		if (strcmp(value, "?") == 0) {
9205e01dafbSagc 			iscsi_trace(TRACE_ISCSI_PARAM, "got inquiry for param \"%s\"\n", param->key);
921b6364952Sagc 			if (param->value_l) {
922b6364952Sagc 				(void) strlcpy(param->answer_tx, param->value_l->value, sizeof(param->answer_tx));
923b6364952Sagc 			} else {
9245e01dafbSagc 				iscsi_err(__FILE__, __LINE__, "param \"%s\" has NULL value_l\n", param->key);
925b6364952Sagc 				param->answer_tx[0] = 0x0;
926b6364952Sagc 			}
927b6364952Sagc 			goto add_answer;
928b6364952Sagc 		}
929b6364952Sagc 		/* Generate answer according to the parameter type */
930b6364952Sagc 
931b6364952Sagc 		switch (param->type) {
932b6364952Sagc 
933b6364952Sagc 		case ISCSI_PARAM_TYPE_BINARY_AND:
934b6364952Sagc 			goto binary_or;
935b6364952Sagc 
936b6364952Sagc 		case ISCSI_PARAM_TYPE_BINARY_OR:
937b6364952Sagc binary_or:
938b6364952Sagc 			if (strcmp(value, "yes") != 0 &&
939b6364952Sagc 			    strcmp(value, "no") != 0 &&
940b6364952Sagc 			    strcmp(value, "Yes") != 0 &&
941b6364952Sagc 			    strcmp(value, "No") != 0) {
9425e01dafbSagc 				iscsi_err(__FILE__, __LINE__, "\"%s\" is not a valid binary value\n", value);
943b6364952Sagc 				(void) strlcpy(param->answer_tx, "Reject", sizeof(param->answer_tx));
944b6364952Sagc 				goto add_answer;
945b6364952Sagc 			}
946b6364952Sagc 			if (strchr(param->valid, ',') != NULL) {
947b6364952Sagc 				(void) strlcpy(param->answer_tx, value, sizeof(param->answer_tx));	/* we accept both yes
948b6364952Sagc 									 * and no, so answer w/
949b6364952Sagc 									 * their offer */
950b6364952Sagc 			} else {
951b6364952Sagc 				(void) strlcpy(param->answer_tx, param->valid, sizeof(param->answer_tx));	/* answer with the only
952b6364952Sagc 									 * value we support */
953b6364952Sagc 			}
954b6364952Sagc 			break;
955b6364952Sagc 
956b6364952Sagc 		case ISCSI_PARAM_TYPE_LIST:
957b6364952Sagc 
958b6364952Sagc 			/*
959b6364952Sagc 			 * Use our default value if it's offered as one of the option
960b6364952Sagc 			 * in the parameter list.
961b6364952Sagc 			 *
962b6364952Sagc 			 * We need to do this at least for CHAP because cisco's initiator
963b6364952Sagc 			 * could be sending us a parameter value list with "CHAP,None",
964b6364952Sagc 			 * even when it doesn't set username/password in its configration
965b6364952Sagc 			 * file, in which case we should pick "None" as for no security instead
966b6364952Sagc 			 * of pick the first one on the value list. "None" is the default value
967b6364952Sagc 			 * for AuthMethod
968b6364952Sagc 			 *
969b6364952Sagc 			 * This fix is working well now, though is arguable. We should keep
970b6364952Sagc 			 * this just to make us work with Cisco for now.
971b6364952Sagc 			 */
972b6364952Sagc 			if (strlen(param->dflt)) {
973b6364952Sagc 				for (p1 = p2 = param->offer_rx; p2; p1 = p2 + 1) {
974b6364952Sagc 
975b6364952Sagc 					if ((p2 = strchr(p1, ',')) != NULL) {
976b6364952Sagc 						strncpy(offer, p1, (unsigned)(p2 - p1));
977b6364952Sagc 						offer[(int)(p2 - p1)] = 0x0;
978b6364952Sagc 					} else {
979b6364952Sagc 						(void) strlcpy(offer, p1, ISCSI_PARAM_MAX_LEN);
980b6364952Sagc 					}
981b6364952Sagc 
982b6364952Sagc 					if (strcmp(param->dflt, offer) == 0) {
983b6364952Sagc 						(void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx));
984b6364952Sagc 						goto add_answer;
985b6364952Sagc 					}
986b6364952Sagc 				}
987b6364952Sagc 			}
988b6364952Sagc 			/* Find the first valid offer that we support */
989b6364952Sagc 
990b6364952Sagc 			for (p1 = p2 = param->offer_rx; p2; p1 = p2 + 1) {
991b6364952Sagc 				if ((p2 = strchr(p1, ',')) != NULL) {
992b6364952Sagc 					strncpy(offer, p1, (unsigned)(p2 - p1));
993b6364952Sagc 					offer[p2 - p1] = 0x0;
994b6364952Sagc 				} else {
995b6364952Sagc 					(void) strlcpy(offer, p1, ISCSI_PARAM_MAX_LEN);
996b6364952Sagc 				}
997b6364952Sagc 				if (strlen(param->valid)) {
998b6364952Sagc 					for (p3 = p4 = param->valid; p4; p3 = p4 + 1) {
999b6364952Sagc 						if ((p4 = strchr(p3, ',')) != NULL) {
1000b6364952Sagc 							strncpy(valid, p3, (unsigned)(p4 - p3));
1001b6364952Sagc 							valid[(int)(p4 - p3)] = 0x0;
1002b6364952Sagc 						} else {
1003b6364952Sagc 							(void) strlcpy(valid, p3, ISCSI_PARAM_MAX_LEN);
1004b6364952Sagc 						}
1005b6364952Sagc 						if (strcmp(valid, offer) == 0) {
1006b6364952Sagc 							(void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx));
1007b6364952Sagc 							goto add_answer;
1008b6364952Sagc 						}
1009b6364952Sagc 					}
1010b6364952Sagc 				} else {
10115e01dafbSagc 					iscsi_trace(TRACE_ISCSI_PARAM, "Valid list empty. Answering with first in offer list\n");
1012b6364952Sagc 					(void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx));
1013b6364952Sagc 					goto add_answer;
1014b6364952Sagc 				}
10155e01dafbSagc 				iscsi_trace(TRACE_ISCSI_PARAM, "\"%s\" is not a valid offer for key \"%s\" (must choose from \"%s\")\n", offer, param->key, param->valid);
1016b6364952Sagc 			}
10175e01dafbSagc 			iscsi_trace(TRACE_ISCSI_PARAM, "No Valid offers: \"%s\" is added as value for key \"%s\")\n", "Reject", param->key);
1018b6364952Sagc 			(void) strlcpy(param->answer_tx, "Reject", sizeof(param->answer_tx));
1019b6364952Sagc 			break;
1020b6364952Sagc 
1021b6364952Sagc 		case ISCSI_PARAM_TYPE_NUMERICAL_Z:
1022b6364952Sagc 			goto numerical;
1023b6364952Sagc 
1024b6364952Sagc 		case ISCSI_PARAM_TYPE_NUMERICAL:
1025b6364952Sagc numerical:
1026b6364952Sagc 			offer_i = iscsi_atoi(param->offer_rx);
1027b6364952Sagc 			max_i = iscsi_atoi(param->valid);
1028b6364952Sagc 			if (param->type == ISCSI_PARAM_TYPE_NUMERICAL_Z) {
1029b6364952Sagc 				if (max_i == 0) {
1030b6364952Sagc 					answer_i = offer_i;	/* we support anything,
1031b6364952Sagc 								 * so return whatever
1032b6364952Sagc 								 * they offered */
1033b6364952Sagc 				} else if (offer_i == 0) {
1034b6364952Sagc 					answer_i = max_i;	/* return only what we
1035b6364952Sagc 								 * can support */
1036b6364952Sagc 				} else if (offer_i > max_i) {
1037b6364952Sagc 					answer_i = max_i;	/* we are the lower of
1038b6364952Sagc 								 * the two */
1039b6364952Sagc 				} else {
1040b6364952Sagc 					answer_i = offer_i;	/* they are the lower of
1041b6364952Sagc 								 * the two */
1042b6364952Sagc 				}
1043b6364952Sagc 			} else {
1044b6364952Sagc 				if (offer_i > max_i) {
1045b6364952Sagc 					answer_i = max_i;	/* we are the lower of
1046b6364952Sagc 								 * the two */
1047b6364952Sagc 				} else {
1048b6364952Sagc 					answer_i = offer_i;	/* they are the lower of
1049b6364952Sagc 								 * the two */
1050b6364952Sagc 				}
1051b6364952Sagc 			}
1052b6364952Sagc 			(void) snprintf(param->answer_tx, sizeof(param->answer_tx), "%d", answer_i);
1053b6364952Sagc 			goto add_answer;
1054b6364952Sagc 
1055b6364952Sagc 		default:
1056b6364952Sagc 			goto next;
1057b6364952Sagc 		}
1058b6364952Sagc add_answer:	PARAM_TEXT_ADD(head, key, param->answer_tx, text_out, text_len_out, textsize, 0, PTP_ERROR);
10595e01dafbSagc 		iscsi_trace(TRACE_ISCSI_PARAM, "answering \"%s\"=\"%s\"\n", param->key, param->answer_tx);
1060b6364952Sagc 		goto next;
1061b6364952Sagc 
1062b6364952Sagc 
1063b6364952Sagc 		/* Negotiate after receiving|sending an answer  */
1064b6364952Sagc 
1065b6364952Sagc negotiate:
1066b6364952Sagc 		switch (param->type) {
1067b6364952Sagc 		case ISCSI_PARAM_TYPE_DECLARE_MULTI:
1068b6364952Sagc 			goto declarative_negotiate;
1069b6364952Sagc 		case ISCSI_PARAM_TYPE_DECLARATIVE:
1070b6364952Sagc declarative_negotiate:
1071b6364952Sagc 			if (param->tx_answer) {
1072b6364952Sagc 				(void) strlcpy(param->negotiated, param->answer_tx, sizeof(param->negotiated));
1073b6364952Sagc 			} else if (param->tx_offer) {
1074b6364952Sagc 				(void) strlcpy(param->negotiated, param->offer_tx, sizeof(param->negotiated));
1075b6364952Sagc 			} else if (param->rx_answer) {
1076b6364952Sagc 				(void) strlcpy(param->negotiated, param->answer_rx, sizeof(param->negotiated));
1077b6364952Sagc 			} else if (param->rx_offer) {
1078b6364952Sagc 				(void) strlcpy(param->negotiated, param->offer_rx, sizeof(param->negotiated));
1079b6364952Sagc 			} else {
10805e01dafbSagc 				iscsi_err(__FILE__, __LINE__, "Invalid negotiation!?!?\n");
1081b6364952Sagc 			}
1082b6364952Sagc 			break;
1083b6364952Sagc 		case ISCSI_PARAM_TYPE_BINARY_AND:
1084b6364952Sagc 			goto binary_or_negotiate;
1085b6364952Sagc 		case ISCSI_PARAM_TYPE_BINARY_OR:
1086b6364952Sagc binary_or_negotiate:
1087b6364952Sagc 			if (outgoing) {
1088b6364952Sagc 				(void) strlcpy(val1, param->offer_rx, ISCSI_PARAM_MAX_LEN);
1089b6364952Sagc 				(void) strlcpy(val2, param->answer_tx, ISCSI_PARAM_MAX_LEN);
1090b6364952Sagc 			} else {
1091b6364952Sagc 				(void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN);
1092b6364952Sagc 				(void) strlcpy(val2, param->offer_tx, ISCSI_PARAM_MAX_LEN);
1093b6364952Sagc 				/* Make sure the answer is valid */
1094b6364952Sagc 				if (strcmp(val1, "Yes") != 0 &&
1095b6364952Sagc 				    strcmp(val1, "No") != 0 &&
1096b6364952Sagc 				    strcmp(val1, "yes") != 0 &&
1097b6364952Sagc 				    strcmp(val1, "no") != 0 &&
1098b6364952Sagc 				    strcmp(val1, "Irrelevant") != 0) {
1099b6364952Sagc 					/* Invalid value returned as answer. */
11005e01dafbSagc 					iscsi_err(__FILE__, __LINE__, "Invalid answer (%s) for key (%s)\n",
1101b6364952Sagc 						    val1, key);
1102b6364952Sagc 					PTP_ERROR;
1103b6364952Sagc 				}
1104b6364952Sagc 			}
1105b6364952Sagc 			if (param->type == ISCSI_PARAM_TYPE_BINARY_OR) {
1106b6364952Sagc 				if (strcmp(val1, "yes") == 0 || strcmp(val2, "yes") == 0 || strcmp(val1, "Yes") == 0 || strcmp(val2, "Yes") == 0) {
1107b6364952Sagc 					(void) strlcpy(param->negotiated, "Yes", sizeof(param->negotiated));
1108b6364952Sagc 				} else {
1109b6364952Sagc 					(void) strlcpy(param->negotiated, "No", sizeof(param->negotiated));
1110b6364952Sagc 				}
1111b6364952Sagc 			} else {
1112b6364952Sagc 				if ((strcmp(val1, "yes") == 0 && strcmp(val2, "yes") == 0) || (strcmp(val1, "Yes") == 0 && strcmp(val2, "Yes") == 0)) {
1113b6364952Sagc 					(void) strlcpy(param->negotiated, "Yes", sizeof(param->negotiated));
1114b6364952Sagc 				} else {
1115b6364952Sagc 					(void) strlcpy(param->negotiated, "No", sizeof(param->negotiated));
1116b6364952Sagc 				}
1117b6364952Sagc 			}
1118b6364952Sagc 			break;
1119b6364952Sagc 		case ISCSI_PARAM_TYPE_NUMERICAL_Z:
1120b6364952Sagc 			goto numerical_negotiate;
1121b6364952Sagc 		case ISCSI_PARAM_TYPE_NUMERICAL:
1122b6364952Sagc numerical_negotiate:
1123b6364952Sagc 			if (outgoing) {
1124b6364952Sagc 				(void) strlcpy(val1, param->offer_rx, ISCSI_PARAM_MAX_LEN);
1125b6364952Sagc 				(void) strlcpy(val2, param->answer_tx, ISCSI_PARAM_MAX_LEN);
1126b6364952Sagc 			} else {
1127b6364952Sagc 				(void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN);
1128b6364952Sagc 				(void) strlcpy(val2, param->offer_tx, ISCSI_PARAM_MAX_LEN);
1129b6364952Sagc 			}
1130b6364952Sagc 			val1_i = iscsi_atoi(val1);
1131b6364952Sagc 			val2_i = iscsi_atoi(val2);
1132b6364952Sagc 			if (param->type == ISCSI_PARAM_TYPE_NUMERICAL_Z) {
1133b6364952Sagc 				if (val1_i == 0) {
1134b6364952Sagc 					negotiated_i = val2_i;
1135b6364952Sagc 				} else if (val2_i == 0) {
1136b6364952Sagc 					negotiated_i = val1_i;
1137b6364952Sagc 				} else if (val1_i > val2_i) {
1138b6364952Sagc 					negotiated_i = val2_i;
1139b6364952Sagc 				} else {
1140b6364952Sagc 					negotiated_i = val1_i;
1141b6364952Sagc 				}
1142b6364952Sagc 			} else {
1143b6364952Sagc 				if (val1_i > val2_i) {
1144b6364952Sagc 					negotiated_i = val2_i;
1145b6364952Sagc 				} else {
1146b6364952Sagc 					negotiated_i = val1_i;
1147b6364952Sagc 				}
1148b6364952Sagc 			}
1149b6364952Sagc 			(void) snprintf(param->negotiated, sizeof(param->negotiated), "%d", negotiated_i);
1150b6364952Sagc 			break;
1151b6364952Sagc 		case ISCSI_PARAM_TYPE_LIST:
1152b6364952Sagc 			if (outgoing) {
1153b6364952Sagc 				if (param->tx_offer) {
11545e01dafbSagc 					iscsi_err(__FILE__, __LINE__, "we should not be here\n");	/* error - we're sending
1155b6364952Sagc 										 * an offer */
1156b6364952Sagc 					PTP_ERROR;
1157b6364952Sagc 				} else if (param->tx_answer) {
1158b6364952Sagc 					(void) strlcpy(val1, param->answer_tx, ISCSI_PARAM_MAX_LEN);	/* we're sending an
1159b6364952Sagc 									 * answer */
1160b6364952Sagc 				} else {
11615e01dafbSagc 					iscsi_err(__FILE__, __LINE__, "unexpected error\n");
1162b6364952Sagc 					PTP_ERROR;
1163b6364952Sagc 				}
1164b6364952Sagc 			} else {
1165b6364952Sagc 				if (param->rx_offer) {
11665e01dafbSagc 					iscsi_err(__FILE__, __LINE__, "we should not be here\n");	/* error - we received
1167b6364952Sagc 										 * an offer */
1168b6364952Sagc 					PTP_ERROR;
1169b6364952Sagc 				} else if (param->rx_answer) {
1170b6364952Sagc 					(void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN);	/* we received an answer */
1171b6364952Sagc 				} else {
11725e01dafbSagc 					iscsi_err(__FILE__, __LINE__, "unexpected error\n");
1173b6364952Sagc 					PTP_ERROR;
1174b6364952Sagc 				}
1175b6364952Sagc 			}
1176b6364952Sagc 
1177b6364952Sagc 			/* Make sure incoming or outgoing answer is valid */
1178b6364952Sagc 			/*
1179b6364952Sagc 			 * None, Reject, Irrelevant and NotUnderstood are
1180b6364952Sagc 			 * valid
1181b6364952Sagc 			 */
1182b6364952Sagc 			if ((strcmp(val1, "None") == 0) || (strcmp(val1, "Reject") == 0) ||
1183b6364952Sagc 			    (strcmp(val1, "Irrelevant") == 0) || (strcmp(val1, "NotUnderstood") == 0)) {
1184b6364952Sagc 				goto value_ok;
1185b6364952Sagc 			}
1186b6364952Sagc 			if (strlen(param->valid) > 0) {
1187b6364952Sagc 				for (p3 = p4 = param->valid; p4; p3 = p4 + 1) {
1188b6364952Sagc 					if ((p4 = strchr(p3, ',')) != NULL) {
1189b6364952Sagc 						strncpy(valid, p3, (unsigned)(p4 - p3));
1190b6364952Sagc 						valid[(int)(p4 - p3)] = 0x0;
1191b6364952Sagc 					} else {
1192b6364952Sagc 						(void) strlcpy(valid, p3, ISCSI_PARAM_MAX_LEN);
1193b6364952Sagc 					}
1194b6364952Sagc 					if (strcmp(valid, val1) == 0) {
1195b6364952Sagc 						goto value_ok;
1196b6364952Sagc 					}
1197b6364952Sagc 				}
1198b6364952Sagc 			} else {
11995e01dafbSagc 				iscsi_trace(TRACE_ISCSI_PARAM, "Valid list empty??\n");
1200b6364952Sagc 				PTP_ERROR;
1201b6364952Sagc 			}
12025e01dafbSagc 			iscsi_err(__FILE__, __LINE__, "\"%s\" is not a valid value (must choose from \"%s\")\n", val1, param->valid);
1203b6364952Sagc 			PTP_ERROR;
1204b6364952Sagc value_ok:
1205b6364952Sagc 			(void) strlcpy(param->negotiated, val1, sizeof(param->negotiated));
1206b6364952Sagc 			break;
1207b6364952Sagc 		}
1208b6364952Sagc 
12095e01dafbSagc 		iscsi_trace(TRACE_ISCSI_PARAM, "negotiated \"%s\"=\"%s\"\n", param->key, param->negotiated);
1210b6364952Sagc 
1211b6364952Sagc 		/* For inquiries, we don't commit the value. */
1212b6364952Sagc 
1213b6364952Sagc 		if (param->tx_offer && strcmp(param->offer_tx, "?") == 0) {
1214b6364952Sagc 			/* we're offering an inquiry  */
12155e01dafbSagc 			iscsi_trace(TRACE_ISCSI_PARAM, "sending an inquiry for \"%s\"\n", param->key);
1216b6364952Sagc 			goto next;
1217b6364952Sagc 		} else if (param->rx_offer && strcmp(param->offer_rx, "?") == 0) {
1218b6364952Sagc 			/* we're receiving an inquiry  */
12195e01dafbSagc 			iscsi_trace(TRACE_ISCSI_PARAM, "received an inquiry for \"%s\"\n", param->key);
1220b6364952Sagc 			goto next;
1221b6364952Sagc 		} else if (param->tx_answer && strcmp(param->offer_rx, "?") == 0) {
1222b6364952Sagc 			/* we're answering an inquiry  */
12235e01dafbSagc 			iscsi_trace(TRACE_ISCSI_PARAM, "answering an inquiry for \"%s\"\n", param->key);
1224b6364952Sagc 			goto next;
1225b6364952Sagc 		} else if (param->rx_answer && strcmp(param->offer_tx, "?") == 0) {
1226b6364952Sagc 			/* we're receiving an answer for our inquiry  */
12275e01dafbSagc 			iscsi_trace(TRACE_ISCSI_PARAM, "received an answer for inquiry on \"%s\"\n", param->key);
1228b6364952Sagc 			goto next;
1229b6364952Sagc 		}
12305e01dafbSagc 		iscsi_trace(TRACE_ISCSI_PARAM, "automatically committing \"%s\"=\"%s\"\n", param->key, param->negotiated);
1231b6364952Sagc 
1232b6364952Sagc 		c = param->negotiated[19];
1233b6364952Sagc 		param->negotiated[19] = 0x0;
1234b6364952Sagc #if ISCSI_DEBUG
1235b6364952Sagc 		printf("* %25s:%20s *\n", param->key, param->negotiated);
1236b6364952Sagc #endif
1237b6364952Sagc 		param->negotiated[19] = c;
1238b6364952Sagc 
1239b6364952Sagc 		if (param->reset) {
12405e01dafbSagc 			iscsi_trace(TRACE_ISCSI_PARAM, "deleting value list for \"%s\"\n", param->key);
1241b6364952Sagc 			if (param_val_delete_all(head, param->key) != 0) {
12425e01dafbSagc 				iscsi_err(__FILE__, __LINE__, "param_val_delete_all() failed\n");
1243b6364952Sagc 				PTP_ERROR;
1244b6364952Sagc 			}
1245b6364952Sagc 			param->reset = 0;
1246b6364952Sagc 		}
1247b6364952Sagc 		if (param->value_l) {
1248b6364952Sagc 			if (param->type == ISCSI_PARAM_TYPE_DECLARE_MULTI) {
1249b6364952Sagc 				for (item_ptr = param->value_l; item_ptr->next != NULL; item_ptr = item_ptr->next) {
1250b6364952Sagc 				}
1251b6364952Sagc 				if ((item_ptr->next = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) {
12525e01dafbSagc 					iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
1253b6364952Sagc 					PTP_ERROR;
1254b6364952Sagc 				}
1255b6364952Sagc 				item_ptr = item_ptr->next;
1256b6364952Sagc 				item_ptr->next = NULL;
1257b6364952Sagc 			} else {
1258b6364952Sagc 				item_ptr = param->value_l;
1259b6364952Sagc 			}
1260b6364952Sagc 		} else {
12615e01dafbSagc 			iscsi_trace(TRACE_ISCSI_PARAM, "allocating value ptr\n");
1262b6364952Sagc 			if ((param->value_l = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) {
12635e01dafbSagc 				iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
1264b6364952Sagc 				PTP_ERROR;
1265b6364952Sagc 			}
1266b6364952Sagc 			item_ptr = param->value_l;
1267b6364952Sagc 			item_ptr->next = NULL;
1268b6364952Sagc 		}
1269b6364952Sagc 		(void) strlcpy(item_ptr->value, param->negotiated, sizeof(item_ptr->value));
1270b6364952Sagc next:
1271b6364952Sagc 		continue;
1272b6364952Sagc 	}
1273b6364952Sagc 	if (!outgoing) {
12745e01dafbSagc 		iscsi_trace(TRACE_ISCSI_PARAM, "generated %d bytes response\n", *text_len_out);
1275b6364952Sagc 	}
1276b6364952Sagc #if ISCSI_DEBUG
1277b6364952Sagc 	printf("**************************************************\n");
1278b6364952Sagc #endif
1279b6364952Sagc 
1280b6364952Sagc 	PTP_CLEANUP;
1281b6364952Sagc 	return 0;
1282b6364952Sagc }
1283b6364952Sagc 
1284b6364952Sagc void
set_session_parameters(iscsi_parameter_t * head,iscsi_sess_param_t * sess_params)1285b6364952Sagc set_session_parameters(iscsi_parameter_t * head,
1286b6364952Sagc 		       iscsi_sess_param_t * sess_params)
1287b6364952Sagc {
1288b6364952Sagc 	/* These parameters are standard and assuming that they are always */
1289b6364952Sagc 	/* present in the list (head). */
1290b6364952Sagc 	memset(sess_params, 0, sizeof(iscsi_sess_param_t));
1291b6364952Sagc 	sess_params->max_burst_length = param_atoi(head, "MaxBurstLength");
1292b6364952Sagc 	sess_params->first_burst_length = param_atoi(head, "FirstBurstLength");
12935e01dafbSagc 	sess_params->max_dataseg_len =
1294b6364952Sagc 		param_atoi(head, "MaxRecvDataSegmentLength");
1295b6364952Sagc 	sess_params->header_digest = (param_equiv(head, "HeaderDigest", "Yes")) ? 1 : 0;
1296b6364952Sagc 	sess_params->data_digest = (param_equiv(head, "DataDigest", "Yes")) ? 1 : 0;
1297b6364952Sagc 	sess_params->initial_r2t = (param_equiv(head, "InitialR2T", "Yes"));
1298b6364952Sagc 	sess_params->immediate_data = (param_equiv(head, "ImmediateData", "Yes"));
1299b6364952Sagc }
1300