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 <sys/event.h> 34 #include <sys/nv.h> 35 #include <sys/time.h> 36 #include <sys/socket.h> 37 #include <sys/stat.h> 38 #include <sys/wait.h> 39 #include <netinet/in.h> 40 #include <arpa/inet.h> 41 #include <assert.h> 42 #include <ctype.h> 43 #include <errno.h> 44 #include <libnvmf.h> 45 #include <netdb.h> 46 #include <signal.h> 47 #include <stdbool.h> 48 #include <stdio.h> 49 #include <stdint.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 #include <cam/scsi/scsi_all.h> 54 55 #include <algorithm> 56 #include <libutil++.hh> 57 58 #include "conf.h" 59 #include "ctld.hh" 60 #include "isns.hh" 61 62 bool proxy_mode = false; 63 64 static volatile bool sighup_received = false; 65 static volatile bool sigterm_received = false; 66 static volatile bool sigalrm_received = false; 67 68 static int kqfd; 69 static int nchildren = 0; 70 71 uint32_t conf::global_genctr; 72 73 static void 74 usage(void) 75 { 76 77 fprintf(stderr, "usage: ctld [-d][-u][-f config-file]\n"); 78 fprintf(stderr, " ctld -t [-u][-f config-file]\n"); 79 exit(1); 80 } 81 82 conf::conf() 83 { 84 conf_genctr = global_genctr++; 85 } 86 87 void 88 conf::set_debug(int debug) 89 { 90 conf_debug = debug; 91 } 92 93 void 94 conf::set_isns_period(int period) 95 { 96 conf_isns_period = period; 97 } 98 99 void 100 conf::set_isns_timeout(int timeout) 101 { 102 conf_isns_timeout = timeout; 103 } 104 105 void 106 conf::set_maxproc(int maxproc) 107 { 108 conf_maxproc = maxproc; 109 } 110 111 void 112 conf::set_timeout(int timeout) 113 { 114 conf_timeout = timeout; 115 } 116 117 bool 118 conf::set_pidfile_path(std::string_view path) 119 { 120 if (!conf_pidfile_path.empty()) { 121 log_warnx("pidfile specified more than once"); 122 return (false); 123 } 124 conf_pidfile_path = path; 125 return (true); 126 } 127 128 void 129 conf::open_pidfile() 130 { 131 const char *path; 132 pid_t otherpid; 133 134 assert(!conf_pidfile_path.empty()); 135 path = conf_pidfile_path.c_str(); 136 log_debugx("opening pidfile %s", path); 137 conf_pidfile = pidfile_open(path, 0600, &otherpid); 138 if (!conf_pidfile) { 139 if (errno == EEXIST) 140 log_errx(1, "daemon already running, pid: %jd.", 141 (intmax_t)otherpid); 142 log_err(1, "cannot open or create pidfile \"%s\"", path); 143 } 144 } 145 146 void 147 conf::write_pidfile() 148 { 149 conf_pidfile.write(); 150 } 151 152 void 153 conf::close_pidfile() 154 { 155 conf_pidfile.close(); 156 } 157 158 #ifdef ICL_KERNEL_PROXY 159 int 160 conf::add_proxy_portal(portal *portal) 161 { 162 conf_proxy_portals.push_back(portal); 163 return (conf_proxy_portals.size() - 1); 164 } 165 166 portal * 167 conf::proxy_portal(int id) 168 { 169 if (id >= conf_proxy_portals.size()) 170 return (nullptr); 171 return (conf_proxy_portals[id]); 172 } 173 #endif 174 175 bool 176 auth_group::set_type(const char *str) 177 { 178 auth_type type; 179 180 if (strcmp(str, "none") == 0) { 181 type = auth_type::NO_AUTHENTICATION; 182 } else if (strcmp(str, "deny") == 0) { 183 type = auth_type::DENY; 184 } else if (strcmp(str, "chap") == 0) { 185 type = auth_type::CHAP; 186 } else if (strcmp(str, "chap-mutual") == 0) { 187 type = auth_type::CHAP_MUTUAL; 188 } else { 189 log_warnx("invalid auth-type \"%s\" for %s", str, label()); 190 return (false); 191 } 192 193 if (ag_type != auth_type::UNKNOWN && ag_type != type) { 194 log_warnx("cannot set auth-type to \"%s\" for %s; " 195 "already has a different type", str, label()); 196 return (false); 197 } 198 199 ag_type = type; 200 201 return (true); 202 } 203 204 void 205 auth_group::set_type(auth_type type) 206 { 207 assert(ag_type == auth_type::UNKNOWN); 208 209 ag_type = type; 210 } 211 212 const struct auth * 213 auth_group::find_auth(std::string_view user) const 214 { 215 auto it = ag_auths.find(std::string(user)); 216 if (it == ag_auths.end()) 217 return (nullptr); 218 219 return (&it->second); 220 } 221 222 void 223 auth_group::check_secret_length(const char *user, const char *secret, 224 const char *secret_type) 225 { 226 size_t len; 227 228 len = strlen(secret); 229 assert(len != 0); 230 if (len > 16) { 231 log_warnx("%s for user \"%s\", %s, is too long; it should be " 232 "at most 16 characters long", secret_type, user, label()); 233 } 234 if (len < 12) { 235 log_warnx("%s for user \"%s\", %s, is too short; it should be " 236 "at least 12 characters long", secret_type, user, label()); 237 } 238 } 239 240 bool 241 auth_group::add_chap(const char *user, const char *secret) 242 { 243 if (ag_type == auth_type::UNKNOWN) 244 ag_type = auth_type::CHAP; 245 if (ag_type != auth_type::CHAP) { 246 log_warnx("cannot mix \"chap\" authentication with " 247 "other types for %s", label()); 248 return (false); 249 } 250 251 check_secret_length(user, secret, "secret"); 252 253 const auto &pair = ag_auths.try_emplace(user, secret); 254 if (!pair.second) { 255 log_warnx("duplicate credentials for user \"%s\" for %s", 256 user, label()); 257 return (false); 258 } 259 260 return (true); 261 } 262 263 bool 264 auth_group::add_chap_mutual(const char *user, const char *secret, 265 const char *user2, const char *secret2) 266 { 267 if (ag_type == auth_type::UNKNOWN) 268 ag_type = auth_type::CHAP_MUTUAL; 269 if (ag_type != auth_type::CHAP_MUTUAL) { 270 log_warnx("cannot mix \"chap-mutual\" authentication " 271 "with other types for %s", label()); 272 return (false); 273 } 274 275 check_secret_length(user, secret, "secret"); 276 check_secret_length(user, secret2, "mutual secret"); 277 278 const auto &pair = ag_auths.try_emplace(user, secret, user2, secret2); 279 if (!pair.second) { 280 log_warnx("duplicate credentials for user \"%s\" for %s", 281 user, label()); 282 return (false); 283 } 284 285 return (true); 286 } 287 288 bool 289 auth_group::add_host_nqn(std::string_view nqn) 290 { 291 /* Silently ignore duplicates. */ 292 ag_host_names.emplace(nqn); 293 return (true); 294 } 295 296 bool 297 auth_group::host_permitted(std::string_view nqn) const 298 { 299 if (ag_host_names.empty()) 300 return (true); 301 302 return (ag_host_names.count(std::string(nqn)) != 0); 303 } 304 305 bool 306 auth_group::add_initiator_name(std::string_view name) 307 { 308 /* Silently ignore duplicates. */ 309 ag_initiator_names.emplace(name); 310 return (true); 311 } 312 313 bool 314 auth_group::initiator_permitted(std::string_view initiator_name) const 315 { 316 if (ag_initiator_names.empty()) 317 return (true); 318 319 return (ag_initiator_names.count(std::string(initiator_name)) != 0); 320 } 321 322 bool 323 auth_portal::parse(const char *portal) 324 { 325 std::string net(portal); 326 std::string mask; 327 328 /* Split into 'net' (address) and 'mask'. */ 329 size_t pos = net.find('/'); 330 if (pos != net.npos) { 331 mask = net.substr(pos + 1); 332 if (mask.empty()) 333 return false; 334 net.resize(pos); 335 } 336 if (net.empty()) 337 return false; 338 339 /* 340 * If 'net' starts with a '[', ensure it ends with a ']' and 341 * force interpreting the address as IPv6. 342 */ 343 bool brackets = net[0] == '['; 344 if (brackets) { 345 net.erase(0, 1); 346 347 size_t len = net.length(); 348 if (len < 2) 349 return false; 350 if (net[len - 1] != ']') 351 return false; 352 net.resize(len - 1); 353 } 354 355 /* Parse address from 'net' and set default mask. */ 356 if (brackets || net.find(':') != net.npos) { 357 struct sockaddr_in6 *sin6 = 358 (struct sockaddr_in6 *)&ap_sa; 359 360 sin6->sin6_len = sizeof(*sin6); 361 sin6->sin6_family = AF_INET6; 362 if (inet_pton(AF_INET6, net.c_str(), &sin6->sin6_addr) <= 0) 363 return false; 364 ap_mask = sizeof(sin6->sin6_addr) * 8; 365 } else { 366 struct sockaddr_in *sin = 367 (struct sockaddr_in *)&ap_sa; 368 369 sin->sin_len = sizeof(*sin); 370 sin->sin_family = AF_INET; 371 if (inet_pton(AF_INET, net.c_str(), &sin->sin_addr) <= 0) 372 return false; 373 ap_mask = sizeof(sin->sin_addr) * 8; 374 } 375 376 /* Parse explicit mask if present. */ 377 if (!mask.empty()) { 378 char *tmp; 379 long m = strtol(mask.c_str(), &tmp, 0); 380 if (m < 0 || m > ap_mask || tmp[0] != 0) 381 return false; 382 ap_mask = m; 383 } 384 385 return true; 386 } 387 388 bool 389 auth_group::add_host_address(const char *address) 390 { 391 auth_portal ap; 392 if (!ap.parse(address)) { 393 log_warnx("invalid controller address \"%s\" for %s", address, 394 label()); 395 return (false); 396 } 397 398 ag_host_addresses.emplace_back(ap); 399 return (true); 400 } 401 402 bool 403 auth_group::add_initiator_portal(const char *portal) 404 { 405 auth_portal ap; 406 if (!ap.parse(portal)) { 407 log_warnx("invalid initiator portal \"%s\" for %s", portal, 408 label()); 409 return (false); 410 } 411 412 ag_initiator_portals.emplace_back(ap); 413 return (true); 414 } 415 416 bool 417 auth_portal::matches(const struct sockaddr *sa) const 418 { 419 const uint8_t *a, *b; 420 int i; 421 422 if (ap_sa.ss_family != sa->sa_family) 423 return (false); 424 425 if (sa->sa_family == AF_INET) { 426 a = (const uint8_t *) 427 &((const struct sockaddr_in *)sa)->sin_addr; 428 b = (const uint8_t *) 429 &((const struct sockaddr_in *)&ap_sa)->sin_addr; 430 } else { 431 a = (const uint8_t *) 432 &((const struct sockaddr_in6 *)sa)->sin6_addr; 433 b = (const uint8_t *) 434 &((const struct sockaddr_in6 *)&ap_sa)->sin6_addr; 435 } 436 for (i = 0; i < ap_mask / 8; i++) { 437 if (a[i] != b[i]) 438 return (false); 439 } 440 if ((ap_mask % 8) != 0) { 441 uint8_t bmask = 0xff << (8 - (ap_mask % 8)); 442 if ((a[i] & bmask) != (b[i] & bmask)) 443 return (false); 444 } 445 return (true); 446 } 447 448 bool 449 auth_group::host_permitted(const struct sockaddr *sa) const 450 { 451 if (ag_host_addresses.empty()) 452 return (true); 453 454 for (const auth_portal &ap : ag_host_addresses) 455 if (ap.matches(sa)) 456 return (true); 457 return (false); 458 } 459 460 bool 461 auth_group::initiator_permitted(const struct sockaddr *sa) const 462 { 463 if (ag_initiator_portals.empty()) 464 return (true); 465 466 for (const auth_portal &ap : ag_initiator_portals) 467 if (ap.matches(sa)) 468 return (true); 469 return (false); 470 } 471 472 struct auth_group * 473 conf::add_auth_group(const char *name) 474 { 475 const auto &pair = conf_auth_groups.try_emplace(name, 476 std::make_shared<auth_group>(freebsd::stringf("auth-group \"%s\"", 477 name))); 478 if (!pair.second) { 479 log_warnx("duplicated auth-group \"%s\"", name); 480 return (NULL); 481 } 482 483 return (pair.first->second.get()); 484 } 485 486 /* 487 * Make it possible to redefine the default auth-group, but only once. 488 */ 489 struct auth_group * 490 conf::define_default_auth_group() 491 { 492 if (conf_default_ag_defined) { 493 log_warnx("duplicated auth-group \"default\""); 494 return (nullptr); 495 } 496 497 conf_default_ag_defined = true; 498 return (find_auth_group("default").get()); 499 } 500 501 auth_group_sp 502 conf::find_auth_group(std::string_view name) 503 { 504 auto it = conf_auth_groups.find(std::string(name)); 505 if (it == conf_auth_groups.end()) 506 return {}; 507 508 return (it->second); 509 } 510 511 portal_group::portal_group(struct conf *conf, std::string_view name) : 512 pg_conf(conf), pg_options(nvlist_create(0)), pg_name(name) 513 { 514 } 515 516 struct portal_group * 517 conf::add_portal_group(const char *name) 518 { 519 auto pair = conf_portal_groups.try_emplace(name, 520 iscsi_make_portal_group(this, name)); 521 if (!pair.second) { 522 log_warnx("duplicated portal-group \"%s\"", name); 523 return (nullptr); 524 } 525 526 return (pair.first->second.get()); 527 } 528 529 /* 530 * Make it possible to redefine the default portal-group, but only 531 * once. 532 */ 533 struct portal_group * 534 conf::define_default_portal_group() 535 { 536 if (conf_default_pg_defined) { 537 log_warnx("duplicated portal-group \"default\""); 538 return (nullptr); 539 } 540 541 conf_default_pg_defined = true; 542 return (find_portal_group("default")); 543 } 544 545 struct portal_group * 546 conf::find_portal_group(std::string_view name) 547 { 548 auto it = conf_portal_groups.find(std::string(name)); 549 if (it == conf_portal_groups.end()) 550 return (nullptr); 551 552 return (it->second.get()); 553 } 554 555 struct portal_group * 556 conf::add_transport_group(const char *name) 557 { 558 auto pair = conf_transport_groups.try_emplace(name, 559 nvmf_make_transport_group(this, name)); 560 if (!pair.second) { 561 log_warnx("duplicated transport-group \"%s\"", name); 562 return (nullptr); 563 } 564 565 return (pair.first->second.get()); 566 } 567 568 /* 569 * Make it possible to redefine the default transport-group, but only 570 * once. 571 */ 572 struct portal_group * 573 conf::define_default_transport_group() 574 { 575 if (conf_default_tg_defined) { 576 log_warnx("duplicated transport-group \"default\""); 577 return (nullptr); 578 } 579 580 conf_default_tg_defined = true; 581 return (find_transport_group("default")); 582 } 583 584 struct portal_group * 585 conf::find_transport_group(std::string_view name) 586 { 587 auto it = conf_transport_groups.find(std::string(name)); 588 if (it == conf_transport_groups.end()) 589 return (nullptr); 590 591 return (it->second.get()); 592 } 593 594 bool 595 portal_group::is_dummy() const 596 { 597 if (pg_foreign) 598 return (true); 599 if (pg_portals.empty()) 600 return (true); 601 return (false); 602 } 603 604 freebsd::addrinfo_up 605 parse_addr_port(const char *address, const char *def_port) 606 { 607 struct addrinfo hints, *ai; 608 int error; 609 610 std::string addr(address); 611 std::string port(def_port); 612 if (addr[0] == '[') { 613 /* 614 * IPv6 address in square brackets, perhaps with port. 615 */ 616 addr.erase(0, 1); 617 size_t pos = addr.find(']'); 618 if (pos == 0 || pos == addr.npos) 619 return {}; 620 if (pos < addr.length() - 1) { 621 port = addr.substr(pos + 1); 622 if (port[0] != ':' || port.length() < 2) 623 return {}; 624 port.erase(0, 1); 625 } 626 addr.resize(pos); 627 } else { 628 /* 629 * Either IPv6 address without brackets - and without 630 * a port - or IPv4 address. Just count the colons. 631 */ 632 size_t pos = addr.find(':'); 633 if (pos != addr.npos && addr.find(':', pos + 1) == addr.npos) { 634 /* Only a single colon at `pos`. */ 635 if (pos == addr.length() - 1) 636 return {}; 637 port = addr.substr(pos + 1); 638 addr.resize(pos); 639 } 640 } 641 642 memset(&hints, 0, sizeof(hints)); 643 hints.ai_family = PF_UNSPEC; 644 hints.ai_socktype = SOCK_STREAM; 645 hints.ai_flags = AI_PASSIVE; 646 error = getaddrinfo(addr.c_str(), port.c_str(), &hints, &ai); 647 if (error != 0) 648 return {}; 649 return freebsd::addrinfo_up(ai); 650 } 651 652 void 653 portal_group::add_port(struct portal_group_port *port) 654 { 655 pg_ports.emplace(port->target()->name(), port); 656 } 657 658 void 659 portal_group::remove_port(struct portal_group_port *port) 660 { 661 auto it = pg_ports.find(port->target()->name()); 662 pg_ports.erase(it); 663 } 664 665 freebsd::nvlist_up 666 portal_group::options() const 667 { 668 return (freebsd::nvlist_up(nvlist_clone(pg_options.get()))); 669 } 670 671 bool 672 portal_group::add_option(const char *name, const char *value) 673 { 674 return (option_new(pg_options.get(), name, value)); 675 } 676 677 bool 678 portal_group::set_discovery_auth_group(const char *ag_name) 679 { 680 if (pg_discovery_auth_group != nullptr) { 681 log_warnx("discovery-auth-group for %s " 682 "\"%s\" specified more than once", keyword(), name()); 683 return (false); 684 } 685 pg_discovery_auth_group = pg_conf->find_auth_group(ag_name); 686 if (pg_discovery_auth_group == nullptr) { 687 log_warnx("unknown discovery-auth-group \"%s\" " 688 "for %s \"%s\"", ag_name, keyword(), name()); 689 return (false); 690 } 691 return (true); 692 } 693 694 bool 695 portal_group::set_dscp(u_int dscp) 696 { 697 if (dscp >= 0x40) { 698 log_warnx("invalid DSCP value %u for %s \"%s\"", 699 dscp, keyword(), name()); 700 return (false); 701 } 702 703 pg_dscp = dscp; 704 return (true); 705 } 706 707 void 708 portal_group::set_foreign() 709 { 710 pg_foreign = true; 711 } 712 713 bool 714 portal_group::set_offload(const char *offload) 715 { 716 if (!pg_offload.empty()) { 717 log_warnx("cannot set offload to \"%s\" for " 718 "%s \"%s\"; already defined", 719 offload, keyword(), name()); 720 return (false); 721 } 722 723 pg_offload = offload; 724 return (true); 725 } 726 727 bool 728 portal_group::set_pcp(u_int pcp) 729 { 730 if (pcp > 7) { 731 log_warnx("invalid PCP value %u for %s \"%s\"", 732 pcp, keyword(), name()); 733 return (false); 734 } 735 736 pg_pcp = pcp; 737 return (true); 738 } 739 740 bool 741 portal_group::set_redirection(const char *addr) 742 { 743 if (!pg_redirection.empty()) { 744 log_warnx("cannot set redirection to \"%s\" for " 745 "%s \"%s\"; already defined", 746 addr, keyword(), name()); 747 return (false); 748 } 749 750 pg_redirection = addr; 751 return (true); 752 } 753 754 void 755 portal_group::set_tag(uint16_t tag) 756 { 757 pg_tag = tag; 758 } 759 760 void 761 portal_group::verify(struct conf *conf) 762 { 763 if (pg_discovery_auth_group == nullptr) { 764 pg_discovery_auth_group = conf->find_auth_group("default"); 765 assert(pg_discovery_auth_group != nullptr); 766 } 767 768 if (pg_discovery_filter == discovery_filter::UNKNOWN) 769 pg_discovery_filter = discovery_filter::NONE; 770 771 if (!pg_redirection.empty()) { 772 if (!pg_ports.empty()) { 773 log_debugx("%s \"%s\" assigned to target, " 774 "but configured for redirection", keyword(), 775 name()); 776 } 777 pg_assigned = true; 778 } else if (!pg_ports.empty()) { 779 pg_assigned = true; 780 } else { 781 if (pg_name != "default") 782 log_warnx("%s \"%s\" not assigned " 783 "to any target", keyword(), name()); 784 pg_assigned = false; 785 } 786 } 787 788 /* 789 * Try to reuse a socket for 'newp' from an existing socket in one of 790 * our portals. 791 */ 792 bool 793 portal_group::reuse_socket(struct portal &newp) 794 { 795 for (portal_up &portal : pg_portals) { 796 if (newp.reuse_socket(*portal)) 797 return (true); 798 } 799 return (false); 800 } 801 802 int 803 portal_group::open_sockets(struct conf &oldconf) 804 { 805 int cumulated_error = 0; 806 807 if (pg_foreign) 808 return (0); 809 810 if (!pg_assigned) { 811 log_debugx("not listening on %s \"%s\", " 812 "not assigned to any target", keyword(), name()); 813 return (0); 814 } 815 816 for (portal_up &portal : pg_portals) { 817 /* 818 * Try to find already open portal and reuse the 819 * listening socket. We don't care about what portal 820 * or portal group that was, what matters is the 821 * listening address. 822 */ 823 if (oldconf.reuse_portal_group_socket(*portal)) 824 continue; 825 826 if (!portal->init_socket()) { 827 cumulated_error++; 828 continue; 829 } 830 } 831 return (cumulated_error); 832 } 833 834 void 835 portal_group::close_sockets() 836 { 837 for (portal_up &portal : pg_portals) { 838 if (portal->socket() < 0) 839 continue; 840 log_debugx("closing socket for %s, %s \"%s\"", 841 portal->listen(), keyword(), name()); 842 portal->close(); 843 } 844 } 845 846 bool 847 conf::add_isns(const char *addr) 848 { 849 if (conf_isns.count(addr) > 0) { 850 log_warnx("duplicate iSNS address %s", addr); 851 return (false); 852 } 853 854 freebsd::addrinfo_up ai = parse_addr_port(addr, "3205"); 855 if (!ai) { 856 log_warnx("invalid iSNS address %s", addr); 857 return (false); 858 } 859 860 /* 861 * XXX: getaddrinfo(3) may return multiple addresses; we should turn 862 * those into multiple servers. 863 */ 864 865 conf_isns.emplace(addr, isns(addr, std::move(ai))); 866 return (true); 867 } 868 869 870 freebsd::fd_up 871 isns::connect() 872 { 873 freebsd::fd_up s; 874 875 s = socket(i_ai->ai_family, i_ai->ai_socktype, i_ai->ai_protocol); 876 if (!s) { 877 log_warn("socket(2) failed for %s", addr()); 878 return (s); 879 } 880 if (::connect(s, i_ai->ai_addr, i_ai->ai_addrlen)) { 881 log_warn("connect(2) failed for %s", addr()); 882 s.reset(); 883 } 884 return (s); 885 } 886 887 bool 888 isns::send_request(int s, struct isns_req req) 889 { 890 if (!req.send(s)) { 891 log_warn("send(2) failed for %s", addr()); 892 return (false); 893 } 894 if (!req.receive(s)) { 895 log_warn("receive(2) failed for %s", addr()); 896 return (false); 897 } 898 uint32_t error = req.get_status(); 899 if (error != 0) { 900 log_warnx("iSNS %s error %u for %s", req.descr(), error, 901 addr()); 902 return (false); 903 } 904 return (true); 905 } 906 907 struct isns_req 908 conf::isns_register_request(const char *hostname) 909 { 910 const struct portal_group *pg; 911 912 isns_req req(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT, "register"); 913 req.add_str(32, conf_first_target->name()); 914 req.add_delim(); 915 req.add_str(1, hostname); 916 req.add_32(2, 2); /* 2 -- iSCSI */ 917 req.add_32(6, conf_isns_period); 918 for (const auto &kv : conf_portal_groups) { 919 pg = kv.second.get(); 920 921 if (!pg->assigned()) 922 continue; 923 for (const portal_up &portal : pg->portals()) { 924 req.add_addr(16, portal->ai()); 925 req.add_port(17, portal->ai()); 926 } 927 } 928 for (const auto &kv : conf_targets) { 929 const struct target *target = kv.second.get(); 930 931 req.add_str(32, target->name()); 932 req.add_32(33, 1); /* 1 -- Target*/ 933 if (target->has_alias()) 934 req.add_str(34, target->alias()); 935 for (const port *port : target->ports()) { 936 pg = port->portal_group(); 937 if (pg == nullptr) 938 continue; 939 req.add_32(51, pg->tag()); 940 for (const portal_up &portal : pg->portals()) { 941 req.add_addr(49, portal->ai()); 942 req.add_port(50, portal->ai()); 943 } 944 } 945 } 946 return (req); 947 } 948 949 struct isns_req 950 conf::isns_check_request(const char *hostname) 951 { 952 isns_req req(ISNS_FUNC_DEVATTRQRY, ISNS_FLAG_CLIENT, "check"); 953 req.add_str(32, conf_first_target->name()); 954 req.add_str(1, hostname); 955 req.add_delim(); 956 req.add(2, 0, NULL); 957 return (req); 958 } 959 960 struct isns_req 961 conf::isns_deregister_request(const char *hostname) 962 { 963 isns_req req(ISNS_FUNC_DEVDEREG, ISNS_FLAG_CLIENT, "deregister"); 964 req.add_str(32, conf_first_target->name()); 965 req.add_delim(); 966 req.add_str(1, hostname); 967 return (req); 968 } 969 970 void 971 conf::isns_register_targets(struct isns *isns, struct conf *oldconf) 972 { 973 int error; 974 char hostname[256]; 975 976 if (conf_targets.empty() || conf_portal_groups.empty()) 977 return; 978 start_timer(conf_isns_timeout); 979 freebsd::fd_up s = isns->connect(); 980 if (!s) { 981 stop_timer(); 982 return; 983 } 984 error = gethostname(hostname, sizeof(hostname)); 985 if (error != 0) 986 log_err(1, "gethostname"); 987 988 if (oldconf == nullptr || oldconf->conf_first_target == nullptr) 989 oldconf = this; 990 isns->send_request(s, oldconf->isns_deregister_request(hostname)); 991 isns->send_request(s, isns_register_request(hostname)); 992 s.reset(); 993 stop_timer(); 994 } 995 996 void 997 conf::isns_check(struct isns *isns) 998 { 999 int error; 1000 char hostname[256]; 1001 1002 if (conf_targets.empty() || conf_portal_groups.empty()) 1003 return; 1004 start_timer(conf_isns_timeout); 1005 freebsd::fd_up s = isns->connect(); 1006 if (!s) { 1007 stop_timer(); 1008 return; 1009 } 1010 error = gethostname(hostname, sizeof(hostname)); 1011 if (error != 0) 1012 log_err(1, "gethostname"); 1013 1014 if (!isns->send_request(s, isns_check_request(hostname))) { 1015 isns->send_request(s, isns_deregister_request(hostname)); 1016 isns->send_request(s, isns_register_request(hostname)); 1017 } 1018 s.reset(); 1019 stop_timer(); 1020 } 1021 1022 void 1023 conf::isns_deregister_targets(struct isns *isns) 1024 { 1025 int error; 1026 char hostname[256]; 1027 1028 if (conf_targets.empty() || conf_portal_groups.empty()) 1029 return; 1030 start_timer(conf_isns_timeout); 1031 freebsd::fd_up s = isns->connect(); 1032 if (!s) 1033 return; 1034 error = gethostname(hostname, sizeof(hostname)); 1035 if (error != 0) 1036 log_err(1, "gethostname"); 1037 1038 isns->send_request(s, isns_deregister_request(hostname)); 1039 s.reset(); 1040 stop_timer(); 1041 } 1042 1043 void 1044 conf::isns_schedule_update() 1045 { 1046 if (!conf_isns.empty()) 1047 start_timer((conf_isns_period + 2) / 3); 1048 } 1049 1050 void 1051 conf::isns_update() 1052 { 1053 stop_timer(); 1054 for (auto &kv : conf_isns) 1055 isns_check(&kv.second); 1056 1057 isns_schedule_update(); 1058 } 1059 1060 bool 1061 kports::add_port(std::string &name, uint32_t ctl_port) 1062 { 1063 const auto &pair = pports.try_emplace(name, name, ctl_port); 1064 if (!pair.second) { 1065 log_warnx("duplicate kernel port \"%s\" (%u)", name.c_str(), 1066 ctl_port); 1067 return (false); 1068 } 1069 1070 return (true); 1071 } 1072 1073 bool 1074 kports::has_port(std::string_view name) 1075 { 1076 return (pports.count(std::string(name)) > 0); 1077 } 1078 1079 struct pport * 1080 kports::find_port(std::string_view name) 1081 { 1082 auto it = pports.find(std::string(name)); 1083 if (it == pports.end()) 1084 return (nullptr); 1085 return (&it->second); 1086 } 1087 1088 port::port(struct target *target) : 1089 p_target(target) 1090 { 1091 target->add_port(this); 1092 } 1093 1094 void 1095 port::clear_references() 1096 { 1097 p_target->remove_port(this); 1098 } 1099 1100 portal_group_port::portal_group_port(struct target *target, 1101 struct portal_group *pg, auth_group_sp ag) : 1102 port(target), p_auth_group(ag), p_portal_group(pg) 1103 { 1104 p_portal_group->add_port(this); 1105 } 1106 1107 portal_group_port::portal_group_port(struct target *target, 1108 struct portal_group *pg, uint32_t ctl_port) : 1109 port(target), p_portal_group(pg) 1110 { 1111 p_ctl_port = ctl_port; 1112 p_portal_group->add_port(this); 1113 } 1114 1115 bool 1116 portal_group_port::is_dummy() const 1117 { 1118 return (p_portal_group->is_dummy()); 1119 } 1120 1121 void 1122 portal_group_port::clear_references() 1123 { 1124 p_portal_group->remove_port(this); 1125 port::clear_references(); 1126 } 1127 1128 bool 1129 conf::add_port(struct target *target, struct portal_group *pg, auth_group_sp ag) 1130 { 1131 std::string name = freebsd::stringf("%s-%s", pg->name(), 1132 target->name()); 1133 const auto &pair = conf_ports.try_emplace(name, pg->create_port(target, 1134 ag)); 1135 if (!pair.second) { 1136 log_warnx("duplicate port \"%s\"", name.c_str()); 1137 return (false); 1138 } 1139 1140 return (true); 1141 } 1142 1143 bool 1144 conf::add_port(struct target *target, struct portal_group *pg, 1145 uint32_t ctl_port) 1146 { 1147 std::string name = freebsd::stringf("%s-%s", pg->name(), 1148 target->name()); 1149 const auto &pair = conf_ports.try_emplace(name, pg->create_port(target, 1150 ctl_port)); 1151 if (!pair.second) { 1152 log_warnx("duplicate port \"%s\"", name.c_str()); 1153 return (false); 1154 } 1155 1156 return (true); 1157 } 1158 1159 bool 1160 conf::add_port(struct target *target, struct pport *pp) 1161 { 1162 std::string name = freebsd::stringf("%s-%s", pp->name(), 1163 target->name()); 1164 const auto &pair = conf_ports.try_emplace(name, 1165 std::make_unique<kernel_port>(target, pp)); 1166 if (!pair.second) { 1167 log_warnx("duplicate port \"%s\"", name.c_str()); 1168 return (false); 1169 } 1170 1171 pp->link(); 1172 return (true); 1173 } 1174 1175 bool 1176 conf::add_port(struct kports &kports, struct target *target, int pp, int vp) 1177 { 1178 struct pport *pport; 1179 1180 std::string pname = freebsd::stringf("ioctl/%d/%d", pp, vp); 1181 1182 pport = kports.find_port(pname); 1183 if (pport != NULL) 1184 return (add_port(target, pport)); 1185 1186 std::string name = pname + "-" + target->name(); 1187 const auto &pair = conf_ports.try_emplace(name, 1188 std::make_unique<ioctl_port>(target, pp, vp)); 1189 if (!pair.second) { 1190 log_warnx("duplicate port \"%s\"", name.c_str()); 1191 return (false); 1192 } 1193 1194 return (true); 1195 } 1196 1197 const struct port * 1198 portal_group::find_port(std::string_view target) const 1199 { 1200 auto it = pg_ports.find(std::string(target)); 1201 if (it == pg_ports.end()) 1202 return (nullptr); 1203 return (it->second); 1204 } 1205 1206 struct target * 1207 conf::add_controller(const char *name) 1208 { 1209 if (!nvmf_nqn_valid_strict(name)) { 1210 log_warnx("controller name \"%s\" is invalid for NVMe", name); 1211 return nullptr; 1212 } 1213 1214 /* 1215 * Normalize the name to lowercase to match iSCSI. 1216 */ 1217 std::string t_name(name); 1218 for (char &c : t_name) 1219 c = tolower(c); 1220 1221 auto const &pair = conf_controllers.try_emplace(t_name, 1222 nvmf_make_controller(this, t_name)); 1223 if (!pair.second) { 1224 log_warnx("duplicated controller \"%s\"", name); 1225 return nullptr; 1226 } 1227 1228 return pair.first->second.get(); 1229 } 1230 1231 struct target * 1232 conf::find_controller(std::string_view name) 1233 { 1234 auto it = conf_controllers.find(std::string(name)); 1235 if (it == conf_controllers.end()) 1236 return nullptr; 1237 return it->second.get(); 1238 } 1239 1240 target::target(struct conf *conf, const char *keyword, std::string_view name) : 1241 t_conf(conf), t_name(name) 1242 { 1243 t_label = freebsd::stringf("%s \"%s\"", keyword, t_name.c_str()); 1244 } 1245 1246 struct target * 1247 conf::add_target(const char *name) 1248 { 1249 if (!valid_iscsi_name(name, log_warnx)) 1250 return (nullptr); 1251 1252 /* 1253 * RFC 3722 requires us to normalize the name to lowercase. 1254 */ 1255 std::string t_name(name); 1256 for (char &c : t_name) 1257 c = tolower(c); 1258 1259 auto const &pair = conf_targets.try_emplace(t_name, 1260 iscsi_make_target(this, t_name)); 1261 if (!pair.second) { 1262 log_warnx("duplicated target \"%s\"", name); 1263 return (NULL); 1264 } 1265 1266 if (conf_first_target == nullptr) 1267 conf_first_target = pair.first->second.get(); 1268 return (pair.first->second.get()); 1269 } 1270 1271 struct target * 1272 conf::find_target(std::string_view name) 1273 { 1274 auto it = conf_targets.find(std::string(name)); 1275 if (it == conf_targets.end()) 1276 return (nullptr); 1277 return (it->second.get()); 1278 } 1279 1280 bool 1281 target::use_private_auth(const char *keyword) 1282 { 1283 if (t_private_auth) 1284 return (true); 1285 1286 if (t_auth_group != nullptr) { 1287 log_warnx("cannot use both auth-group and %s for %s", 1288 keyword, label()); 1289 return (false); 1290 } 1291 1292 t_auth_group = std::make_shared<struct auth_group>(t_label); 1293 t_private_auth = true; 1294 return (true); 1295 } 1296 1297 bool 1298 target::add_chap(const char *user, const char *secret) 1299 { 1300 if (!use_private_auth("chap")) 1301 return (false); 1302 return (t_auth_group->add_chap(user, secret)); 1303 } 1304 1305 bool 1306 target::add_chap_mutual(const char *user, const char *secret, 1307 const char *user2, const char *secret2) 1308 { 1309 if (!use_private_auth("chap-mutual")) 1310 return (false); 1311 return (t_auth_group->add_chap_mutual(user, secret, user2, secret2)); 1312 } 1313 1314 bool 1315 target::add_lun(u_int id, const char *lun_label, const char *lun_name) 1316 { 1317 struct lun *t_lun; 1318 1319 if (id >= MAX_LUNS) { 1320 log_warnx("%s too big for %s", lun_label, label()); 1321 return (false); 1322 } 1323 1324 if (t_luns[id] != NULL) { 1325 log_warnx("duplicate %s for %s", lun_label, label()); 1326 return (false); 1327 } 1328 1329 t_lun = t_conf->find_lun(lun_name); 1330 if (t_lun == NULL) { 1331 log_warnx("unknown LUN named %s used for %s", lun_name, 1332 label()); 1333 return (false); 1334 } 1335 1336 t_luns[id] = t_lun; 1337 return (true); 1338 } 1339 1340 bool 1341 target::set_alias(std::string_view alias) 1342 { 1343 if (has_alias()) { 1344 log_warnx("alias for %s specified more than once", label()); 1345 return (false); 1346 } 1347 t_alias = alias; 1348 return (true); 1349 } 1350 1351 bool 1352 target::set_auth_group(const char *ag_name) 1353 { 1354 if (t_auth_group != nullptr) { 1355 if (t_private_auth) 1356 log_warnx("cannot use both auth-group and explicit " 1357 "authorisations for %s", label()); 1358 else 1359 log_warnx("auth-group for %s " 1360 "specified more than once", label()); 1361 return (false); 1362 } 1363 t_auth_group = t_conf->find_auth_group(ag_name); 1364 if (t_auth_group == nullptr) { 1365 log_warnx("unknown auth-group \"%s\" for %s", 1366 ag_name, label()); 1367 return (false); 1368 } 1369 return (true); 1370 } 1371 1372 bool 1373 target::set_auth_type(const char *type) 1374 { 1375 if (!use_private_auth("auth-type")) 1376 return (false); 1377 return (t_auth_group->set_type(type)); 1378 } 1379 1380 bool 1381 target::set_physical_port(std::string_view pport) 1382 { 1383 if (!t_pport.empty()) { 1384 log_warnx("cannot set multiple physical ports for target " 1385 "\"%s\"", name()); 1386 return (false); 1387 } 1388 t_pport = pport; 1389 return (true); 1390 } 1391 1392 bool 1393 target::set_redirection(const char *addr) 1394 { 1395 if (!t_redirection.empty()) { 1396 log_warnx("cannot set redirection to \"%s\" for " 1397 "%s; already defined", 1398 addr, label()); 1399 return (false); 1400 } 1401 1402 t_redirection = addr; 1403 return (true); 1404 } 1405 1406 struct lun * 1407 target::start_lun(u_int id, const char *lun_label, const char *lun_name) 1408 { 1409 if (id >= MAX_LUNS) { 1410 log_warnx("%s too big for %s", lun_label, label()); 1411 return (nullptr); 1412 } 1413 1414 if (t_luns[id] != NULL) { 1415 log_warnx("duplicate %s for %s", lun_label, label()); 1416 return (nullptr); 1417 } 1418 1419 struct lun *new_lun = t_conf->add_lun(lun_name); 1420 if (new_lun == nullptr) 1421 return (nullptr); 1422 1423 new_lun->set_scsiname(lun_name); 1424 1425 t_luns[id] = new_lun; 1426 1427 return (new_lun); 1428 } 1429 1430 void 1431 target::add_port(struct port *port) 1432 { 1433 t_ports.push_back(port); 1434 } 1435 1436 void 1437 target::remove_port(struct port *port) 1438 { 1439 t_ports.remove(port); 1440 } 1441 1442 void 1443 target::remove_lun(struct lun *lun) 1444 { 1445 /* XXX: clang is not able to deduce the type without the cast. */ 1446 std::replace(t_luns.begin(), t_luns.end(), lun, 1447 static_cast<struct lun *>(nullptr)); 1448 } 1449 1450 void 1451 target::verify() 1452 { 1453 if (t_auth_group == nullptr) { 1454 t_auth_group = t_conf->find_auth_group("default"); 1455 assert(t_auth_group != nullptr); 1456 } 1457 if (t_ports.empty()) { 1458 struct portal_group *pg = default_portal_group(); 1459 assert(pg != NULL); 1460 t_conf->add_port(this, pg, nullptr); 1461 } 1462 1463 bool found = std::any_of(t_luns.begin(), t_luns.end(), 1464 [](struct lun *lun) { return (lun != nullptr); }); 1465 if (!found && t_redirection.empty()) 1466 log_warnx("no LUNs defined for %s", label()); 1467 if (found && !t_redirection.empty()) 1468 log_debugx("%s contains LUNs, but configured " 1469 "for redirection", label()); 1470 } 1471 1472 lun::lun(struct conf *conf, std::string_view name) 1473 : l_conf(conf), l_options(nvlist_create(0)), l_name(name) 1474 { 1475 } 1476 1477 struct lun * 1478 conf::add_lun(const char *name) 1479 { 1480 const auto &pair = conf_luns.try_emplace(name, 1481 std::make_unique<lun>(this, name)); 1482 if (!pair.second) { 1483 log_warnx("duplicated lun \"%s\"", name); 1484 return (NULL); 1485 } 1486 return (pair.first->second.get()); 1487 } 1488 1489 void 1490 conf::delete_target_luns(struct lun *lun) 1491 { 1492 for (const auto &kv : conf_targets) 1493 kv.second->remove_lun(lun); 1494 for (const auto &kv : conf_controllers) 1495 kv.second->remove_lun(lun); 1496 } 1497 1498 struct lun * 1499 conf::find_lun(std::string_view name) 1500 { 1501 auto it = conf_luns.find(std::string(name)); 1502 if (it == conf_luns.end()) 1503 return (nullptr); 1504 return (it->second.get()); 1505 } 1506 1507 static void 1508 nvlist_replace_string(nvlist_t *nvl, const char *name, const char *value) 1509 { 1510 if (nvlist_exists_string(nvl, name)) 1511 nvlist_free_string(nvl, name); 1512 nvlist_add_string(nvl, name, value); 1513 } 1514 1515 freebsd::nvlist_up 1516 lun::options() const 1517 { 1518 freebsd::nvlist_up nvl(nvlist_clone(l_options.get())); 1519 if (!l_path.empty()) 1520 nvlist_replace_string(nvl.get(), "file", l_path.c_str()); 1521 1522 nvlist_replace_string(nvl.get(), "ctld_name", l_name.c_str()); 1523 1524 if (!nvlist_exists_string(nvl.get(), "scsiname") && 1525 !l_scsiname.empty()) 1526 nvlist_add_string(nvl.get(), "scsiname", l_scsiname.c_str()); 1527 return (nvl); 1528 } 1529 1530 bool 1531 lun::add_option(const char *name, const char *value) 1532 { 1533 return (option_new(l_options.get(), name, value)); 1534 } 1535 1536 bool 1537 lun::set_backend(std::string_view value) 1538 { 1539 if (!l_backend.empty()) { 1540 log_warnx("backend for lun \"%s\" specified more than once", 1541 name()); 1542 return (false); 1543 } 1544 1545 l_backend = value; 1546 return (true); 1547 } 1548 1549 bool 1550 lun::set_blocksize(size_t value) 1551 { 1552 if (l_blocksize != 0) { 1553 log_warnx("blocksize for lun \"%s\" specified more than once", 1554 name()); 1555 return (false); 1556 } 1557 l_blocksize = value; 1558 return (true); 1559 } 1560 1561 bool 1562 lun::set_ctl_lun(uint32_t value) 1563 { 1564 if (l_ctl_lun >= 0) { 1565 log_warnx("ctl_lun for lun \"%s\" specified more than once", 1566 name()); 1567 return (false); 1568 } 1569 1570 l_ctl_lun = value; 1571 return (true); 1572 } 1573 1574 bool 1575 lun::set_device_type(uint8_t device_type) 1576 { 1577 if (device_type > 15) { 1578 log_warnx("invalid device-type \"%u\" for lun \"%s\"", 1579 device_type, name()); 1580 return (false); 1581 } 1582 1583 l_device_type = device_type; 1584 return (true); 1585 } 1586 1587 bool 1588 lun::set_device_type(const char *value) 1589 { 1590 const char *errstr; 1591 int device_type; 1592 1593 if (strcasecmp(value, "disk") == 0 || 1594 strcasecmp(value, "direct") == 0) 1595 device_type = T_DIRECT; 1596 else if (strcasecmp(value, "processor") == 0) 1597 device_type = T_PROCESSOR; 1598 else if (strcasecmp(value, "cd") == 0 || 1599 strcasecmp(value, "cdrom") == 0 || 1600 strcasecmp(value, "dvd") == 0 || 1601 strcasecmp(value, "dvdrom") == 0) 1602 device_type = T_CDROM; 1603 else { 1604 device_type = strtonum(value, 0, 15, &errstr); 1605 if (errstr != NULL) { 1606 log_warnx("invalid device-type \"%s\" for lun \"%s\"", 1607 value, name()); 1608 return (false); 1609 } 1610 } 1611 1612 l_device_type = device_type; 1613 return (true); 1614 } 1615 1616 bool 1617 lun::set_device_id(std::string_view value) 1618 { 1619 if (!l_device_id.empty()) { 1620 log_warnx("device_id for lun \"%s\" specified more than once", 1621 name()); 1622 return (false); 1623 } 1624 1625 l_device_id = value; 1626 return (true); 1627 } 1628 1629 bool 1630 lun::set_path(std::string_view value) 1631 { 1632 if (!l_path.empty()) { 1633 log_warnx("path for lun \"%s\" specified more than once", 1634 name()); 1635 return (false); 1636 } 1637 1638 l_path = value; 1639 return (true); 1640 } 1641 1642 void 1643 lun::set_scsiname(std::string_view value) 1644 { 1645 l_scsiname = value; 1646 } 1647 1648 bool 1649 lun::set_serial(std::string_view value) 1650 { 1651 if (!l_serial.empty()) { 1652 log_warnx("serial for lun \"%s\" specified more than once", 1653 name()); 1654 return (false); 1655 } 1656 1657 l_serial = value; 1658 return (true); 1659 } 1660 1661 bool 1662 lun::set_size(uint64_t value) 1663 { 1664 if (l_size != 0) { 1665 log_warnx("size for lun \"%s\" specified more than once", 1666 name()); 1667 return (false); 1668 } 1669 1670 l_size = value; 1671 return (true); 1672 } 1673 1674 1675 bool 1676 lun::changed(const struct lun &newlun) const 1677 { 1678 if (l_backend != newlun.l_backend) { 1679 log_debugx("backend for lun \"%s\", CTL lun %d changed; " 1680 "removing", name(), l_ctl_lun); 1681 return (true); 1682 } 1683 if (l_blocksize != newlun.l_blocksize) { 1684 log_debugx("blocksize for lun \"%s\", CTL lun %d changed; " 1685 "removing", name(), l_ctl_lun); 1686 return (true); 1687 } 1688 if (l_device_id != newlun.l_device_id) { 1689 log_debugx("device-id for lun \"%s\", CTL lun %d changed; " 1690 "removing", name(), l_ctl_lun); 1691 return (true); 1692 } 1693 if (l_path != newlun.l_path) { 1694 log_debugx("path for lun \"%s\", CTL lun %d, changed; " 1695 "removing", name(), l_ctl_lun); 1696 return (true); 1697 } 1698 if (l_serial != newlun.l_serial) { 1699 log_debugx("serial for lun \"%s\", CTL lun %d changed; " 1700 "removing", name(), l_ctl_lun); 1701 return (true); 1702 } 1703 return (false); 1704 } 1705 1706 bool 1707 option_new(nvlist_t *nvl, const char *name, const char *value) 1708 { 1709 int error; 1710 1711 if (nvlist_exists_string(nvl, name)) { 1712 log_warnx("duplicated option \"%s\"", name); 1713 return (false); 1714 } 1715 1716 nvlist_add_string(nvl, name, value); 1717 error = nvlist_error(nvl); 1718 if (error != 0) { 1719 log_warnc(error, "failed to add option \"%s\"", name); 1720 return (false); 1721 } 1722 return (true); 1723 } 1724 1725 bool 1726 lun::verify() 1727 { 1728 if (l_backend.empty()) 1729 l_backend = "block"; 1730 if (l_backend == "block") { 1731 if (l_path.empty()) { 1732 log_warnx("missing path for lun \"%s\"", 1733 name()); 1734 return (false); 1735 } 1736 } else if (l_backend == "ramdisk") { 1737 if (l_size == 0) { 1738 log_warnx("missing size for ramdisk-backed lun \"%s\"", 1739 name()); 1740 return (false); 1741 } 1742 if (!l_path.empty()) { 1743 log_warnx("path must not be specified " 1744 "for ramdisk-backed lun \"%s\"", 1745 name()); 1746 return (false); 1747 } 1748 } 1749 if (l_blocksize == 0) { 1750 if (l_device_type == T_CDROM) 1751 l_blocksize = DEFAULT_CD_BLOCKSIZE; 1752 else 1753 l_blocksize = DEFAULT_BLOCKSIZE; 1754 } else if (l_blocksize < 0) { 1755 log_warnx("invalid blocksize %d for lun \"%s\"; " 1756 "must be larger than 0", l_blocksize, name()); 1757 return (false); 1758 } 1759 if (l_size != 0 && (l_size % l_blocksize) != 0) { 1760 log_warnx("invalid size for lun \"%s\"; " 1761 "must be multiple of blocksize", name()); 1762 return (false); 1763 } 1764 return (true); 1765 } 1766 1767 bool 1768 conf::verify() 1769 { 1770 if (conf_pidfile_path.empty()) 1771 conf_pidfile_path = DEFAULT_PIDFILE; 1772 1773 std::unordered_map<std::string, struct lun *> path_map; 1774 for (const auto &kv : conf_luns) { 1775 struct lun *lun = kv.second.get(); 1776 if (!lun->verify()) 1777 return (false); 1778 1779 const std::string &path = lun->path(); 1780 if (path.empty()) 1781 continue; 1782 1783 const auto &pair = path_map.try_emplace(path, lun); 1784 if (!pair.second) { 1785 struct lun *lun2 = pair.first->second; 1786 log_debugx("WARNING: path \"%s\" duplicated " 1787 "between lun \"%s\", and " 1788 "lun \"%s\"", path.c_str(), 1789 lun->name(), lun2->name()); 1790 } 1791 } 1792 1793 for (auto &kv : conf_targets) { 1794 kv.second->verify(); 1795 } 1796 for (auto &kv : conf_controllers) { 1797 kv.second->verify(); 1798 } 1799 for (auto &kv : conf_portal_groups) { 1800 kv.second->verify(this); 1801 } 1802 for (auto &kv : conf_transport_groups) { 1803 kv.second->verify(this); 1804 } 1805 for (const auto &kv : conf_auth_groups) { 1806 const std::string &ag_name = kv.first; 1807 if (ag_name == "default" || 1808 ag_name == "no-authentication" || 1809 ag_name == "no-access") 1810 continue; 1811 1812 if (kv.second.use_count() == 1) { 1813 log_warnx("auth-group \"%s\" not assigned " 1814 "to any target", ag_name.c_str()); 1815 } 1816 } 1817 1818 return (true); 1819 } 1820 1821 bool 1822 portal::reuse_socket(struct portal &oldp) 1823 { 1824 struct kevent kev; 1825 1826 if (p_listen != oldp.p_listen) 1827 return (false); 1828 1829 if (!oldp.p_socket) 1830 return (false); 1831 1832 EV_SET(&kev, oldp.p_socket, EVFILT_READ, EV_ADD, 0, 0, this); 1833 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == -1) 1834 return (false); 1835 1836 p_socket = std::move(oldp.p_socket); 1837 return (true); 1838 } 1839 1840 bool 1841 portal::init_socket() 1842 { 1843 struct portal_group *pg = portal_group(); 1844 struct kevent kev; 1845 freebsd::fd_up s; 1846 int error; 1847 int one = 1; 1848 1849 #ifdef ICL_KERNEL_PROXY 1850 if (proxy_mode) { 1851 int id = pg->conf()->add_proxy_portal(this); 1852 log_debugx("listening on %s, %s \"%s\", " 1853 "portal id %d, using ICL proxy", listen(), pg->keyword(), 1854 pg->name(), id); 1855 kernel_listen(ai(), protocol() == ISER, id); 1856 return (true); 1857 } 1858 #endif 1859 assert(proxy_mode == false); 1860 assert(protocol() != portal_protocol::ISER); 1861 1862 log_debugx("listening on %s, %s \"%s\"", listen(), pg->keyword(), 1863 pg->name()); 1864 s = ::socket(p_ai->ai_family, p_ai->ai_socktype, p_ai->ai_protocol); 1865 if (!s) { 1866 log_warn("socket(2) failed for %s", listen()); 1867 return (false); 1868 } 1869 1870 if (setsockopt(s, SOL_SOCKET, SO_NO_DDP, &one, 1871 sizeof(one)) == -1) 1872 log_warn("setsockopt(SO_NO_DDP) failed for %s", listen()); 1873 error = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, 1874 sizeof(one)); 1875 if (error != 0) { 1876 log_warn("setsockopt(SO_REUSEADDR) failed for %s", listen()); 1877 return (false); 1878 } 1879 1880 if (pg->dscp() != -1) { 1881 /* Only allow the 6-bit DSCP field to be modified */ 1882 int tos = pg->dscp() << 2; 1883 switch (p_ai->ai_family) { 1884 case AF_INET: 1885 if (setsockopt(s, IPPROTO_IP, IP_TOS, 1886 &tos, sizeof(tos)) == -1) 1887 log_warn("setsockopt(IP_TOS) failed for %s", 1888 listen()); 1889 break; 1890 case AF_INET6: 1891 if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, 1892 &tos, sizeof(tos)) == -1) 1893 log_warn("setsockopt(IPV6_TCLASS) failed for %s", 1894 listen()); 1895 break; 1896 } 1897 } 1898 if (pg->pcp() != -1) { 1899 int pcp = pg->pcp(); 1900 switch (p_ai->ai_family) { 1901 case AF_INET: 1902 if (setsockopt(s, IPPROTO_IP, IP_VLAN_PCP, 1903 &pcp, sizeof(pcp)) == -1) 1904 log_warn("setsockopt(IP_VLAN_PCP) failed for %s", 1905 listen()); 1906 break; 1907 case AF_INET6: 1908 if (setsockopt(s, IPPROTO_IPV6, IPV6_VLAN_PCP, 1909 &pcp, sizeof(pcp)) == -1) 1910 log_warn("setsockopt(IPV6_VLAN_PCP) failed for %s", 1911 listen()); 1912 break; 1913 } 1914 } 1915 1916 if (!init_socket_options(s)) 1917 return (false); 1918 1919 error = bind(s, p_ai->ai_addr, p_ai->ai_addrlen); 1920 if (error != 0) { 1921 log_warn("bind(2) failed for %s", listen()); 1922 return (false); 1923 } 1924 error = ::listen(s, -1); 1925 if (error != 0) { 1926 log_warn("listen(2) failed for %s", listen()); 1927 return (false); 1928 } 1929 EV_SET(&kev, s, EVFILT_READ, EV_ADD, 0, 0, this); 1930 error = kevent(kqfd, &kev, 1, NULL, 0, NULL); 1931 if (error == -1) { 1932 log_warn("kevent(2) failed to register for %s", listen()); 1933 return (false); 1934 } 1935 p_socket = std::move(s); 1936 return (true); 1937 } 1938 1939 bool 1940 conf::reuse_portal_group_socket(struct portal &newp) 1941 { 1942 for (auto &kv : conf_portal_groups) { 1943 struct portal_group &pg = *kv.second; 1944 1945 if (pg.reuse_socket(newp)) 1946 return (true); 1947 } 1948 for (auto &kv : conf_transport_groups) { 1949 struct portal_group &pg = *kv.second; 1950 1951 if (pg.reuse_socket(newp)) 1952 return (true); 1953 } 1954 return (false); 1955 } 1956 1957 int 1958 conf::apply(struct conf *oldconf) 1959 { 1960 int cumulated_error = 0; 1961 1962 if (oldconf->conf_debug != conf_debug) { 1963 log_debugx("changing debug level to %d", conf_debug); 1964 log_init(conf_debug); 1965 } 1966 1967 /* 1968 * On startup, oldconf created via conf_new_from_kernel will 1969 * not contain a valid pidfile_path, and the current 1970 * conf_pidfile will already own the pidfile. On shutdown, 1971 * the temporary newconf will not contain a valid 1972 * pidfile_path, and the pidfile will be cleaned up when the 1973 * oldconf is deleted. 1974 */ 1975 if (!oldconf->conf_pidfile_path.empty() && 1976 !conf_pidfile_path.empty()) { 1977 if (oldconf->conf_pidfile_path != conf_pidfile_path) { 1978 /* pidfile has changed. rename it */ 1979 log_debugx("moving pidfile to %s", 1980 conf_pidfile_path.c_str()); 1981 if (rename(oldconf->conf_pidfile_path.c_str(), 1982 conf_pidfile_path.c_str()) != 0) { 1983 log_err(1, "renaming pidfile %s -> %s", 1984 oldconf->conf_pidfile_path.c_str(), 1985 conf_pidfile_path.c_str()); 1986 } 1987 } 1988 conf_pidfile = std::move(oldconf->conf_pidfile); 1989 } 1990 1991 /* 1992 * Go through the new portal groups, assigning tags or preserving old. 1993 */ 1994 for (auto &kv : conf_portal_groups) { 1995 struct portal_group &newpg = *kv.second; 1996 1997 if (newpg.tag() != 0) 1998 continue; 1999 auto it = oldconf->conf_portal_groups.find(kv.first); 2000 if (it != oldconf->conf_portal_groups.end()) 2001 newpg.set_tag(it->second->tag()); 2002 else 2003 newpg.allocate_tag(); 2004 } 2005 for (auto &kv : conf_transport_groups) { 2006 struct portal_group &newpg = *kv.second; 2007 2008 if (newpg.tag() != 0) 2009 continue; 2010 auto it = oldconf->conf_transport_groups.find(kv.first); 2011 if (it != oldconf->conf_transport_groups.end()) 2012 newpg.set_tag(it->second->tag()); 2013 else 2014 newpg.allocate_tag(); 2015 } 2016 2017 /* Deregister on removed iSNS servers. */ 2018 for (auto &kv : oldconf->conf_isns) { 2019 if (conf_isns.count(kv.first) == 0) 2020 oldconf->isns_deregister_targets(&kv.second); 2021 } 2022 2023 /* 2024 * XXX: If target or lun removal fails, we should somehow "move" 2025 * the old lun or target into this, so that subsequent 2026 * conf::apply() would try to remove them again. That would 2027 * be somewhat hairy, though, and lun deletion failures don't 2028 * really happen, so leave it as it is for now. 2029 */ 2030 /* 2031 * First, remove any ports present in the old configuration 2032 * and missing in the new one. 2033 */ 2034 for (const auto &kv : oldconf->conf_ports) { 2035 const std::string &name = kv.first; 2036 port *oldport = kv.second.get(); 2037 2038 if (oldport->is_dummy()) 2039 continue; 2040 const auto it = conf_ports.find(name); 2041 if (it != conf_ports.end() && !it->second->is_dummy()) 2042 continue; 2043 log_debugx("removing port \"%s\"", name.c_str()); 2044 if (!oldport->kernel_remove()) { 2045 log_warnx("failed to remove port %s", name.c_str()); 2046 /* 2047 * XXX: Uncomment after fixing the root cause. 2048 * 2049 * cumulated_error++; 2050 */ 2051 } 2052 } 2053 2054 /* 2055 * Second, remove any LUNs present in the old configuration 2056 * and missing in the new one. 2057 */ 2058 for (auto it = oldconf->conf_luns.begin(); 2059 it != oldconf->conf_luns.end(); ) { 2060 struct lun *oldlun = it->second.get(); 2061 2062 auto newit = conf_luns.find(it->first); 2063 if (newit == conf_luns.end()) { 2064 log_debugx("lun \"%s\", CTL lun %d " 2065 "not found in new configuration; " 2066 "removing", oldlun->name(), oldlun->ctl_lun()); 2067 if (!oldlun->kernel_remove()) { 2068 log_warnx("failed to remove lun \"%s\", " 2069 "CTL lun %d", 2070 oldlun->name(), oldlun->ctl_lun()); 2071 cumulated_error++; 2072 } 2073 it++; 2074 continue; 2075 } 2076 2077 /* 2078 * Also remove the LUNs changed by more than size. 2079 */ 2080 struct lun *newlun = newit->second.get(); 2081 if (oldlun->changed(*newlun)) { 2082 if (!oldlun->kernel_remove()) { 2083 log_warnx("failed to remove lun \"%s\", " 2084 "CTL lun %d", 2085 oldlun->name(), oldlun->ctl_lun()); 2086 cumulated_error++; 2087 } 2088 2089 /* 2090 * Delete the lun from the old configuration 2091 * so it is added as a new LUN below. 2092 */ 2093 it = oldconf->conf_luns.erase(it); 2094 continue; 2095 } 2096 2097 newlun->set_ctl_lun(oldlun->ctl_lun()); 2098 it++; 2099 } 2100 2101 for (auto it = conf_luns.begin(); it != conf_luns.end(); ) { 2102 struct lun *newlun = it->second.get(); 2103 2104 auto oldit = oldconf->conf_luns.find(it->first); 2105 if (oldit != oldconf->conf_luns.end()) { 2106 log_debugx("modifying lun \"%s\", CTL lun %d", 2107 newlun->name(), newlun->ctl_lun()); 2108 if (!newlun->kernel_modify()) { 2109 log_warnx("failed to " 2110 "modify lun \"%s\", CTL lun %d", 2111 newlun->name(), newlun->ctl_lun()); 2112 cumulated_error++; 2113 } 2114 it++; 2115 continue; 2116 } 2117 2118 log_debugx("adding lun \"%s\"", newlun->name()); 2119 if (!newlun->kernel_add()) { 2120 log_warnx("failed to add lun \"%s\"", newlun->name()); 2121 delete_target_luns(newlun); 2122 it = conf_luns.erase(it); 2123 cumulated_error++; 2124 } else 2125 it++; 2126 } 2127 2128 /* 2129 * Now add new ports or modify existing ones. 2130 */ 2131 for (auto it = conf_ports.begin(); it != conf_ports.end(); ) { 2132 const std::string &name = it->first; 2133 port *newport = it->second.get(); 2134 2135 if (newport->is_dummy()) { 2136 it++; 2137 continue; 2138 } 2139 const auto oldit = oldconf->conf_ports.find(name); 2140 if (oldit == oldconf->conf_ports.end() || 2141 oldit->second->is_dummy()) { 2142 log_debugx("adding port \"%s\"", name.c_str()); 2143 if (!newport->kernel_add()) { 2144 log_warnx("failed to add port %s", 2145 name.c_str()); 2146 2147 /* 2148 * XXX: Uncomment after fixing the 2149 * root cause. 2150 * 2151 * cumulated_error++; 2152 */ 2153 2154 /* 2155 * conf "owns" the port, but other 2156 * objects contain pointers to this 2157 * port that must be removed before 2158 * deleting the port. 2159 */ 2160 newport->clear_references(); 2161 it = conf_ports.erase(it); 2162 } else 2163 it++; 2164 } else { 2165 log_debugx("updating port \"%s\"", name.c_str()); 2166 if (!newport->kernel_update(oldit->second.get())) 2167 log_warnx("failed to update port %s", 2168 name.c_str()); 2169 it++; 2170 } 2171 } 2172 2173 /* 2174 * Go through the new portals, opening the sockets as necessary. 2175 */ 2176 for (auto &kv : conf_portal_groups) { 2177 cumulated_error += kv.second->open_sockets(*oldconf); 2178 } 2179 for (auto &kv : conf_transport_groups) { 2180 cumulated_error += kv.second->open_sockets(*oldconf); 2181 } 2182 2183 /* 2184 * Go through the no longer used sockets, closing them. 2185 */ 2186 for (auto &kv : oldconf->conf_portal_groups) { 2187 kv.second->close_sockets(); 2188 } 2189 for (auto &kv : oldconf->conf_transport_groups) { 2190 kv.second->close_sockets(); 2191 } 2192 2193 /* (Re-)Register on remaining/new iSNS servers. */ 2194 for (auto &kv : conf_isns) { 2195 auto it = oldconf->conf_isns.find(kv.first); 2196 if (it == oldconf->conf_isns.end()) 2197 isns_register_targets(&kv.second, nullptr); 2198 else 2199 isns_register_targets(&kv.second, oldconf); 2200 } 2201 2202 isns_schedule_update(); 2203 2204 return (cumulated_error); 2205 } 2206 2207 bool 2208 timed_out(void) 2209 { 2210 2211 return (sigalrm_received); 2212 } 2213 2214 static void 2215 sigalrm_handler_fatal(int dummy __unused) 2216 { 2217 /* 2218 * It would be easiest to just log an error and exit. We can't 2219 * do this, though, because log_errx() is not signal safe, since 2220 * it calls syslog(3). Instead, set a flag checked by pdu_send() 2221 * and pdu_receive(), to call log_errx() there. Should they fail 2222 * to notice, we'll exit here one second later. 2223 */ 2224 if (sigalrm_received) { 2225 /* 2226 * Oh well. Just give up and quit. 2227 */ 2228 _exit(2); 2229 } 2230 2231 sigalrm_received = true; 2232 } 2233 2234 static void 2235 sigalrm_handler(int dummy __unused) 2236 { 2237 2238 sigalrm_received = true; 2239 } 2240 2241 void 2242 stop_timer() 2243 { 2244 struct itimerval itv; 2245 int error; 2246 2247 log_debugx("session timeout disabled"); 2248 bzero(&itv, sizeof(itv)); 2249 error = setitimer(ITIMER_REAL, &itv, NULL); 2250 if (error != 0) 2251 log_err(1, "setitimer"); 2252 sigalrm_received = false; 2253 } 2254 2255 void 2256 start_timer(int timeout, bool fatal) 2257 { 2258 struct sigaction sa; 2259 struct itimerval itv; 2260 int error; 2261 2262 if (timeout <= 0) { 2263 stop_timer(); 2264 return; 2265 } 2266 2267 sigalrm_received = false; 2268 bzero(&sa, sizeof(sa)); 2269 if (fatal) 2270 sa.sa_handler = sigalrm_handler_fatal; 2271 else 2272 sa.sa_handler = sigalrm_handler; 2273 sigfillset(&sa.sa_mask); 2274 error = sigaction(SIGALRM, &sa, NULL); 2275 if (error != 0) 2276 log_err(1, "sigaction"); 2277 2278 /* 2279 * First SIGALRM will arive after timeout seconds. 2280 * If we do nothing, another one will arrive a second later. 2281 */ 2282 log_debugx("setting session timeout to %d seconds", timeout); 2283 bzero(&itv, sizeof(itv)); 2284 itv.it_interval.tv_sec = 1; 2285 itv.it_value.tv_sec = timeout; 2286 error = setitimer(ITIMER_REAL, &itv, NULL); 2287 if (error != 0) 2288 log_err(1, "setitimer"); 2289 } 2290 2291 static int 2292 wait_for_children(bool block) 2293 { 2294 pid_t pid; 2295 int status; 2296 int num = 0; 2297 2298 for (;;) { 2299 /* 2300 * If "block" is true, wait for at least one process. 2301 */ 2302 if (block && num == 0) 2303 pid = wait4(-1, &status, 0, NULL); 2304 else 2305 pid = wait4(-1, &status, WNOHANG, NULL); 2306 if (pid <= 0) 2307 break; 2308 if (WIFSIGNALED(status)) { 2309 log_warnx("child process %d terminated with signal %d", 2310 pid, WTERMSIG(status)); 2311 } else if (WEXITSTATUS(status) != 0) { 2312 log_warnx("child process %d terminated with exit status %d", 2313 pid, WEXITSTATUS(status)); 2314 } else { 2315 log_debugx("child process %d terminated gracefully", pid); 2316 } 2317 num++; 2318 } 2319 2320 return (num); 2321 } 2322 2323 static void 2324 handle_connection(struct portal *portal, freebsd::fd_up fd, 2325 const struct sockaddr *client_sa, bool dont_fork) 2326 { 2327 struct portal_group *pg; 2328 int error; 2329 pid_t pid; 2330 char host[NI_MAXHOST + 1]; 2331 struct conf *conf; 2332 2333 pg = portal->portal_group(); 2334 conf = pg->conf(); 2335 2336 if (dont_fork) { 2337 log_debugx("incoming connection; not forking due to -d flag"); 2338 } else { 2339 nchildren -= wait_for_children(false); 2340 assert(nchildren >= 0); 2341 2342 while (conf->maxproc() > 0 && nchildren >= conf->maxproc()) { 2343 log_debugx("maxproc limit of %d child processes hit; " 2344 "waiting for child process to exit", 2345 conf->maxproc()); 2346 nchildren -= wait_for_children(true); 2347 assert(nchildren >= 0); 2348 } 2349 log_debugx("incoming connection; forking child process #%d", 2350 nchildren); 2351 nchildren++; 2352 pid = fork(); 2353 if (pid < 0) 2354 log_err(1, "fork"); 2355 if (pid > 0) 2356 return; 2357 conf->close_pidfile(); 2358 } 2359 2360 error = getnameinfo(client_sa, client_sa->sa_len, 2361 host, sizeof(host), NULL, 0, NI_NUMERICHOST); 2362 if (error != 0) 2363 log_errx(1, "getnameinfo: %s", gai_strerror(error)); 2364 2365 log_debugx("accepted connection from %s; portal group \"%s\"", 2366 host, pg->name()); 2367 log_set_peer_addr(host); 2368 setproctitle("%s", host); 2369 2370 portal->handle_connection(std::move(fd), host, client_sa); 2371 log_debugx("nothing more to do; exiting"); 2372 exit(0); 2373 } 2374 2375 static void 2376 main_loop(bool dont_fork) 2377 { 2378 struct kevent kev; 2379 struct portal *portal; 2380 struct sockaddr_storage client_sa; 2381 socklen_t client_salen; 2382 #ifdef ICL_KERNEL_PROXY 2383 int connection_id; 2384 int portal_id; 2385 #endif 2386 int error, client_fd; 2387 2388 for (;;) { 2389 if (sighup_received || sigterm_received || timed_out()) 2390 return; 2391 2392 #ifdef ICL_KERNEL_PROXY 2393 if (proxy_mode) { 2394 client_salen = sizeof(client_sa); 2395 kernel_accept(&connection_id, &portal_id, 2396 (struct sockaddr *)&client_sa, &client_salen); 2397 assert(client_salen >= client_sa.ss_len); 2398 2399 log_debugx("incoming connection, id %d, portal id %d", 2400 connection_id, portal_id); 2401 portal = conf->proxy_portal(portal_id); 2402 if (portal == nullptr) 2403 log_errx(1, 2404 "kernel returned invalid portal_id %d", 2405 portal_id); 2406 2407 handle_connection(portal, connection_id, 2408 (struct sockaddr *)&client_sa, dont_fork); 2409 } else { 2410 #endif 2411 assert(proxy_mode == false); 2412 2413 error = kevent(kqfd, NULL, 0, &kev, 1, NULL); 2414 if (error == -1) { 2415 if (errno == EINTR) 2416 continue; 2417 log_err(1, "kevent"); 2418 } 2419 2420 switch (kev.filter) { 2421 case EVFILT_READ: 2422 portal = reinterpret_cast<struct portal *>(kev.udata); 2423 assert(portal->socket() == (int)kev.ident); 2424 2425 client_salen = sizeof(client_sa); 2426 client_fd = accept(portal->socket(), 2427 (struct sockaddr *)&client_sa, 2428 &client_salen); 2429 if (client_fd < 0) { 2430 if (errno == ECONNABORTED) 2431 continue; 2432 log_err(1, "accept"); 2433 } 2434 assert(client_salen >= client_sa.ss_len); 2435 2436 handle_connection(portal, client_fd, 2437 (struct sockaddr *)&client_sa, dont_fork); 2438 break; 2439 default: 2440 __assert_unreachable(); 2441 } 2442 #ifdef ICL_KERNEL_PROXY 2443 } 2444 #endif 2445 } 2446 } 2447 2448 static void 2449 sighup_handler(int dummy __unused) 2450 { 2451 2452 sighup_received = true; 2453 } 2454 2455 static void 2456 sigterm_handler(int dummy __unused) 2457 { 2458 2459 sigterm_received = true; 2460 } 2461 2462 static void 2463 sigchld_handler(int dummy __unused) 2464 { 2465 2466 /* 2467 * The only purpose of this handler is to make SIGCHLD 2468 * interrupt the ISCSIDWAIT ioctl(2), so we can call 2469 * wait_for_children(). 2470 */ 2471 } 2472 2473 static void 2474 register_signals(void) 2475 { 2476 struct sigaction sa; 2477 int error; 2478 2479 bzero(&sa, sizeof(sa)); 2480 sa.sa_handler = sighup_handler; 2481 sigfillset(&sa.sa_mask); 2482 error = sigaction(SIGHUP, &sa, NULL); 2483 if (error != 0) 2484 log_err(1, "sigaction"); 2485 2486 sa.sa_handler = sigterm_handler; 2487 error = sigaction(SIGTERM, &sa, NULL); 2488 if (error != 0) 2489 log_err(1, "sigaction"); 2490 2491 sa.sa_handler = sigterm_handler; 2492 error = sigaction(SIGINT, &sa, NULL); 2493 if (error != 0) 2494 log_err(1, "sigaction"); 2495 2496 sa.sa_handler = sigchld_handler; 2497 error = sigaction(SIGCHLD, &sa, NULL); 2498 if (error != 0) 2499 log_err(1, "sigaction"); 2500 } 2501 2502 static void 2503 check_perms(const char *path) 2504 { 2505 struct stat sb; 2506 int error; 2507 2508 error = stat(path, &sb); 2509 if (error != 0) { 2510 log_warn("stat"); 2511 return; 2512 } 2513 if (sb.st_mode & S_IWOTH) { 2514 log_warnx("%s is world-writable", path); 2515 } else if (sb.st_mode & S_IROTH) { 2516 log_warnx("%s is world-readable", path); 2517 } else if (sb.st_mode & S_IXOTH) { 2518 /* 2519 * Ok, this one doesn't matter, but still do it, 2520 * just for consistency. 2521 */ 2522 log_warnx("%s is world-executable", path); 2523 } 2524 2525 /* 2526 * XXX: Should we also check for owner != 0? 2527 */ 2528 } 2529 2530 static conf_up 2531 conf_new_from_file(const char *path, bool ucl) 2532 { 2533 struct auth_group *ag; 2534 struct portal_group *pg; 2535 bool valid; 2536 2537 log_debugx("obtaining configuration from %s", path); 2538 2539 conf_up conf = std::make_unique<struct conf>(); 2540 2541 ag = conf->add_auth_group("default"); 2542 assert(ag != NULL); 2543 2544 ag = conf->add_auth_group("no-authentication"); 2545 assert(ag != NULL); 2546 ag->set_type(auth_type::NO_AUTHENTICATION); 2547 2548 ag = conf->add_auth_group("no-access"); 2549 assert(ag != NULL); 2550 ag->set_type(auth_type::DENY); 2551 2552 pg = conf->add_portal_group("default"); 2553 assert(pg != NULL); 2554 2555 pg = conf->add_transport_group("default"); 2556 assert(pg != NULL); 2557 2558 conf_start(conf.get()); 2559 if (ucl) 2560 valid = uclparse_conf(path); 2561 else 2562 valid = parse_conf(path); 2563 conf_finish(); 2564 2565 if (!valid) { 2566 conf.reset(); 2567 return {}; 2568 } 2569 2570 check_perms(path); 2571 2572 if (!conf->default_auth_group_defined()) { 2573 log_debugx("auth-group \"default\" not defined; " 2574 "going with defaults"); 2575 ag = conf->find_auth_group("default").get(); 2576 assert(ag != NULL); 2577 ag->set_type(auth_type::DENY); 2578 } 2579 2580 if (!conf->default_portal_group_defined()) { 2581 log_debugx("portal-group \"default\" not defined; " 2582 "going with defaults"); 2583 pg = conf->find_portal_group("default"); 2584 assert(pg != NULL); 2585 pg->add_default_portals(); 2586 } 2587 2588 if (!conf->default_portal_group_defined()) { 2589 log_debugx("transport-group \"default\" not defined; " 2590 "going with defaults"); 2591 pg = conf->find_transport_group("default"); 2592 assert(pg != NULL); 2593 pg->add_default_portals(); 2594 } 2595 2596 if (!conf->verify()) { 2597 conf.reset(); 2598 return {}; 2599 } 2600 2601 return (conf); 2602 } 2603 2604 /* 2605 * If the config file specifies physical ports for any target, associate them 2606 * with the config file. If necessary, create them. 2607 */ 2608 bool 2609 conf::add_pports(struct kports &kports) 2610 { 2611 struct pport *pp; 2612 int ret, i_pp, i_vp; 2613 2614 for (auto &kv : conf_targets) { 2615 struct target *targ = kv.second.get(); 2616 2617 if (!targ->has_pport()) 2618 continue; 2619 2620 ret = sscanf(targ->pport(), "ioctl/%d/%d", &i_pp, &i_vp); 2621 if (ret > 0) { 2622 if (!add_port(kports, targ, i_pp, i_vp)) { 2623 log_warnx("can't create new ioctl port " 2624 "for %s", targ->label()); 2625 return (false); 2626 } 2627 2628 continue; 2629 } 2630 2631 pp = kports.find_port(targ->pport()); 2632 if (pp == NULL) { 2633 log_warnx("unknown port \"%s\" for %s", 2634 targ->pport(), targ->label()); 2635 return (false); 2636 } 2637 if (pp->linked()) { 2638 log_warnx("can't link port \"%s\" to %s, " 2639 "port already linked to some target", 2640 targ->pport(), targ->label()); 2641 return (false); 2642 } 2643 if (!add_port(targ, pp)) { 2644 log_warnx("can't link port \"%s\" to %s", 2645 targ->pport(), targ->label()); 2646 return (false); 2647 } 2648 } 2649 return (true); 2650 } 2651 2652 int 2653 main(int argc, char **argv) 2654 { 2655 struct kports kports; 2656 const char *config_path = DEFAULT_CONFIG_PATH; 2657 int debug = 0, ch, error; 2658 bool daemonize = true; 2659 bool test_config = false; 2660 bool use_ucl = false; 2661 2662 while ((ch = getopt(argc, argv, "dtuf:R")) != -1) { 2663 switch (ch) { 2664 case 'd': 2665 daemonize = false; 2666 debug++; 2667 break; 2668 case 't': 2669 test_config = true; 2670 break; 2671 case 'u': 2672 use_ucl = true; 2673 break; 2674 case 'f': 2675 config_path = optarg; 2676 break; 2677 case 'R': 2678 #ifndef ICL_KERNEL_PROXY 2679 log_errx(1, "ctld(8) compiled without ICL_KERNEL_PROXY " 2680 "does not support iSER protocol"); 2681 #endif 2682 proxy_mode = true; 2683 break; 2684 case '?': 2685 default: 2686 usage(); 2687 } 2688 } 2689 argc -= optind; 2690 if (argc != 0) 2691 usage(); 2692 2693 log_init(debug); 2694 kernel_init(); 2695 2696 conf_up newconf = conf_new_from_file(config_path, use_ucl); 2697 2698 if (newconf == NULL) 2699 log_errx(1, "configuration error; exiting"); 2700 2701 if (test_config) 2702 return (0); 2703 2704 newconf->open_pidfile(); 2705 2706 register_signals(); 2707 2708 conf_up oldconf = conf_new_from_kernel(kports); 2709 2710 if (debug > 0) { 2711 oldconf->set_debug(debug); 2712 newconf->set_debug(debug); 2713 } 2714 2715 if (!newconf->add_pports(kports)) 2716 log_errx(1, "Error associating physical ports; exiting"); 2717 2718 if (daemonize) { 2719 log_debugx("daemonizing"); 2720 if (daemon(0, 0) == -1) { 2721 log_warn("cannot daemonize"); 2722 return (1); 2723 } 2724 } 2725 2726 kqfd = kqueue(); 2727 if (kqfd == -1) { 2728 log_warn("Cannot create kqueue"); 2729 return (1); 2730 } 2731 2732 error = newconf->apply(oldconf.get()); 2733 if (error != 0) 2734 log_errx(1, "failed to apply configuration; exiting"); 2735 2736 oldconf.reset(); 2737 2738 newconf->write_pidfile(); 2739 2740 newconf->isns_schedule_update(); 2741 2742 for (;;) { 2743 main_loop(!daemonize); 2744 if (sighup_received) { 2745 sighup_received = false; 2746 log_debugx("received SIGHUP, reloading configuration"); 2747 conf_up tmpconf = conf_new_from_file(config_path, 2748 use_ucl); 2749 2750 if (tmpconf == NULL) { 2751 log_warnx("configuration error, " 2752 "continuing with old configuration"); 2753 } else if (!tmpconf->add_pports(kports)) { 2754 log_warnx("Error associating physical ports, " 2755 "continuing with old configuration"); 2756 } else { 2757 if (debug > 0) 2758 tmpconf->set_debug(debug); 2759 oldconf = std::move(newconf); 2760 newconf = std::move(tmpconf); 2761 2762 error = newconf->apply(oldconf.get()); 2763 if (error != 0) 2764 log_warnx("failed to reload " 2765 "configuration"); 2766 oldconf.reset(); 2767 } 2768 } else if (sigterm_received) { 2769 log_debugx("exiting on signal; " 2770 "reloading empty configuration"); 2771 2772 log_debugx("removing CTL iSCSI ports " 2773 "and terminating all connections"); 2774 2775 oldconf = std::move(newconf); 2776 newconf = std::make_unique<conf>(); 2777 if (debug > 0) 2778 newconf->set_debug(debug); 2779 error = newconf->apply(oldconf.get()); 2780 if (error != 0) 2781 log_warnx("failed to apply configuration"); 2782 oldconf.reset(); 2783 2784 log_warnx("exiting on signal"); 2785 return (0); 2786 } else { 2787 nchildren -= wait_for_children(false); 2788 assert(nchildren >= 0); 2789 if (timed_out()) { 2790 newconf->isns_update(); 2791 } 2792 } 2793 } 2794 /* NOTREACHED */ 2795 } 2796