1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2012 The FreeBSD Foundation 5 * 6 * This software was developed by Edward Tomasz Napierala under sponsorship 7 * from the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32 #include <sys/types.h> 33 #include <assert.h> 34 #include <stddef.h> 35 #include <stdint.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <stdbool.h> 39 #include <string.h> 40 #include <cam/scsi/scsi_all.h> 41 42 #include "conf.h" 43 #include "ctld.h" 44 45 static struct conf *conf = NULL; 46 static struct auth_group *auth_group = NULL; 47 static struct portal_group *portal_group = NULL; 48 static struct target *target = NULL; 49 static struct lun *lun = NULL; 50 51 void 52 conf_start(struct conf *new_conf) 53 { 54 assert(conf == NULL); 55 conf = new_conf; 56 } 57 58 void 59 conf_finish(void) 60 { 61 auth_group = NULL; 62 portal_group = NULL; 63 target = NULL; 64 lun = NULL; 65 conf = NULL; 66 } 67 68 bool 69 isns_add_server(const char *addr) 70 { 71 return (isns_new(conf, addr)); 72 } 73 74 void 75 conf_set_debug(int debug) 76 { 77 conf->conf_debug = debug; 78 } 79 80 void 81 conf_set_isns_period(int period) 82 { 83 conf->conf_isns_period = period; 84 } 85 86 void 87 conf_set_isns_timeout(int timeout) 88 { 89 conf->conf_isns_timeout = timeout; 90 } 91 92 void 93 conf_set_maxproc(int maxproc) 94 { 95 conf->conf_maxproc = maxproc; 96 } 97 98 bool 99 conf_set_pidfile_path(const char *path) 100 { 101 if (conf->conf_pidfile_path != NULL) { 102 log_warnx("pidfile specified more than once"); 103 return (false); 104 } 105 conf->conf_pidfile_path = checked_strdup(path); 106 return (true); 107 } 108 109 void 110 conf_set_timeout(int timeout) 111 { 112 conf->conf_timeout = timeout; 113 } 114 115 static bool 116 _auth_group_set_type(struct auth_group *ag, const char *str) 117 { 118 int type; 119 120 if (strcmp(str, "none") == 0) { 121 type = AG_TYPE_NO_AUTHENTICATION; 122 } else if (strcmp(str, "deny") == 0) { 123 type = AG_TYPE_DENY; 124 } else if (strcmp(str, "chap") == 0) { 125 type = AG_TYPE_CHAP; 126 } else if (strcmp(str, "chap-mutual") == 0) { 127 type = AG_TYPE_CHAP_MUTUAL; 128 } else { 129 log_warnx("invalid auth-type \"%s\" for %s", str, ag->ag_label); 130 return (false); 131 } 132 133 if (ag->ag_type != AG_TYPE_UNKNOWN && ag->ag_type != type) { 134 log_warnx("cannot set auth-type to \"%s\" for %s; " 135 "already has a different type", str, ag->ag_label); 136 return (false); 137 } 138 139 ag->ag_type = type; 140 141 return (true); 142 } 143 144 bool 145 auth_group_add_chap(const char *user, const char *secret) 146 { 147 return (auth_new_chap(auth_group, user, secret)); 148 } 149 150 bool 151 auth_group_add_chap_mutual(const char *user, const char *secret, 152 const char *user2, const char *secret2) 153 { 154 return (auth_new_chap_mutual(auth_group, user, secret, user2, secret2)); 155 } 156 157 bool 158 auth_group_add_initiator_name(const char *name) 159 { 160 return (auth_name_new(auth_group, name)); 161 } 162 163 bool 164 auth_group_add_initiator_portal(const char *portal) 165 { 166 return (auth_portal_new(auth_group, portal)); 167 } 168 169 bool 170 auth_group_set_type(const char *type) 171 { 172 return (_auth_group_set_type(auth_group, type)); 173 } 174 175 bool 176 auth_group_start(const char *name) 177 { 178 /* 179 * Make it possible to redefine the default auth-group. but 180 * only once. 181 */ 182 if (strcmp(name, "default") == 0) { 183 if (conf->conf_default_ag_defined) { 184 log_warnx("duplicated auth-group \"default\""); 185 return (false); 186 } 187 188 conf->conf_default_ag_defined = true; 189 auth_group = auth_group_find(conf, "default"); 190 return (true); 191 } 192 193 auth_group = auth_group_new(conf, name); 194 return (auth_group != NULL); 195 } 196 197 void 198 auth_group_finish(void) 199 { 200 auth_group = NULL; 201 } 202 203 bool 204 portal_group_start(const char *name) 205 { 206 /* 207 * Make it possible to redefine the default portal-group. but 208 * only once. 209 */ 210 if (strcmp(name, "default") == 0) { 211 if (conf->conf_default_pg_defined) { 212 log_warnx("duplicated portal-group \"default\""); 213 return (false); 214 } 215 216 conf->conf_default_pg_defined = true; 217 portal_group = portal_group_find(conf, "default"); 218 return (true); 219 } 220 221 portal_group = portal_group_new(conf, name); 222 return (portal_group != NULL); 223 } 224 225 void 226 portal_group_finish(void) 227 { 228 portal_group = NULL; 229 } 230 231 bool 232 portal_group_add_listen(const char *listen, bool iser) 233 { 234 return (portal_group_add_portal(portal_group, listen, iser)); 235 } 236 237 bool 238 portal_group_add_option(const char *name, const char *value) 239 { 240 return (option_new(portal_group->pg_options, name, value)); 241 } 242 243 bool 244 portal_group_set_discovery_auth_group(const char *name) 245 { 246 if (portal_group->pg_discovery_auth_group != NULL) { 247 log_warnx("discovery-auth-group for portal-group " 248 "\"%s\" specified more than once", 249 portal_group->pg_name); 250 return (false); 251 } 252 portal_group->pg_discovery_auth_group = auth_group_find(conf, name); 253 if (portal_group->pg_discovery_auth_group == NULL) { 254 log_warnx("unknown discovery-auth-group \"%s\" " 255 "for portal-group \"%s\"", name, portal_group->pg_name); 256 return (false); 257 } 258 return (true); 259 } 260 261 bool 262 portal_group_set_dscp(u_int dscp) 263 { 264 if (dscp >= 0x40) { 265 log_warnx("invalid DSCP value %u for portal-group \"%s\"", 266 dscp, portal_group->pg_name); 267 return (false); 268 } 269 270 portal_group->pg_dscp = dscp; 271 return (true); 272 } 273 274 bool 275 portal_group_set_filter(const char *str) 276 { 277 int filter; 278 279 if (strcmp(str, "none") == 0) { 280 filter = PG_FILTER_NONE; 281 } else if (strcmp(str, "portal") == 0) { 282 filter = PG_FILTER_PORTAL; 283 } else if (strcmp(str, "portal-name") == 0) { 284 filter = PG_FILTER_PORTAL_NAME; 285 } else if (strcmp(str, "portal-name-auth") == 0) { 286 filter = PG_FILTER_PORTAL_NAME_AUTH; 287 } else { 288 log_warnx("invalid discovery-filter \"%s\" for portal-group " 289 "\"%s\"; valid values are \"none\", \"portal\", " 290 "\"portal-name\", and \"portal-name-auth\"", 291 str, portal_group->pg_name); 292 return (false); 293 } 294 295 if (portal_group->pg_discovery_filter != PG_FILTER_UNKNOWN && 296 portal_group->pg_discovery_filter != filter) { 297 log_warnx("cannot set discovery-filter to \"%s\" for " 298 "portal-group \"%s\"; already has a different " 299 "value", str, portal_group->pg_name); 300 return (false); 301 } 302 303 portal_group->pg_discovery_filter = filter; 304 305 return (true); 306 } 307 308 void 309 portal_group_set_foreign(void) 310 { 311 portal_group->pg_foreign = true; 312 } 313 314 bool 315 portal_group_set_offload(const char *offload) 316 { 317 318 if (portal_group->pg_offload != NULL) { 319 log_warnx("cannot set offload to \"%s\" for " 320 "portal-group \"%s\"; already defined", 321 offload, portal_group->pg_name); 322 return (false); 323 } 324 325 portal_group->pg_offload = checked_strdup(offload); 326 327 return (true); 328 } 329 330 bool 331 portal_group_set_pcp(u_int pcp) 332 { 333 if (pcp > 7) { 334 log_warnx("invalid PCP value %u for portal-group \"%s\"", 335 pcp, portal_group->pg_name); 336 return (false); 337 } 338 339 portal_group->pg_pcp = pcp; 340 return (true); 341 } 342 343 bool 344 portal_group_set_redirection(const char *addr) 345 { 346 347 if (portal_group->pg_redirection != NULL) { 348 log_warnx("cannot set redirection to \"%s\" for " 349 "portal-group \"%s\"; already defined", 350 addr, portal_group->pg_name); 351 return (false); 352 } 353 354 portal_group->pg_redirection = checked_strdup(addr); 355 356 return (true); 357 } 358 359 void 360 portal_group_set_tag(uint16_t tag) 361 { 362 portal_group->pg_tag = tag; 363 } 364 365 bool 366 lun_start(const char *name) 367 { 368 lun = lun_new(conf, name); 369 return (lun != NULL); 370 } 371 372 void 373 lun_finish(void) 374 { 375 lun = NULL; 376 } 377 378 bool 379 lun_add_option(const char *name, const char *value) 380 { 381 return (option_new(lun->l_options, name, value)); 382 } 383 384 bool 385 lun_set_backend(const char *value) 386 { 387 if (lun->l_backend != NULL) { 388 log_warnx("backend for lun \"%s\" specified more than once", 389 lun->l_name); 390 return (false); 391 } 392 393 lun->l_backend = checked_strdup(value); 394 return (true); 395 } 396 397 bool 398 lun_set_blocksize(size_t value) 399 { 400 if (lun->l_blocksize != 0) { 401 log_warnx("blocksize for lun \"%s\" specified more than once", 402 lun->l_name); 403 return (false); 404 } 405 lun->l_blocksize = value; 406 return (true); 407 } 408 409 bool 410 lun_set_device_type(const char *value) 411 { 412 uint64_t device_type; 413 414 if (strcasecmp(value, "disk") == 0 || 415 strcasecmp(value, "direct") == 0) 416 device_type = T_DIRECT; 417 else if (strcasecmp(value, "processor") == 0) 418 device_type = T_PROCESSOR; 419 else if (strcasecmp(value, "cd") == 0 || 420 strcasecmp(value, "cdrom") == 0 || 421 strcasecmp(value, "dvd") == 0 || 422 strcasecmp(value, "dvdrom") == 0) 423 device_type = T_CDROM; 424 else if (expand_number(value, &device_type) != 0 || device_type > 15) { 425 log_warnx("invalid device-type \"%s\" for lun \"%s\"", value, 426 lun->l_name); 427 return (false); 428 } 429 430 lun->l_device_type = device_type; 431 return (true); 432 } 433 434 bool 435 lun_set_device_id(const char *value) 436 { 437 if (lun->l_device_id != NULL) { 438 log_warnx("device_id for lun \"%s\" specified more than once", 439 lun->l_name); 440 return (false); 441 } 442 443 lun->l_device_id = checked_strdup(value); 444 return (true); 445 } 446 447 bool 448 lun_set_path(const char *value) 449 { 450 if (lun->l_path != NULL) { 451 log_warnx("path for lun \"%s\" specified more than once", 452 lun->l_name); 453 return (false); 454 } 455 456 lun->l_path = checked_strdup(value); 457 return (true); 458 } 459 460 bool 461 lun_set_serial(const char *value) 462 { 463 if (lun->l_serial != NULL) { 464 log_warnx("serial for lun \"%s\" specified more than once", 465 lun->l_name); 466 return (false); 467 } 468 469 lun->l_serial = checked_strdup(value); 470 return (true); 471 } 472 473 bool 474 lun_set_size(uint64_t value) 475 { 476 if (lun->l_size != 0) { 477 log_warnx("size for lun \"%s\" specified more than once", 478 lun->l_name); 479 return (false); 480 } 481 482 lun->l_size = value; 483 return (true); 484 } 485 486 bool 487 lun_set_ctl_lun(uint32_t value) 488 { 489 490 if (lun->l_ctl_lun >= 0) { 491 log_warnx("ctl_lun for lun \"%s\" specified more than once", 492 lun->l_name); 493 return (false); 494 } 495 lun->l_ctl_lun = value; 496 return (true); 497 } 498 499 bool 500 target_start(const char *name) 501 { 502 target = target_new(conf, name); 503 return (target != NULL); 504 } 505 506 void 507 target_finish(void) 508 { 509 target = NULL; 510 } 511 512 bool 513 target_add_chap(const char *user, const char *secret) 514 { 515 if (target->t_auth_group != NULL) { 516 if (target->t_auth_group->ag_name != NULL) { 517 log_warnx("cannot use both auth-group and " 518 "chap for target \"%s\"", target->t_name); 519 return (false); 520 } 521 } else { 522 target->t_auth_group = auth_group_new(conf, target); 523 if (target->t_auth_group == NULL) 524 return (false); 525 } 526 return (auth_new_chap(target->t_auth_group, user, secret)); 527 } 528 529 bool 530 target_add_chap_mutual(const char *user, const char *secret, 531 const char *user2, const char *secret2) 532 { 533 if (target->t_auth_group != NULL) { 534 if (target->t_auth_group->ag_name != NULL) { 535 log_warnx("cannot use both auth-group and " 536 "chap-mutual for target \"%s\"", target->t_name); 537 return (false); 538 } 539 } else { 540 target->t_auth_group = auth_group_new(conf, target); 541 if (target->t_auth_group == NULL) 542 return (false); 543 } 544 return (auth_new_chap_mutual(target->t_auth_group, user, secret, user2, 545 secret2)); 546 } 547 548 bool 549 target_add_initiator_name(const char *name) 550 { 551 if (target->t_auth_group != NULL) { 552 if (target->t_auth_group->ag_name != NULL) { 553 log_warnx("cannot use both auth-group and " 554 "initiator-name for target \"%s\"", target->t_name); 555 return (false); 556 } 557 } else { 558 target->t_auth_group = auth_group_new(conf, target); 559 if (target->t_auth_group == NULL) 560 return (false); 561 } 562 return (auth_name_new(target->t_auth_group, name)); 563 } 564 565 bool 566 target_add_initiator_portal(const char *addr) 567 { 568 if (target->t_auth_group != NULL) { 569 if (target->t_auth_group->ag_name != NULL) { 570 log_warnx("cannot use both auth-group and " 571 "initiator-portal for target \"%s\"", 572 target->t_name); 573 return (false); 574 } 575 } else { 576 target->t_auth_group = auth_group_new(conf, target); 577 if (target->t_auth_group == NULL) 578 return (false); 579 } 580 return (auth_portal_new(target->t_auth_group, addr)); 581 } 582 583 bool 584 target_add_lun(u_int id, const char *name) 585 { 586 struct lun *t_lun; 587 588 if (id >= MAX_LUNS) { 589 log_warnx("LUN %u too big for target \"%s\"", id, 590 target->t_name); 591 return (false); 592 } 593 594 if (target->t_luns[id] != NULL) { 595 log_warnx("duplicate LUN %u for target \"%s\"", id, 596 target->t_name); 597 return (false); 598 } 599 600 t_lun = lun_find(conf, name); 601 if (t_lun == NULL) { 602 log_warnx("unknown LUN named %s used for target \"%s\"", 603 name, target->t_name); 604 return (false); 605 } 606 607 target->t_luns[id] = t_lun; 608 return (true); 609 } 610 611 bool 612 target_add_portal_group(const char *pg_name, const char *ag_name) 613 { 614 struct portal_group *pg; 615 struct auth_group *ag; 616 struct port *p; 617 618 pg = portal_group_find(conf, pg_name); 619 if (pg == NULL) { 620 log_warnx("unknown portal-group \"%s\" for target \"%s\"", 621 pg_name, target->t_name); 622 return (false); 623 } 624 625 if (ag_name != NULL) { 626 ag = auth_group_find(conf, ag_name); 627 if (ag == NULL) { 628 log_warnx("unknown auth-group \"%s\" for target \"%s\"", 629 ag_name, target->t_name); 630 return (false); 631 } 632 } else 633 ag = NULL; 634 635 p = port_new(conf, target, pg); 636 if (p == NULL) { 637 log_warnx("can't link portal-group \"%s\" to target \"%s\"", 638 pg_name, target->t_name); 639 return (false); 640 } 641 p->p_auth_group = ag; 642 return (true); 643 } 644 645 bool 646 target_set_alias(const char *alias) 647 { 648 if (target->t_alias != NULL) { 649 log_warnx("alias for target \"%s\" specified more than once", 650 target->t_name); 651 return (false); 652 } 653 target->t_alias = checked_strdup(alias); 654 return (true); 655 } 656 657 bool 658 target_set_auth_group(const char *name) 659 { 660 if (target->t_auth_group != NULL) { 661 if (target->t_auth_group->ag_name != NULL) 662 log_warnx("auth-group for target \"%s\" " 663 "specified more than once", target->t_name); 664 else 665 log_warnx("cannot use both auth-group and explicit " 666 "authorisations for target \"%s\"", target->t_name); 667 return (false); 668 } 669 target->t_auth_group = auth_group_find(conf, name); 670 if (target->t_auth_group == NULL) { 671 log_warnx("unknown auth-group \"%s\" for target \"%s\"", name, 672 target->t_name); 673 return (false); 674 } 675 return (true); 676 } 677 678 bool 679 target_set_auth_type(const char *type) 680 { 681 if (target->t_auth_group != NULL) { 682 if (target->t_auth_group->ag_name != NULL) { 683 log_warnx("cannot use both auth-group and " 684 "auth-type for target \"%s\"", target->t_name); 685 return (false); 686 } 687 } else { 688 target->t_auth_group = auth_group_new(conf, target); 689 if (target->t_auth_group == NULL) 690 return (false); 691 } 692 return (_auth_group_set_type(target->t_auth_group, type)); 693 } 694 695 bool 696 target_set_physical_port(const char *pport) 697 { 698 if (target->t_pport != NULL) { 699 log_warnx("cannot set multiple physical ports for target " 700 "\"%s\"", target->t_name); 701 return (false); 702 } 703 target->t_pport = checked_strdup(pport); 704 return (true); 705 } 706 707 bool 708 target_set_redirection(const char *addr) 709 { 710 711 if (target->t_redirection != NULL) { 712 log_warnx("cannot set redirection to \"%s\" for " 713 "target \"%s\"; already defined", 714 addr, target->t_name); 715 return (false); 716 } 717 718 target->t_redirection = checked_strdup(addr); 719 720 return (true); 721 } 722 723 bool 724 target_start_lun(u_int id) 725 { 726 struct lun *new_lun; 727 char *name; 728 729 if (id >= MAX_LUNS) { 730 log_warnx("LUN %u too big for target \"%s\"", id, 731 target->t_name); 732 return (false); 733 } 734 735 if (target->t_luns[id] != NULL) { 736 log_warnx("duplicate LUN %u for target \"%s\"", id, 737 target->t_name); 738 return (false); 739 } 740 741 if (asprintf(&name, "%s,lun,%u", target->t_name, id) <= 0) 742 log_err(1, "asprintf"); 743 744 new_lun = lun_new(conf, name); 745 if (new_lun == NULL) 746 return (false); 747 748 lun_set_scsiname(new_lun, name); 749 free(name); 750 751 target->t_luns[id] = new_lun; 752 753 lun = new_lun; 754 return (true); 755 } 756