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