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