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