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