1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2015 iXsystems Inc. 5 * All rights reserved. 6 * 7 * This software was developed by Jakub Klama <jceel@FreeBSD.org> 8 * under sponsorship from iXsystems Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/queue.h> 33 #include <sys/types.h> 34 #include <assert.h> 35 #include <stdio.h> 36 #include <stdint.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <ucl.h> 40 #include <netinet/in.h> 41 #include <netinet/ip.h> 42 43 #include "ctld.h" 44 45 static struct conf *conf = NULL; 46 47 static int uclparse_toplevel(const ucl_object_t *); 48 static int uclparse_chap(struct auth_group *, const ucl_object_t *); 49 static int uclparse_chap_mutual(struct auth_group *, const ucl_object_t *); 50 static int uclparse_lun(const char *, const ucl_object_t *); 51 static int uclparse_auth_group(const char *, const ucl_object_t *); 52 static int uclparse_portal_group(const char *, const ucl_object_t *); 53 static int uclparse_target(const char *, const ucl_object_t *); 54 static int uclparse_target_portal_group(struct target *, const ucl_object_t *); 55 static int uclparse_target_lun(struct target *, const ucl_object_t *); 56 57 static int 58 uclparse_chap(struct auth_group *auth_group, const ucl_object_t *obj) 59 { 60 const struct auth *ca; 61 const ucl_object_t *user, *secret; 62 63 user = ucl_object_find_key(obj, "user"); 64 if (!user || user->type != UCL_STRING) { 65 log_warnx("chap section in auth-group \"%s\" is missing " 66 "\"user\" string key", auth_group->ag_name); 67 return (1); 68 } 69 70 secret = ucl_object_find_key(obj, "secret"); 71 if (!secret || secret->type != UCL_STRING) { 72 log_warnx("chap section in auth-group \"%s\" is missing " 73 "\"secret\" string key", auth_group->ag_name); 74 } 75 76 ca = auth_new_chap(auth_group, 77 ucl_object_tostring(user), 78 ucl_object_tostring(secret)); 79 80 if (ca == NULL) 81 return (1); 82 83 return (0); 84 } 85 86 static int 87 uclparse_chap_mutual(struct auth_group *auth_group, const ucl_object_t *obj) 88 { 89 const struct auth *ca; 90 const ucl_object_t *user, *secret, *mutual_user; 91 const ucl_object_t *mutual_secret; 92 93 user = ucl_object_find_key(obj, "user"); 94 if (!user || user->type != UCL_STRING) { 95 log_warnx("chap-mutual section in auth-group \"%s\" is missing " 96 "\"user\" string key", auth_group->ag_name); 97 return (1); 98 } 99 100 secret = ucl_object_find_key(obj, "secret"); 101 if (!secret || secret->type != UCL_STRING) { 102 log_warnx("chap-mutual section in auth-group \"%s\" is missing " 103 "\"secret\" string key", auth_group->ag_name); 104 return (1); 105 } 106 107 mutual_user = ucl_object_find_key(obj, "mutual-user"); 108 if (!user || user->type != UCL_STRING) { 109 log_warnx("chap-mutual section in auth-group \"%s\" is missing " 110 "\"mutual-user\" string key", auth_group->ag_name); 111 return (1); 112 } 113 114 mutual_secret = ucl_object_find_key(obj, "mutual-secret"); 115 if (!secret || secret->type != UCL_STRING) { 116 log_warnx("chap-mutual section in auth-group \"%s\" is missing " 117 "\"mutual-secret\" string key", auth_group->ag_name); 118 return (1); 119 } 120 121 ca = auth_new_chap_mutual(auth_group, 122 ucl_object_tostring(user), 123 ucl_object_tostring(secret), 124 ucl_object_tostring(mutual_user), 125 ucl_object_tostring(mutual_secret)); 126 127 if (ca == NULL) 128 return (1); 129 130 return (0); 131 } 132 133 static int 134 uclparse_target_portal_group(struct target *target, const ucl_object_t *obj) 135 { 136 struct portal_group *tpg; 137 struct auth_group *tag = NULL; 138 struct port *tp; 139 const ucl_object_t *portal_group, *auth_group; 140 141 portal_group = ucl_object_find_key(obj, "name"); 142 if (!portal_group || portal_group->type != UCL_STRING) { 143 log_warnx("portal-group section in target \"%s\" is missing " 144 "\"name\" string key", target->t_name); 145 return (1); 146 } 147 148 auth_group = ucl_object_find_key(obj, "auth-group-name"); 149 if (auth_group && auth_group->type != UCL_STRING) { 150 log_warnx("portal-group section in target \"%s\" is missing " 151 "\"auth-group-name\" string key", target->t_name); 152 return (1); 153 } 154 155 156 tpg = portal_group_find(conf, ucl_object_tostring(portal_group)); 157 if (tpg == NULL) { 158 log_warnx("unknown portal-group \"%s\" for target " 159 "\"%s\"", ucl_object_tostring(portal_group), target->t_name); 160 return (1); 161 } 162 163 if (auth_group) { 164 tag = auth_group_find(conf, ucl_object_tostring(auth_group)); 165 if (tag == NULL) { 166 log_warnx("unknown auth-group \"%s\" for target " 167 "\"%s\"", ucl_object_tostring(auth_group), 168 target->t_name); 169 return (1); 170 } 171 } 172 173 tp = port_new(conf, target, tpg); 174 if (tp == NULL) { 175 log_warnx("can't link portal-group \"%s\" to target " 176 "\"%s\"", ucl_object_tostring(portal_group), target->t_name); 177 return (1); 178 } 179 tp->p_auth_group = tag; 180 181 return (0); 182 } 183 184 static int 185 uclparse_target_lun(struct target *target, const ucl_object_t *obj) 186 { 187 struct lun *lun; 188 uint64_t tmp; 189 190 if (obj->type == UCL_INT) { 191 char *name; 192 193 tmp = ucl_object_toint(obj); 194 if (tmp >= MAX_LUNS) { 195 log_warnx("LU number %ju in target \"%s\" is too big", 196 tmp, target->t_name); 197 return (1); 198 } 199 200 asprintf(&name, "%s,lun,%ju", target->t_name, tmp); 201 lun = lun_new(conf, name); 202 if (lun == NULL) 203 return (1); 204 205 lun_set_scsiname(lun, name); 206 target->t_luns[tmp] = lun; 207 return (0); 208 } 209 210 if (obj->type == UCL_OBJECT) { 211 const ucl_object_t *num = ucl_object_find_key(obj, "number"); 212 const ucl_object_t *name = ucl_object_find_key(obj, "name"); 213 214 if (num == NULL || num->type != UCL_INT) { 215 log_warnx("lun section in target \"%s\" is missing " 216 "\"number\" integer property", target->t_name); 217 return (1); 218 } 219 tmp = ucl_object_toint(num); 220 if (tmp >= MAX_LUNS) { 221 log_warnx("LU number %ju in target \"%s\" is too big", 222 tmp, target->t_name); 223 return (1); 224 } 225 226 if (name == NULL || name->type != UCL_STRING) { 227 log_warnx("lun section in target \"%s\" is missing " 228 "\"name\" string property", target->t_name); 229 return (1); 230 } 231 232 lun = lun_find(conf, ucl_object_tostring(name)); 233 if (lun == NULL) 234 return (1); 235 236 target->t_luns[tmp] = lun; 237 } 238 239 return (0); 240 } 241 242 static int 243 uclparse_toplevel(const ucl_object_t *top) 244 { 245 ucl_object_iter_t it = NULL, iter = NULL; 246 const ucl_object_t *obj = NULL, *child = NULL; 247 int err = 0; 248 249 /* Pass 1 - everything except targets */ 250 while ((obj = ucl_iterate_object(top, &it, true))) { 251 const char *key = ucl_object_key(obj); 252 253 if (!strcmp(key, "debug")) { 254 if (obj->type == UCL_INT) 255 conf->conf_debug = ucl_object_toint(obj); 256 else { 257 log_warnx("\"debug\" property value is not integer"); 258 return (1); 259 } 260 } 261 262 if (!strcmp(key, "timeout")) { 263 if (obj->type == UCL_INT) 264 conf->conf_timeout = ucl_object_toint(obj); 265 else { 266 log_warnx("\"timeout\" property value is not integer"); 267 return (1); 268 } 269 } 270 271 if (!strcmp(key, "maxproc")) { 272 if (obj->type == UCL_INT) 273 conf->conf_maxproc = ucl_object_toint(obj); 274 else { 275 log_warnx("\"maxproc\" property value is not integer"); 276 return (1); 277 } 278 } 279 280 if (!strcmp(key, "pidfile")) { 281 if (obj->type == UCL_STRING) 282 conf->conf_pidfile_path = strdup( 283 ucl_object_tostring(obj)); 284 else { 285 log_warnx("\"pidfile\" property value is not string"); 286 return (1); 287 } 288 } 289 290 if (!strcmp(key, "isns-server")) { 291 if (obj->type == UCL_ARRAY) { 292 iter = NULL; 293 while ((child = ucl_iterate_object(obj, &iter, 294 true))) { 295 if (child->type != UCL_STRING) 296 return (1); 297 298 err = isns_new(conf, 299 ucl_object_tostring(child)); 300 if (err != 0) { 301 return (1); 302 } 303 } 304 } else { 305 log_warnx("\"isns-server\" property value is " 306 "not an array"); 307 return (1); 308 } 309 } 310 311 if (!strcmp(key, "isns-period")) { 312 if (obj->type == UCL_INT) 313 conf->conf_timeout = ucl_object_toint(obj); 314 else { 315 log_warnx("\"isns-period\" property value is not integer"); 316 return (1); 317 } 318 } 319 320 if (!strcmp(key, "isns-timeout")) { 321 if (obj->type == UCL_INT) 322 conf->conf_timeout = ucl_object_toint(obj); 323 else { 324 log_warnx("\"isns-timeout\" property value is not integer"); 325 return (1); 326 } 327 } 328 329 if (!strcmp(key, "auth-group")) { 330 if (obj->type == UCL_OBJECT) { 331 iter = NULL; 332 while ((child = ucl_iterate_object(obj, &iter, true))) { 333 uclparse_auth_group(ucl_object_key(child), child); 334 } 335 } else { 336 log_warnx("\"auth-group\" section is not an object"); 337 return (1); 338 } 339 } 340 341 if (!strcmp(key, "portal-group")) { 342 if (obj->type == UCL_OBJECT) { 343 iter = NULL; 344 while ((child = ucl_iterate_object(obj, &iter, true))) { 345 uclparse_portal_group(ucl_object_key(child), child); 346 } 347 } else { 348 log_warnx("\"portal-group\" section is not an object"); 349 return (1); 350 } 351 } 352 353 if (!strcmp(key, "lun")) { 354 if (obj->type == UCL_OBJECT) { 355 iter = NULL; 356 while ((child = ucl_iterate_object(obj, &iter, true))) { 357 uclparse_lun(ucl_object_key(child), child); 358 } 359 } else { 360 log_warnx("\"lun\" section is not an object"); 361 return (1); 362 } 363 } 364 } 365 366 /* Pass 2 - targets */ 367 it = NULL; 368 while ((obj = ucl_iterate_object(top, &it, true))) { 369 const char *key = ucl_object_key(obj); 370 371 if (!strcmp(key, "target")) { 372 if (obj->type == UCL_OBJECT) { 373 iter = NULL; 374 while ((child = ucl_iterate_object(obj, &iter, 375 true))) { 376 uclparse_target(ucl_object_key(child), 377 child); 378 } 379 } else { 380 log_warnx("\"target\" section is not an object"); 381 return (1); 382 } 383 } 384 } 385 386 return (0); 387 } 388 389 static int 390 uclparse_auth_group(const char *name, const ucl_object_t *top) 391 { 392 struct auth_group *auth_group; 393 const struct auth_name *an; 394 const struct auth_portal *ap; 395 ucl_object_iter_t it = NULL, it2 = NULL; 396 const ucl_object_t *obj = NULL, *tmp = NULL; 397 const char *key; 398 int err; 399 400 if (!strcmp(name, "default") && 401 conf->conf_default_ag_defined == false) { 402 auth_group = auth_group_find(conf, name); 403 conf->conf_default_ag_defined = true; 404 } else { 405 auth_group = auth_group_new(conf, name); 406 } 407 408 if (auth_group == NULL) 409 return (1); 410 411 while ((obj = ucl_iterate_object(top, &it, true))) { 412 key = ucl_object_key(obj); 413 414 if (!strcmp(key, "auth-type")) { 415 const char *value = ucl_object_tostring(obj); 416 417 err = auth_group_set_type(auth_group, value); 418 if (err) 419 return (1); 420 } 421 422 if (!strcmp(key, "chap")) { 423 if (obj->type != UCL_ARRAY) { 424 log_warnx("\"chap\" property of " 425 "auth-group \"%s\" is not an array", 426 name); 427 return (1); 428 } 429 430 it2 = NULL; 431 while ((tmp = ucl_iterate_object(obj, &it2, true))) { 432 if (uclparse_chap(auth_group, tmp) != 0) 433 return (1); 434 } 435 } 436 437 if (!strcmp(key, "chap-mutual")) { 438 if (obj->type != UCL_ARRAY) { 439 log_warnx("\"chap-mutual\" property of " 440 "auth-group \"%s\" is not an array", 441 name); 442 return (1); 443 } 444 445 it2 = NULL; 446 while ((tmp = ucl_iterate_object(obj, &it2, true))) { 447 if (uclparse_chap_mutual(auth_group, tmp) != 0) 448 return (1); 449 } 450 } 451 452 if (!strcmp(key, "initiator-name")) { 453 if (obj->type != UCL_ARRAY) { 454 log_warnx("\"initiator-name\" property of " 455 "auth-group \"%s\" is not an array", 456 name); 457 return (1); 458 } 459 460 it2 = NULL; 461 while ((tmp = ucl_iterate_object(obj, &it2, true))) { 462 const char *value = ucl_object_tostring(tmp); 463 464 an = auth_name_new(auth_group, value); 465 if (an == NULL) 466 return (1); 467 } 468 } 469 470 if (!strcmp(key, "initiator-portal")) { 471 if (obj->type != UCL_ARRAY) { 472 log_warnx("\"initiator-portal\" property of " 473 "auth-group \"%s\" is not an array", 474 name); 475 return (1); 476 } 477 478 it2 = NULL; 479 while ((tmp = ucl_iterate_object(obj, &it2, true))) { 480 const char *value = ucl_object_tostring(tmp); 481 482 ap = auth_portal_new(auth_group, value); 483 if (ap == NULL) 484 return (1); 485 } 486 } 487 } 488 489 return (0); 490 } 491 492 static int 493 uclparse_portal_group(const char *name, const ucl_object_t *top) 494 { 495 struct portal_group *portal_group; 496 ucl_object_iter_t it = NULL, it2 = NULL; 497 const ucl_object_t *obj = NULL, *tmp = NULL; 498 const char *key; 499 500 if (strcmp(name, "default") == 0 && 501 conf->conf_default_pg_defined == false) { 502 portal_group = portal_group_find(conf, name); 503 conf->conf_default_pg_defined = true; 504 } else { 505 portal_group = portal_group_new(conf, name); 506 } 507 508 if (portal_group == NULL) 509 return (1); 510 511 while ((obj = ucl_iterate_object(top, &it, true))) { 512 key = ucl_object_key(obj); 513 514 if (!strcmp(key, "discovery-auth-group")) { 515 portal_group->pg_discovery_auth_group = 516 auth_group_find(conf, ucl_object_tostring(obj)); 517 if (portal_group->pg_discovery_auth_group == NULL) { 518 log_warnx("unknown discovery-auth-group \"%s\" " 519 "for portal-group \"%s\"", 520 ucl_object_tostring(obj), 521 portal_group->pg_name); 522 return (1); 523 } 524 } 525 526 if (!strcmp(key, "discovery-filter")) { 527 if (obj->type != UCL_STRING) { 528 log_warnx("\"discovery-filter\" property of " 529 "portal-group \"%s\" is not a string", 530 portal_group->pg_name); 531 return (1); 532 } 533 534 if (portal_group_set_filter(portal_group, 535 ucl_object_tostring(obj)) != 0) 536 return (1); 537 } 538 539 if (!strcmp(key, "listen")) { 540 if (obj->type == UCL_STRING) { 541 if (portal_group_add_listen(portal_group, 542 ucl_object_tostring(obj), false) != 0) 543 return (1); 544 } else if (obj->type == UCL_ARRAY) { 545 while ((tmp = ucl_iterate_object(obj, &it2, 546 true))) { 547 if (portal_group_add_listen( 548 portal_group, 549 ucl_object_tostring(tmp), 550 false) != 0) 551 return (1); 552 } 553 } else { 554 log_warnx("\"listen\" property of " 555 "portal-group \"%s\" is not a string", 556 portal_group->pg_name); 557 return (1); 558 } 559 } 560 561 if (!strcmp(key, "listen-iser")) { 562 if (obj->type == UCL_STRING) { 563 if (portal_group_add_listen(portal_group, 564 ucl_object_tostring(obj), true) != 0) 565 return (1); 566 } else if (obj->type == UCL_ARRAY) { 567 while ((tmp = ucl_iterate_object(obj, &it2, 568 true))) { 569 if (portal_group_add_listen( 570 portal_group, 571 ucl_object_tostring(tmp), 572 true) != 0) 573 return (1); 574 } 575 } else { 576 log_warnx("\"listen\" property of " 577 "portal-group \"%s\" is not a string", 578 portal_group->pg_name); 579 return (1); 580 } 581 } 582 583 if (!strcmp(key, "redirect")) { 584 if (obj->type != UCL_STRING) { 585 log_warnx("\"listen\" property of " 586 "portal-group \"%s\" is not a string", 587 portal_group->pg_name); 588 return (1); 589 } 590 591 if (portal_group_set_redirection(portal_group, 592 ucl_object_tostring(obj)) != 0) 593 return (1); 594 } 595 596 if (!strcmp(key, "options")) { 597 if (obj->type != UCL_OBJECT) { 598 log_warnx("\"options\" property of portal group " 599 "\"%s\" is not an object", portal_group->pg_name); 600 return (1); 601 } 602 603 while ((tmp = ucl_iterate_object(obj, &it2, 604 true))) { 605 option_new(&portal_group->pg_options, 606 ucl_object_key(tmp), 607 ucl_object_tostring_forced(tmp)); 608 } 609 } 610 611 if (!strcmp(key, "dscp")) { 612 if ((obj->type != UCL_STRING) && (obj->type != UCL_INT)) { 613 log_warnx("\"dscp\" property of portal group " 614 "\"%s\" is not a string or integer", portal_group->pg_name); 615 return(1); 616 } 617 if (obj->type == UCL_INT) 618 portal_group->pg_dscp = ucl_object_toint(obj); 619 else { 620 key = ucl_object_tostring(obj); 621 if (strcmp(key, "0x") == 0) 622 portal_group->pg_dscp = strtol(key + 2, NULL, 16); 623 else if (strcmp(key, "be") || strcmp(key, "cs0")) 624 portal_group->pg_dscp = IPTOS_DSCP_CS0 >> 2; 625 else if (strcmp(key, "ef")) 626 portal_group->pg_dscp = IPTOS_DSCP_EF >> 2; 627 else if (strcmp(key, "cs0")) 628 portal_group->pg_dscp = IPTOS_DSCP_CS0 >> 2; 629 else if (strcmp(key, "cs1")) 630 portal_group->pg_dscp = IPTOS_DSCP_CS1 >> 2; 631 else if (strcmp(key, "cs2")) 632 portal_group->pg_dscp = IPTOS_DSCP_CS2 >> 2; 633 else if (strcmp(key, "cs3")) 634 portal_group->pg_dscp = IPTOS_DSCP_CS3 >> 2; 635 else if (strcmp(key, "cs4")) 636 portal_group->pg_dscp = IPTOS_DSCP_CS4 >> 2; 637 else if (strcmp(key, "cs5")) 638 portal_group->pg_dscp = IPTOS_DSCP_CS5 >> 2; 639 else if (strcmp(key, "cs6")) 640 portal_group->pg_dscp = IPTOS_DSCP_CS6 >> 2; 641 else if (strcmp(key, "cs7")) 642 portal_group->pg_dscp = IPTOS_DSCP_CS7 >> 2; 643 else if (strcmp(key, "af11")) 644 portal_group->pg_dscp = IPTOS_DSCP_AF11 >> 2; 645 else if (strcmp(key, "af12")) 646 portal_group->pg_dscp = IPTOS_DSCP_AF12 >> 2; 647 else if (strcmp(key, "af13")) 648 portal_group->pg_dscp = IPTOS_DSCP_AF13 >> 2; 649 else if (strcmp(key, "af21")) 650 portal_group->pg_dscp = IPTOS_DSCP_AF21 >> 2; 651 else if (strcmp(key, "af22")) 652 portal_group->pg_dscp = IPTOS_DSCP_AF22 >> 2; 653 else if (strcmp(key, "af23")) 654 portal_group->pg_dscp = IPTOS_DSCP_AF23 >> 2; 655 else if (strcmp(key, "af31")) 656 portal_group->pg_dscp = IPTOS_DSCP_AF31 >> 2; 657 else if (strcmp(key, "af32")) 658 portal_group->pg_dscp = IPTOS_DSCP_AF32 >> 2; 659 else if (strcmp(key, "af33")) 660 portal_group->pg_dscp = IPTOS_DSCP_AF33 >> 2; 661 else if (strcmp(key, "af41")) 662 portal_group->pg_dscp = IPTOS_DSCP_AF41 >> 2; 663 else if (strcmp(key, "af42")) 664 portal_group->pg_dscp = IPTOS_DSCP_AF42 >> 2; 665 else if (strcmp(key, "af43")) 666 portal_group->pg_dscp = IPTOS_DSCP_AF43 >> 2; 667 else { 668 log_warnx("\"dscp\" property value is not a supported textual value"); 669 return (1); 670 } 671 } 672 } 673 674 if (!strcmp(key, "pcp")) { 675 if (obj->type != UCL_INT) { 676 log_warnx("\"pcp\" property of portal group " 677 "\"%s\" is not an integer", portal_group->pg_name); 678 return(1); 679 } 680 portal_group->pg_pcp = ucl_object_toint(obj); 681 if (!((portal_group->pg_pcp >= 0) && (portal_group->pg_pcp <= 7))) { 682 log_warnx("invalid \"pcp\" value %d, using default", portal_group->pg_pcp); 683 portal_group->pg_pcp = -1; 684 } 685 } 686 } 687 688 return (0); 689 } 690 691 static int 692 uclparse_target(const char *name, const ucl_object_t *top) 693 { 694 struct target *target; 695 ucl_object_iter_t it = NULL, it2 = NULL; 696 const ucl_object_t *obj = NULL, *tmp = NULL; 697 const char *key; 698 699 target = target_new(conf, name); 700 if (target == NULL) 701 return (1); 702 703 while ((obj = ucl_iterate_object(top, &it, true))) { 704 key = ucl_object_key(obj); 705 706 if (!strcmp(key, "alias")) { 707 if (obj->type != UCL_STRING) { 708 log_warnx("\"alias\" property of target " 709 "\"%s\" is not a string", target->t_name); 710 return (1); 711 } 712 713 target->t_alias = strdup(ucl_object_tostring(obj)); 714 } 715 716 if (!strcmp(key, "auth-group")) { 717 if (target->t_auth_group != NULL) { 718 if (target->t_auth_group->ag_name != NULL) 719 log_warnx("auth-group for target \"%s\" " 720 "specified more than once", 721 target->t_name); 722 else 723 log_warnx("cannot use both auth-group " 724 "and explicit authorisations for " 725 "target \"%s\"", target->t_name); 726 return (1); 727 } 728 target->t_auth_group = auth_group_find(conf, 729 ucl_object_tostring(obj)); 730 if (target->t_auth_group == NULL) { 731 log_warnx("unknown auth-group \"%s\" for target " 732 "\"%s\"", ucl_object_tostring(obj), 733 target->t_name); 734 return (1); 735 } 736 } 737 738 if (!strcmp(key, "auth-type")) { 739 int error; 740 741 if (target->t_auth_group != NULL) { 742 if (target->t_auth_group->ag_name != NULL) { 743 log_warnx("cannot use both auth-group and " 744 "auth-type for target \"%s\"", 745 target->t_name); 746 return (1); 747 } 748 } else { 749 target->t_auth_group = auth_group_new(conf, NULL); 750 if (target->t_auth_group == NULL) 751 return (1); 752 753 target->t_auth_group->ag_target = target; 754 } 755 error = auth_group_set_type(target->t_auth_group, 756 ucl_object_tostring(obj)); 757 if (error != 0) 758 return (1); 759 } 760 761 if (!strcmp(key, "chap")) { 762 if (uclparse_chap(target->t_auth_group, obj) != 0) 763 return (1); 764 } 765 766 if (!strcmp(key, "chap-mutual")) { 767 if (uclparse_chap_mutual(target->t_auth_group, obj) != 0) 768 return (1); 769 } 770 771 if (!strcmp(key, "initiator-name")) { 772 const struct auth_name *an; 773 774 if (target->t_auth_group != NULL) { 775 if (target->t_auth_group->ag_name != NULL) { 776 log_warnx("cannot use both auth-group and " 777 "initiator-name for target \"%s\"", 778 target->t_name); 779 return (1); 780 } 781 } else { 782 target->t_auth_group = auth_group_new(conf, NULL); 783 if (target->t_auth_group == NULL) 784 return (1); 785 786 target->t_auth_group->ag_target = target; 787 } 788 an = auth_name_new(target->t_auth_group, 789 ucl_object_tostring(obj)); 790 if (an == NULL) 791 return (1); 792 } 793 794 if (!strcmp(key, "initiator-portal")) { 795 const struct auth_portal *ap; 796 797 if (target->t_auth_group != NULL) { 798 if (target->t_auth_group->ag_name != NULL) { 799 log_warnx("cannot use both auth-group and " 800 "initiator-portal for target \"%s\"", 801 target->t_name); 802 return (1); 803 } 804 } else { 805 target->t_auth_group = auth_group_new(conf, NULL); 806 if (target->t_auth_group == NULL) 807 return (1); 808 809 target->t_auth_group->ag_target = target; 810 } 811 ap = auth_portal_new(target->t_auth_group, 812 ucl_object_tostring(obj)); 813 if (ap == NULL) 814 return (1); 815 } 816 817 if (!strcmp(key, "portal-group")) { 818 if (obj->type == UCL_OBJECT) { 819 if (uclparse_target_portal_group(target, obj) != 0) 820 return (1); 821 } 822 823 if (obj->type == UCL_ARRAY) { 824 while ((tmp = ucl_iterate_object(obj, &it2, 825 true))) { 826 if (uclparse_target_portal_group(target, 827 tmp) != 0) 828 return (1); 829 } 830 } 831 } 832 833 if (!strcmp(key, "port")) { 834 struct pport *pp; 835 struct port *tp; 836 const char *value = ucl_object_tostring(obj); 837 int ret, i_pp, i_vp = 0; 838 839 ret = sscanf(value, "ioctl/%d/%d", &i_pp, &i_vp); 840 if (ret > 0) { 841 tp = port_new_ioctl(conf, target, i_pp, i_vp); 842 if (tp == NULL) { 843 log_warnx("can't create new ioctl port " 844 "for target \"%s\"", target->t_name); 845 return (1); 846 } 847 848 continue; 849 } 850 851 pp = pport_find(conf, value); 852 if (pp == NULL) { 853 log_warnx("unknown port \"%s\" for target \"%s\"", 854 value, target->t_name); 855 return (1); 856 } 857 if (!TAILQ_EMPTY(&pp->pp_ports)) { 858 log_warnx("can't link port \"%s\" to target \"%s\", " 859 "port already linked to some target", 860 value, target->t_name); 861 return (1); 862 } 863 tp = port_new_pp(conf, target, pp); 864 if (tp == NULL) { 865 log_warnx("can't link port \"%s\" to target \"%s\"", 866 value, target->t_name); 867 return (1); 868 } 869 } 870 871 if (!strcmp(key, "redirect")) { 872 if (obj->type != UCL_STRING) { 873 log_warnx("\"redirect\" property of target " 874 "\"%s\" is not a string", target->t_name); 875 return (1); 876 } 877 878 if (target_set_redirection(target, 879 ucl_object_tostring(obj)) != 0) 880 return (1); 881 } 882 883 if (!strcmp(key, "lun")) { 884 while ((tmp = ucl_iterate_object(obj, &it2, true))) { 885 if (uclparse_target_lun(target, tmp) != 0) 886 return (1); 887 } 888 } 889 } 890 891 return (0); 892 } 893 894 static int 895 uclparse_lun(const char *name, const ucl_object_t *top) 896 { 897 struct lun *lun; 898 ucl_object_iter_t it = NULL, child_it = NULL; 899 const ucl_object_t *obj = NULL, *child = NULL; 900 const char *key; 901 902 lun = lun_new(conf, name); 903 if (lun == NULL) 904 return (1); 905 906 while ((obj = ucl_iterate_object(top, &it, true))) { 907 key = ucl_object_key(obj); 908 909 if (!strcmp(key, "backend")) { 910 if (obj->type != UCL_STRING) { 911 log_warnx("\"backend\" property of lun " 912 "\"%s\" is not a string", 913 lun->l_name); 914 return (1); 915 } 916 917 lun_set_backend(lun, ucl_object_tostring(obj)); 918 } 919 920 if (!strcmp(key, "blocksize")) { 921 if (obj->type != UCL_INT) { 922 log_warnx("\"blocksize\" property of lun " 923 "\"%s\" is not an integer", lun->l_name); 924 return (1); 925 } 926 927 lun_set_blocksize(lun, ucl_object_toint(obj)); 928 } 929 930 if (!strcmp(key, "device-id")) { 931 if (obj->type != UCL_STRING) { 932 log_warnx("\"device-id\" property of lun " 933 "\"%s\" is not an integer", lun->l_name); 934 return (1); 935 } 936 937 lun_set_device_id(lun, ucl_object_tostring(obj)); 938 } 939 940 if (!strcmp(key, "options")) { 941 if (obj->type != UCL_OBJECT) { 942 log_warnx("\"options\" property of lun " 943 "\"%s\" is not an object", lun->l_name); 944 return (1); 945 } 946 947 while ((child = ucl_iterate_object(obj, &child_it, 948 true))) { 949 option_new(&lun->l_options, 950 ucl_object_key(child), 951 ucl_object_tostring_forced(child)); 952 } 953 } 954 955 if (!strcmp(key, "path")) { 956 if (obj->type != UCL_STRING) { 957 log_warnx("\"path\" property of lun " 958 "\"%s\" is not a string", lun->l_name); 959 return (1); 960 } 961 962 lun_set_path(lun, ucl_object_tostring(obj)); 963 } 964 965 if (!strcmp(key, "serial")) { 966 if (obj->type != UCL_STRING) { 967 log_warnx("\"serial\" property of lun " 968 "\"%s\" is not a string", lun->l_name); 969 return (1); 970 } 971 972 lun_set_serial(lun, ucl_object_tostring(obj)); 973 } 974 975 if (!strcmp(key, "size")) { 976 if (obj->type != UCL_INT) { 977 log_warnx("\"size\" property of lun " 978 "\"%s\" is not an integer", lun->l_name); 979 return (1); 980 } 981 982 lun_set_size(lun, ucl_object_toint(obj)); 983 } 984 } 985 986 return (0); 987 } 988 989 int 990 uclparse_conf(struct conf *newconf, const char *path) 991 { 992 struct ucl_parser *parser; 993 ucl_object_t *top; 994 int error; 995 996 conf = newconf; 997 parser = ucl_parser_new(0); 998 999 if (!ucl_parser_add_file(parser, path)) { 1000 log_warn("unable to parse configuration file %s: %s", path, 1001 ucl_parser_get_error(parser)); 1002 ucl_parser_free(parser); 1003 return (1); 1004 } 1005 1006 top = ucl_parser_get_object(parser); 1007 error = uclparse_toplevel(top); 1008 ucl_object_unref(top); 1009 ucl_parser_free(parser); 1010 1011 return (error); 1012 } 1013