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