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