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