1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $FreeBSD$ 32 */ 33 34 #include <sys/queue.h> 35 #include <sys/types.h> 36 #include <assert.h> 37 #include <stdio.h> 38 #include <stdint.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <ucl.h> 42 #include <netinet/in.h> 43 #include <netinet/ip.h> 44 45 #include "ctld.h" 46 47 static struct conf *conf = NULL; 48 49 static int uclparse_toplevel(const ucl_object_t *); 50 static int uclparse_chap(struct auth_group *, const ucl_object_t *); 51 static int uclparse_chap_mutual(struct auth_group *, const ucl_object_t *); 52 static int uclparse_lun(const char *, const ucl_object_t *); 53 static int uclparse_auth_group(const char *, const ucl_object_t *); 54 static int uclparse_portal_group(const char *, const ucl_object_t *); 55 static int uclparse_target(const char *, const ucl_object_t *); 56 static int uclparse_target_portal_group(struct target *, const ucl_object_t *); 57 static int uclparse_target_lun(struct target *, const ucl_object_t *); 58 59 static int 60 uclparse_chap(struct auth_group *auth_group, const ucl_object_t *obj) 61 { 62 const struct auth *ca; 63 const ucl_object_t *user, *secret; 64 65 user = ucl_object_find_key(obj, "user"); 66 if (!user || user->type != UCL_STRING) { 67 log_warnx("chap section in auth-group \"%s\" is missing " 68 "\"user\" string key", auth_group->ag_name); 69 return (1); 70 } 71 72 secret = ucl_object_find_key(obj, "secret"); 73 if (!secret || secret->type != UCL_STRING) { 74 log_warnx("chap section in auth-group \"%s\" is missing " 75 "\"secret\" string key", auth_group->ag_name); 76 } 77 78 ca = auth_new_chap(auth_group, 79 ucl_object_tostring(user), 80 ucl_object_tostring(secret)); 81 82 if (ca == NULL) 83 return (1); 84 85 return (0); 86 } 87 88 static int 89 uclparse_chap_mutual(struct auth_group *auth_group, const ucl_object_t *obj) 90 { 91 const struct auth *ca; 92 const ucl_object_t *user, *secret, *mutual_user; 93 const ucl_object_t *mutual_secret; 94 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 if (target->t_auth_group != NULL) { 720 if (target->t_auth_group->ag_name != NULL) 721 log_warnx("auth-group for target \"%s\" " 722 "specified more than once", 723 target->t_name); 724 else 725 log_warnx("cannot use both auth-group " 726 "and explicit authorisations for " 727 "target \"%s\"", target->t_name); 728 return (1); 729 } 730 target->t_auth_group = auth_group_find(conf, 731 ucl_object_tostring(obj)); 732 if (target->t_auth_group == NULL) { 733 log_warnx("unknown auth-group \"%s\" for target " 734 "\"%s\"", ucl_object_tostring(obj), 735 target->t_name); 736 return (1); 737 } 738 } 739 740 if (!strcmp(key, "auth-type")) { 741 int error; 742 743 if (target->t_auth_group != NULL) { 744 if (target->t_auth_group->ag_name != NULL) { 745 log_warnx("cannot use both auth-group and " 746 "auth-type for target \"%s\"", 747 target->t_name); 748 return (1); 749 } 750 } else { 751 target->t_auth_group = auth_group_new(conf, NULL); 752 if (target->t_auth_group == NULL) 753 return (1); 754 755 target->t_auth_group->ag_target = target; 756 } 757 error = auth_group_set_type(target->t_auth_group, 758 ucl_object_tostring(obj)); 759 if (error != 0) 760 return (1); 761 } 762 763 if (!strcmp(key, "chap")) { 764 if (uclparse_chap(target->t_auth_group, obj) != 0) 765 return (1); 766 } 767 768 if (!strcmp(key, "chap-mutual")) { 769 if (uclparse_chap_mutual(target->t_auth_group, obj) != 0) 770 return (1); 771 } 772 773 if (!strcmp(key, "initiator-name")) { 774 const struct auth_name *an; 775 776 if (target->t_auth_group != NULL) { 777 if (target->t_auth_group->ag_name != NULL) { 778 log_warnx("cannot use both auth-group and " 779 "initiator-name for target \"%s\"", 780 target->t_name); 781 return (1); 782 } 783 } else { 784 target->t_auth_group = auth_group_new(conf, NULL); 785 if (target->t_auth_group == NULL) 786 return (1); 787 788 target->t_auth_group->ag_target = target; 789 } 790 an = auth_name_new(target->t_auth_group, 791 ucl_object_tostring(obj)); 792 if (an == NULL) 793 return (1); 794 } 795 796 if (!strcmp(key, "initiator-portal")) { 797 const struct auth_portal *ap; 798 799 if (target->t_auth_group != NULL) { 800 if (target->t_auth_group->ag_name != NULL) { 801 log_warnx("cannot use both auth-group and " 802 "initiator-portal for target \"%s\"", 803 target->t_name); 804 return (1); 805 } 806 } else { 807 target->t_auth_group = auth_group_new(conf, NULL); 808 if (target->t_auth_group == NULL) 809 return (1); 810 811 target->t_auth_group->ag_target = target; 812 } 813 ap = auth_portal_new(target->t_auth_group, 814 ucl_object_tostring(obj)); 815 if (ap == NULL) 816 return (1); 817 } 818 819 if (!strcmp(key, "portal-group")) { 820 if (obj->type == UCL_OBJECT) { 821 if (uclparse_target_portal_group(target, obj) != 0) 822 return (1); 823 } 824 825 if (obj->type == UCL_ARRAY) { 826 while ((tmp = ucl_iterate_object(obj, &it2, 827 true))) { 828 if (uclparse_target_portal_group(target, 829 tmp) != 0) 830 return (1); 831 } 832 } 833 } 834 835 if (!strcmp(key, "port")) { 836 struct pport *pp; 837 struct port *tp; 838 const char *value = ucl_object_tostring(obj); 839 int ret, i_pp, i_vp = 0; 840 841 ret = sscanf(value, "ioctl/%d/%d", &i_pp, &i_vp); 842 if (ret > 0) { 843 tp = port_new_ioctl(conf, target, i_pp, i_vp); 844 if (tp == NULL) { 845 log_warnx("can't create new ioctl port " 846 "for target \"%s\"", target->t_name); 847 return (1); 848 } 849 850 return (0); 851 } 852 853 pp = pport_find(conf, value); 854 if (pp == NULL) { 855 log_warnx("unknown port \"%s\" for target \"%s\"", 856 value, target->t_name); 857 return (1); 858 } 859 if (!TAILQ_EMPTY(&pp->pp_ports)) { 860 log_warnx("can't link port \"%s\" to target \"%s\", " 861 "port already linked to some target", 862 value, target->t_name); 863 return (1); 864 } 865 tp = port_new_pp(conf, target, pp); 866 if (tp == NULL) { 867 log_warnx("can't link port \"%s\" to target \"%s\"", 868 value, target->t_name); 869 return (1); 870 } 871 } 872 873 if (!strcmp(key, "redirect")) { 874 if (obj->type != UCL_STRING) { 875 log_warnx("\"redirect\" property of target " 876 "\"%s\" is not a string", target->t_name); 877 return (1); 878 } 879 880 if (target_set_redirection(target, 881 ucl_object_tostring(obj)) != 0) 882 return (1); 883 } 884 885 if (!strcmp(key, "lun")) { 886 while ((tmp = ucl_iterate_object(obj, &it2, true))) { 887 if (uclparse_target_lun(target, tmp) != 0) 888 return (1); 889 } 890 } 891 } 892 893 return (0); 894 } 895 896 static int 897 uclparse_lun(const char *name, const ucl_object_t *top) 898 { 899 struct lun *lun; 900 ucl_object_iter_t it = NULL, child_it = NULL; 901 const ucl_object_t *obj = NULL, *child = NULL; 902 const char *key; 903 904 lun = lun_new(conf, name); 905 if (lun == NULL) 906 return (1); 907 908 while ((obj = ucl_iterate_object(top, &it, true))) { 909 key = ucl_object_key(obj); 910 911 if (!strcmp(key, "backend")) { 912 if (obj->type != UCL_STRING) { 913 log_warnx("\"backend\" property of lun " 914 "\"%s\" is not a string", 915 lun->l_name); 916 return (1); 917 } 918 919 lun_set_backend(lun, ucl_object_tostring(obj)); 920 } 921 922 if (!strcmp(key, "blocksize")) { 923 if (obj->type != UCL_INT) { 924 log_warnx("\"blocksize\" property of lun " 925 "\"%s\" is not an integer", lun->l_name); 926 return (1); 927 } 928 929 lun_set_blocksize(lun, ucl_object_toint(obj)); 930 } 931 932 if (!strcmp(key, "device-id")) { 933 if (obj->type != UCL_STRING) { 934 log_warnx("\"device-id\" property of lun " 935 "\"%s\" is not an integer", lun->l_name); 936 return (1); 937 } 938 939 lun_set_device_id(lun, ucl_object_tostring(obj)); 940 } 941 942 if (!strcmp(key, "options")) { 943 if (obj->type != UCL_OBJECT) { 944 log_warnx("\"options\" property of lun " 945 "\"%s\" is not an object", lun->l_name); 946 return (1); 947 } 948 949 while ((child = ucl_iterate_object(obj, &child_it, 950 true))) { 951 option_new(&lun->l_options, 952 ucl_object_key(child), 953 ucl_object_tostring_forced(child)); 954 } 955 } 956 957 if (!strcmp(key, "path")) { 958 if (obj->type != UCL_STRING) { 959 log_warnx("\"path\" property of lun " 960 "\"%s\" is not a string", lun->l_name); 961 return (1); 962 } 963 964 lun_set_path(lun, ucl_object_tostring(obj)); 965 } 966 967 if (!strcmp(key, "serial")) { 968 if (obj->type != UCL_STRING) { 969 log_warnx("\"serial\" property of lun " 970 "\"%s\" is not a string", lun->l_name); 971 return (1); 972 } 973 974 lun_set_serial(lun, ucl_object_tostring(obj)); 975 } 976 977 if (!strcmp(key, "size")) { 978 if (obj->type != UCL_INT) { 979 log_warnx("\"size\" property of lun " 980 "\"%s\" is not an integer", lun->l_name); 981 return (1); 982 } 983 984 lun_set_size(lun, ucl_object_toint(obj)); 985 } 986 } 987 988 return (0); 989 } 990 991 int 992 uclparse_conf(struct conf *newconf, const char *path) 993 { 994 struct ucl_parser *parser; 995 ucl_object_t *top; 996 int error; 997 998 conf = newconf; 999 parser = ucl_parser_new(0); 1000 1001 if (!ucl_parser_add_file(parser, path)) { 1002 log_warn("unable to parse configuration file %s: %s", path, 1003 ucl_parser_get_error(parser)); 1004 ucl_parser_free(parser); 1005 return (1); 1006 } 1007 1008 top = ucl_parser_get_object(parser); 1009 error = uclparse_toplevel(top); 1010 ucl_object_unref(top); 1011 ucl_parser_free(parser); 1012 1013 return (error); 1014 } 1015