xref: /freebsd/usr.sbin/ctld/ctld.cc (revision 1435a9b293e21f8fca1f654420c5075ea7434e8f)
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 		if (!portal->prepare()) {
818 			cumulated_error++;
819 			continue;
820 		}
821 
822 		/*
823 		 * Try to find already open portal and reuse the
824 		 * listening socket.  We don't care about what portal
825 		 * or portal group that was, what matters is the
826 		 * listening address.
827 		 */
828 		if (oldconf.reuse_portal_group_socket(*portal))
829 			continue;
830 
831 		if (!portal->init_socket()) {
832 			cumulated_error++;
833 			continue;
834 		}
835 	}
836 	return (cumulated_error);
837 }
838 
839 void
close_sockets()840 portal_group::close_sockets()
841 {
842 	for (portal_up &portal : pg_portals) {
843 		if (portal->socket() < 0)
844 			continue;
845 		log_debugx("closing socket for %s, %s \"%s\"",
846 		    portal->listen(), keyword(), name());
847 		portal->close();
848 	}
849 }
850 
851 bool
add_isns(const char * addr)852 conf::add_isns(const char *addr)
853 {
854 	if (conf_isns.count(addr) > 0) {
855 		log_warnx("duplicate iSNS address %s", addr);
856 		return (false);
857 	}
858 
859 	freebsd::addrinfo_up ai = parse_addr_port(addr, "3205");
860 	if (!ai) {
861 		log_warnx("invalid iSNS address %s", addr);
862 		return (false);
863 	}
864 
865 	/*
866 	 * XXX: getaddrinfo(3) may return multiple addresses; we should turn
867 	 *	those into multiple servers.
868 	 */
869 
870 	conf_isns.emplace(addr, isns(addr, std::move(ai)));
871 	return (true);
872 }
873 
874 
875 freebsd::fd_up
connect()876 isns::connect()
877 {
878 	freebsd::fd_up s;
879 
880 	s = socket(i_ai->ai_family, i_ai->ai_socktype, i_ai->ai_protocol);
881 	if (!s) {
882 		log_warn("socket(2) failed for %s", addr());
883 		return (s);
884 	}
885 	if (::connect(s, i_ai->ai_addr, i_ai->ai_addrlen)) {
886 		log_warn("connect(2) failed for %s", addr());
887 		s.reset();
888 	}
889 	return (s);
890 }
891 
892 bool
send_request(int s,struct isns_req req)893 isns::send_request(int s, struct isns_req req)
894 {
895 	if (!req.send(s)) {
896 		log_warn("send(2) failed for %s", addr());
897 		return (false);
898 	}
899 	if (!req.receive(s)) {
900 		log_warn("receive(2) failed for %s", addr());
901 		return (false);
902 	}
903 	uint32_t error = req.get_status();
904 	if (error != 0) {
905 		log_warnx("iSNS %s error %u for %s", req.descr(), error,
906 		    addr());
907 		return (false);
908 	}
909 	return (true);
910 }
911 
912 struct isns_req
isns_register_request(const char * hostname)913 conf::isns_register_request(const char *hostname)
914 {
915 	const struct portal_group *pg;
916 
917 	isns_req req(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT, "register");
918 	req.add_str(32, conf_first_target->name());
919 	req.add_delim();
920 	req.add_str(1, hostname);
921 	req.add_32(2, 2); /* 2 -- iSCSI */
922 	req.add_32(6, conf_isns_period);
923 	for (const auto &kv : conf_portal_groups) {
924 		pg = kv.second.get();
925 
926 		if (!pg->assigned())
927 			continue;
928 		for (const portal_up &portal : pg->portals()) {
929 			req.add_addr(16, portal->ai());
930 			req.add_port(17, portal->ai());
931 		}
932 	}
933 	for (const auto &kv : conf_targets) {
934 		const struct target *target = kv.second.get();
935 
936 		req.add_str(32, target->name());
937 		req.add_32(33, 1); /* 1 -- Target*/
938 		if (target->has_alias())
939 			req.add_str(34, target->alias());
940 		for (const port *port : target->ports()) {
941 			pg = port->portal_group();
942 			if (pg == nullptr)
943 				continue;
944 			req.add_32(51, pg->tag());
945 			for (const portal_up &portal : pg->portals()) {
946 				req.add_addr(49, portal->ai());
947 				req.add_port(50, portal->ai());
948 			}
949 		}
950 	}
951 	return (req);
952 }
953 
954 struct isns_req
isns_check_request(const char * hostname)955 conf::isns_check_request(const char *hostname)
956 {
957 	isns_req req(ISNS_FUNC_DEVATTRQRY, ISNS_FLAG_CLIENT, "check");
958 	req.add_str(32, conf_first_target->name());
959 	req.add_str(1, hostname);
960 	req.add_delim();
961 	req.add(2, 0, NULL);
962 	return (req);
963 }
964 
965 struct isns_req
isns_deregister_request(const char * hostname)966 conf::isns_deregister_request(const char *hostname)
967 {
968 	isns_req req(ISNS_FUNC_DEVDEREG, ISNS_FLAG_CLIENT, "deregister");
969 	req.add_str(32, conf_first_target->name());
970 	req.add_delim();
971 	req.add_str(1, hostname);
972 	return (req);
973 }
974 
975 void
isns_register_targets(struct isns * isns,struct conf * oldconf)976 conf::isns_register_targets(struct isns *isns, struct conf *oldconf)
977 {
978 	int error;
979 	char hostname[256];
980 
981 	if (conf_targets.empty() || conf_portal_groups.empty())
982 		return;
983 	start_timer(conf_isns_timeout);
984 	freebsd::fd_up s = isns->connect();
985 	if (!s) {
986 		stop_timer();
987 		return;
988 	}
989 	error = gethostname(hostname, sizeof(hostname));
990 	if (error != 0)
991 		log_err(1, "gethostname");
992 
993 	if (oldconf == nullptr || oldconf->conf_first_target == nullptr)
994 		oldconf = this;
995 	isns->send_request(s, oldconf->isns_deregister_request(hostname));
996 	isns->send_request(s, isns_register_request(hostname));
997 	s.reset();
998 	stop_timer();
999 }
1000 
1001 void
isns_check(struct isns * isns)1002 conf::isns_check(struct isns *isns)
1003 {
1004 	int error;
1005 	char hostname[256];
1006 
1007 	if (conf_targets.empty() || conf_portal_groups.empty())
1008 		return;
1009 	start_timer(conf_isns_timeout);
1010 	freebsd::fd_up s = isns->connect();
1011 	if (!s) {
1012 		stop_timer();
1013 		return;
1014 	}
1015 	error = gethostname(hostname, sizeof(hostname));
1016 	if (error != 0)
1017 		log_err(1, "gethostname");
1018 
1019 	if (!isns->send_request(s, isns_check_request(hostname))) {
1020 		isns->send_request(s, isns_deregister_request(hostname));
1021 		isns->send_request(s, isns_register_request(hostname));
1022 	}
1023 	s.reset();
1024 	stop_timer();
1025 }
1026 
1027 void
isns_deregister_targets(struct isns * isns)1028 conf::isns_deregister_targets(struct isns *isns)
1029 {
1030 	int error;
1031 	char hostname[256];
1032 
1033 	if (conf_targets.empty() || conf_portal_groups.empty())
1034 		return;
1035 	start_timer(conf_isns_timeout);
1036 	freebsd::fd_up s = isns->connect();
1037 	if (!s)
1038 		return;
1039 	error = gethostname(hostname, sizeof(hostname));
1040 	if (error != 0)
1041 		log_err(1, "gethostname");
1042 
1043 	isns->send_request(s, isns_deregister_request(hostname));
1044 	s.reset();
1045 	stop_timer();
1046 }
1047 
1048 void
isns_schedule_update()1049 conf::isns_schedule_update()
1050 {
1051 	if (!conf_isns.empty())
1052 		start_timer((conf_isns_period + 2) / 3);
1053 }
1054 
1055 void
isns_update()1056 conf::isns_update()
1057 {
1058 	stop_timer();
1059 	for (auto &kv : conf_isns)
1060 		isns_check(&kv.second);
1061 
1062 	isns_schedule_update();
1063 }
1064 
1065 bool
add_port(std::string & name,uint32_t ctl_port)1066 kports::add_port(std::string &name, uint32_t ctl_port)
1067 {
1068 	const auto &pair = pports.try_emplace(name, name, ctl_port);
1069 	if (!pair.second) {
1070 		log_warnx("duplicate kernel port \"%s\" (%u)", name.c_str(),
1071 		    ctl_port);
1072 		return (false);
1073 	}
1074 
1075 	return (true);
1076 }
1077 
1078 bool
has_port(std::string_view name)1079 kports::has_port(std::string_view name)
1080 {
1081 	return (pports.count(std::string(name)) > 0);
1082 }
1083 
1084 struct pport *
find_port(std::string_view name)1085 kports::find_port(std::string_view name)
1086 {
1087 	auto it = pports.find(std::string(name));
1088 	if (it == pports.end())
1089 		return (nullptr);
1090 	return (&it->second);
1091 }
1092 
port(struct target * target)1093 port::port(struct target *target) :
1094 	p_target(target)
1095 {
1096 	target->add_port(this);
1097 }
1098 
1099 void
clear_references()1100 port::clear_references()
1101 {
1102 	p_target->remove_port(this);
1103 }
1104 
portal_group_port(struct target * target,struct portal_group * pg,auth_group_sp ag)1105 portal_group_port::portal_group_port(struct target *target,
1106     struct portal_group *pg, auth_group_sp ag) :
1107 	port(target), p_auth_group(ag), p_portal_group(pg)
1108 {
1109 	p_portal_group->add_port(this);
1110 }
1111 
portal_group_port(struct target * target,struct portal_group * pg,uint32_t ctl_port)1112 portal_group_port::portal_group_port(struct target *target,
1113     struct portal_group *pg, uint32_t ctl_port) :
1114 	port(target), p_portal_group(pg)
1115 {
1116 	p_ctl_port = ctl_port;
1117 	p_portal_group->add_port(this);
1118 }
1119 
1120 bool
is_dummy() const1121 portal_group_port::is_dummy() const
1122 {
1123 	return (p_portal_group->is_dummy());
1124 }
1125 
1126 void
clear_references()1127 portal_group_port::clear_references()
1128 {
1129 	p_portal_group->remove_port(this);
1130 	port::clear_references();
1131 }
1132 
1133 bool
add_port(struct target * target,struct portal_group * pg,auth_group_sp ag)1134 conf::add_port(struct target *target, struct portal_group *pg, auth_group_sp ag)
1135 {
1136 	std::string name = freebsd::stringf("%s-%s", pg->name(),
1137 	    target->name());
1138 	const auto &pair = conf_ports.try_emplace(name, pg->create_port(target,
1139 	    ag));
1140 	if (!pair.second) {
1141 		log_warnx("duplicate port \"%s\"", name.c_str());
1142 		return (false);
1143 	}
1144 
1145 	return (true);
1146 }
1147 
1148 bool
add_port(struct target * target,struct portal_group * pg,uint32_t ctl_port)1149 conf::add_port(struct target *target, struct portal_group *pg,
1150     uint32_t ctl_port)
1151 {
1152 	std::string name = freebsd::stringf("%s-%s", pg->name(),
1153 	    target->name());
1154 	const auto &pair = conf_ports.try_emplace(name, pg->create_port(target,
1155 	    ctl_port));
1156 	if (!pair.second) {
1157 		log_warnx("duplicate port \"%s\"", name.c_str());
1158 		return (false);
1159 	}
1160 
1161 	return (true);
1162 }
1163 
1164 bool
add_port(struct target * target,struct pport * pp)1165 conf::add_port(struct target *target, struct pport *pp)
1166 {
1167 	std::string name = freebsd::stringf("%s-%s", pp->name(),
1168 	    target->name());
1169 	const auto &pair = conf_ports.try_emplace(name,
1170 	    std::make_unique<kernel_port>(target, pp));
1171 	if (!pair.second) {
1172 		log_warnx("duplicate port \"%s\"", name.c_str());
1173 		return (false);
1174 	}
1175 
1176 	pp->link();
1177 	return (true);
1178 }
1179 
1180 bool
add_port(struct kports & kports,struct target * target,int pp,int vp)1181 conf::add_port(struct kports &kports, struct target *target, int pp, int vp)
1182 {
1183 	struct pport *pport;
1184 
1185 	std::string pname = freebsd::stringf("ioctl/%d/%d", pp, vp);
1186 
1187 	pport = kports.find_port(pname);
1188 	if (pport != NULL)
1189 		return (add_port(target, pport));
1190 
1191 	std::string name = pname + "-" + target->name();
1192 	const auto &pair = conf_ports.try_emplace(name,
1193 	    std::make_unique<ioctl_port>(target, pp, vp));
1194 	if (!pair.second) {
1195 		log_warnx("duplicate port \"%s\"", name.c_str());
1196 		return (false);
1197 	}
1198 
1199 	return (true);
1200 }
1201 
1202 const struct port *
find_port(std::string_view target) const1203 portal_group::find_port(std::string_view target) const
1204 {
1205 	auto it = pg_ports.find(std::string(target));
1206 	if (it == pg_ports.end())
1207 		return (nullptr);
1208 	return (it->second);
1209 }
1210 
1211 struct target *
add_controller(const char * name)1212 conf::add_controller(const char *name)
1213 {
1214 	if (!nvmf_nqn_valid_strict(name)) {
1215 		log_warnx("controller name \"%s\" is invalid for NVMe", name);
1216 		return nullptr;
1217 	}
1218 
1219 	/*
1220 	 * Normalize the name to lowercase to match iSCSI.
1221 	 */
1222 	std::string t_name(name);
1223 	for (char &c : t_name)
1224 		c = tolower(c);
1225 
1226 	auto const &pair = conf_controllers.try_emplace(t_name,
1227 	    nvmf_make_controller(this, t_name));
1228 	if (!pair.second) {
1229 		log_warnx("duplicated controller \"%s\"", name);
1230 		return nullptr;
1231 	}
1232 
1233 	return pair.first->second.get();
1234 }
1235 
1236 struct target *
find_controller(std::string_view name)1237 conf::find_controller(std::string_view name)
1238 {
1239 	auto it = conf_controllers.find(std::string(name));
1240 	if (it == conf_controllers.end())
1241 		return nullptr;
1242 	return it->second.get();
1243 }
1244 
target(struct conf * conf,const char * keyword,std::string_view name)1245 target::target(struct conf *conf, const char *keyword, std::string_view name) :
1246 	t_conf(conf), t_name(name)
1247 {
1248 	t_label = freebsd::stringf("%s \"%s\"", keyword, t_name.c_str());
1249 }
1250 
1251 struct target *
add_target(const char * name)1252 conf::add_target(const char *name)
1253 {
1254 	if (!valid_iscsi_name(name, log_warnx))
1255 		return (nullptr);
1256 
1257 	/*
1258 	 * RFC 3722 requires us to normalize the name to lowercase.
1259 	 */
1260 	std::string t_name(name);
1261 	for (char &c : t_name)
1262 		c = tolower(c);
1263 
1264 	auto const &pair = conf_targets.try_emplace(t_name,
1265 	    iscsi_make_target(this, t_name));
1266 	if (!pair.second) {
1267 		log_warnx("duplicated target \"%s\"", name);
1268 		return (NULL);
1269 	}
1270 
1271 	if (conf_first_target == nullptr)
1272 		conf_first_target = pair.first->second.get();
1273 	return (pair.first->second.get());
1274 }
1275 
1276 struct target *
find_target(std::string_view name)1277 conf::find_target(std::string_view name)
1278 {
1279 	auto it = conf_targets.find(std::string(name));
1280 	if (it == conf_targets.end())
1281 		return (nullptr);
1282 	return (it->second.get());
1283 }
1284 
1285 bool
use_private_auth(const char * keyword)1286 target::use_private_auth(const char *keyword)
1287 {
1288 	if (t_private_auth)
1289 		return (true);
1290 
1291 	if (t_auth_group != nullptr) {
1292 		log_warnx("cannot use both auth-group and %s for %s",
1293 		    keyword, label());
1294 		return (false);
1295 	}
1296 
1297 	t_auth_group = std::make_shared<struct auth_group>(t_label);
1298 	t_private_auth = true;
1299 	return (true);
1300 }
1301 
1302 bool
add_chap(const char * user,const char * secret)1303 target::add_chap(const char *user, const char *secret)
1304 {
1305 	if (!use_private_auth("chap"))
1306 		return (false);
1307 	return (t_auth_group->add_chap(user, secret));
1308 }
1309 
1310 bool
add_chap_mutual(const char * user,const char * secret,const char * user2,const char * secret2)1311 target::add_chap_mutual(const char *user, const char *secret,
1312     const char *user2, const char *secret2)
1313 {
1314 	if (!use_private_auth("chap-mutual"))
1315 		return (false);
1316 	return (t_auth_group->add_chap_mutual(user, secret, user2, secret2));
1317 }
1318 
1319 bool
add_lun(u_int id,const char * lun_label,const char * lun_name)1320 target::add_lun(u_int id, const char *lun_label, const char *lun_name)
1321 {
1322 	struct lun *t_lun;
1323 
1324 	if (id >= MAX_LUNS) {
1325 		log_warnx("%s too big for %s", lun_label, label());
1326 		return (false);
1327 	}
1328 
1329 	if (t_luns[id] != NULL) {
1330 		log_warnx("duplicate %s for %s", lun_label, label());
1331 		return (false);
1332 	}
1333 
1334 	t_lun = t_conf->find_lun(lun_name);
1335 	if (t_lun == NULL) {
1336 		log_warnx("unknown LUN named %s used for %s", lun_name,
1337 		    label());
1338 		return (false);
1339 	}
1340 
1341 	t_luns[id] = t_lun;
1342 	return (true);
1343 }
1344 
1345 bool
set_alias(std::string_view alias)1346 target::set_alias(std::string_view alias)
1347 {
1348 	if (has_alias()) {
1349 		log_warnx("alias for %s specified more than once", label());
1350 		return (false);
1351 	}
1352 	t_alias = alias;
1353 	return (true);
1354 }
1355 
1356 bool
set_auth_group(const char * ag_name)1357 target::set_auth_group(const char *ag_name)
1358 {
1359 	if (t_auth_group != nullptr) {
1360 		if (t_private_auth)
1361 			log_warnx("cannot use both auth-group and explicit "
1362 			    "authorisations for %s", label());
1363 		else
1364 			log_warnx("auth-group for %s "
1365 			    "specified more than once", label());
1366 		return (false);
1367 	}
1368 	t_auth_group = t_conf->find_auth_group(ag_name);
1369 	if (t_auth_group == nullptr) {
1370 		log_warnx("unknown auth-group \"%s\" for %s",
1371 		    ag_name, label());
1372 		return (false);
1373 	}
1374 	return (true);
1375 }
1376 
1377 bool
set_auth_type(const char * type)1378 target::set_auth_type(const char *type)
1379 {
1380 	if (!use_private_auth("auth-type"))
1381 		return (false);
1382 	return (t_auth_group->set_type(type));
1383 }
1384 
1385 bool
set_physical_port(std::string_view pport)1386 target::set_physical_port(std::string_view pport)
1387 {
1388 	if (!t_pport.empty()) {
1389 		log_warnx("cannot set multiple physical ports for target "
1390 		    "\"%s\"", name());
1391 		return (false);
1392 	}
1393 	t_pport = pport;
1394 	return (true);
1395 }
1396 
1397 bool
set_redirection(const char * addr)1398 target::set_redirection(const char *addr)
1399 {
1400 	if (!t_redirection.empty()) {
1401 		log_warnx("cannot set redirection to \"%s\" for "
1402 		    "%s; already defined",
1403 		    addr, label());
1404 		return (false);
1405 	}
1406 
1407 	t_redirection = addr;
1408 	return (true);
1409 }
1410 
1411 struct lun *
start_lun(u_int id,const char * lun_label,const char * lun_name)1412 target::start_lun(u_int id, const char *lun_label, const char *lun_name)
1413 {
1414 	if (id >= MAX_LUNS) {
1415 		log_warnx("%s too big for %s", lun_label, label());
1416 		return (nullptr);
1417 	}
1418 
1419 	if (t_luns[id] != NULL) {
1420 		log_warnx("duplicate %s for %s", lun_label, label());
1421 		return (nullptr);
1422 	}
1423 
1424 	struct lun *new_lun = t_conf->add_lun(lun_name);
1425 	if (new_lun == nullptr)
1426 		return (nullptr);
1427 
1428 	new_lun->set_scsiname(lun_name);
1429 
1430 	t_luns[id] = new_lun;
1431 
1432 	return (new_lun);
1433 }
1434 
1435 void
add_port(struct port * port)1436 target::add_port(struct port *port)
1437 {
1438 	t_ports.push_back(port);
1439 }
1440 
1441 void
remove_port(struct port * port)1442 target::remove_port(struct port *port)
1443 {
1444 	t_ports.remove(port);
1445 }
1446 
1447 void
remove_lun(struct lun * lun)1448 target::remove_lun(struct lun *lun)
1449 {
1450 	/* XXX: clang is not able to deduce the type without the cast. */
1451 	std::replace(t_luns.begin(), t_luns.end(), lun,
1452 	    static_cast<struct lun *>(nullptr));
1453 }
1454 
1455 void
verify()1456 target::verify()
1457 {
1458 	if (t_auth_group == nullptr) {
1459 		t_auth_group = t_conf->find_auth_group("default");
1460 		assert(t_auth_group != nullptr);
1461 	}
1462 	if (t_ports.empty()) {
1463 		struct portal_group *pg = default_portal_group();
1464 		assert(pg != NULL);
1465 		t_conf->add_port(this, pg, nullptr);
1466 	}
1467 
1468 	bool found = std::any_of(t_luns.begin(), t_luns.end(),
1469 	    [](struct lun *lun) { return (lun != nullptr); });
1470 	if (!found && t_redirection.empty())
1471 		log_warnx("no LUNs defined for %s", label());
1472 	if (found && !t_redirection.empty())
1473 		log_debugx("%s contains LUNs, but configured "
1474 		    "for redirection", label());
1475 }
1476 
lun(struct conf * conf,std::string_view name)1477 lun::lun(struct conf *conf, std::string_view name)
1478     : l_conf(conf), l_options(nvlist_create(0)), l_name(name)
1479 {
1480 }
1481 
1482 struct lun *
add_lun(const char * name)1483 conf::add_lun(const char *name)
1484 {
1485 	const auto &pair = conf_luns.try_emplace(name,
1486 	    std::make_unique<lun>(this, name));
1487 	if (!pair.second) {
1488 		log_warnx("duplicated lun \"%s\"", name);
1489 		return (NULL);
1490 	}
1491 	return (pair.first->second.get());
1492 }
1493 
1494 void
delete_target_luns(struct lun * lun)1495 conf::delete_target_luns(struct lun *lun)
1496 {
1497 	for (const auto &kv : conf_targets)
1498 		kv.second->remove_lun(lun);
1499 	for (const auto &kv : conf_controllers)
1500 		kv.second->remove_lun(lun);
1501 }
1502 
1503 struct lun *
find_lun(std::string_view name)1504 conf::find_lun(std::string_view name)
1505 {
1506 	auto it = conf_luns.find(std::string(name));
1507 	if (it == conf_luns.end())
1508 		return (nullptr);
1509 	return (it->second.get());
1510 }
1511 
1512 static void
nvlist_replace_string(nvlist_t * nvl,const char * name,const char * value)1513 nvlist_replace_string(nvlist_t *nvl, const char *name, const char *value)
1514 {
1515 	if (nvlist_exists_string(nvl, name))
1516 		nvlist_free_string(nvl, name);
1517 	nvlist_add_string(nvl, name, value);
1518 }
1519 
1520 freebsd::nvlist_up
options() const1521 lun::options() const
1522 {
1523 	freebsd::nvlist_up nvl(nvlist_clone(l_options.get()));
1524 	if (!l_path.empty())
1525 		nvlist_replace_string(nvl.get(), "file", l_path.c_str());
1526 
1527 	nvlist_replace_string(nvl.get(), "ctld_name", l_name.c_str());
1528 
1529 	if (!nvlist_exists_string(nvl.get(), "scsiname") &&
1530 	    !l_scsiname.empty())
1531 		nvlist_add_string(nvl.get(), "scsiname", l_scsiname.c_str());
1532 	return (nvl);
1533 }
1534 
1535 bool
add_option(const char * name,const char * value)1536 lun::add_option(const char *name, const char *value)
1537 {
1538 	return (option_new(l_options.get(), name, value));
1539 }
1540 
1541 bool
set_backend(std::string_view value)1542 lun::set_backend(std::string_view value)
1543 {
1544 	if (!l_backend.empty()) {
1545 		log_warnx("backend for lun \"%s\" specified more than once",
1546 		    name());
1547 		return (false);
1548 	}
1549 
1550 	l_backend = value;
1551 	return (true);
1552 }
1553 
1554 bool
set_blocksize(size_t value)1555 lun::set_blocksize(size_t value)
1556 {
1557 	if (l_blocksize != 0) {
1558 		log_warnx("blocksize for lun \"%s\" specified more than once",
1559 		    name());
1560 		return (false);
1561 	}
1562 	l_blocksize = value;
1563 	return (true);
1564 }
1565 
1566 bool
set_ctl_lun(uint32_t value)1567 lun::set_ctl_lun(uint32_t value)
1568 {
1569 	if (l_ctl_lun >= 0) {
1570 		log_warnx("ctl_lun for lun \"%s\" specified more than once",
1571 		    name());
1572 		return (false);
1573 	}
1574 
1575 	l_ctl_lun = value;
1576 	return (true);
1577 }
1578 
1579 bool
set_device_type(uint8_t device_type)1580 lun::set_device_type(uint8_t device_type)
1581 {
1582 	if (device_type > 15) {
1583 		log_warnx("invalid device-type \"%u\" for lun \"%s\"",
1584 		    device_type, name());
1585 		return (false);
1586 	}
1587 
1588 	l_device_type = device_type;
1589 	return (true);
1590 }
1591 
1592 bool
set_device_type(const char * value)1593 lun::set_device_type(const char *value)
1594 {
1595 	const char *errstr;
1596 	int device_type;
1597 
1598 	if (strcasecmp(value, "disk") == 0 ||
1599 	    strcasecmp(value, "direct") == 0)
1600 		device_type = T_DIRECT;
1601 	else if (strcasecmp(value, "processor") == 0)
1602 		device_type = T_PROCESSOR;
1603 	else if (strcasecmp(value, "cd") == 0 ||
1604 	    strcasecmp(value, "cdrom") == 0 ||
1605 	    strcasecmp(value, "dvd") == 0 ||
1606 	    strcasecmp(value, "dvdrom") == 0)
1607 		device_type = T_CDROM;
1608 	else {
1609 		device_type = strtonum(value, 0, 15, &errstr);
1610 		if (errstr != NULL) {
1611 			log_warnx("invalid device-type \"%s\" for lun \"%s\"",
1612 			    value, name());
1613 			return (false);
1614 		}
1615 	}
1616 
1617 	l_device_type = device_type;
1618 	return (true);
1619 }
1620 
1621 bool
set_device_id(std::string_view value)1622 lun::set_device_id(std::string_view value)
1623 {
1624 	if (!l_device_id.empty()) {
1625 		log_warnx("device_id for lun \"%s\" specified more than once",
1626 		    name());
1627 		return (false);
1628 	}
1629 
1630 	l_device_id = value;
1631 	return (true);
1632 }
1633 
1634 bool
set_path(std::string_view value)1635 lun::set_path(std::string_view value)
1636 {
1637 	if (!l_path.empty()) {
1638 		log_warnx("path for lun \"%s\" specified more than once",
1639 		    name());
1640 		return (false);
1641 	}
1642 
1643 	l_path = value;
1644 	return (true);
1645 }
1646 
1647 void
set_scsiname(std::string_view value)1648 lun::set_scsiname(std::string_view value)
1649 {
1650 	l_scsiname = value;
1651 }
1652 
1653 bool
set_serial(std::string_view value)1654 lun::set_serial(std::string_view value)
1655 {
1656 	if (!l_serial.empty()) {
1657 		log_warnx("serial for lun \"%s\" specified more than once",
1658 		    name());
1659 		return (false);
1660 	}
1661 
1662 	l_serial = value;
1663 	return (true);
1664 }
1665 
1666 bool
set_size(uint64_t value)1667 lun::set_size(uint64_t value)
1668 {
1669 	if (l_size != 0) {
1670 		log_warnx("size for lun \"%s\" specified more than once",
1671 		    name());
1672 		return (false);
1673 	}
1674 
1675 	l_size = value;
1676 	return (true);
1677 }
1678 
1679 
1680 bool
changed(const struct lun & newlun) const1681 lun::changed(const struct lun &newlun) const
1682 {
1683 	if (l_backend != newlun.l_backend) {
1684 		log_debugx("backend for lun \"%s\", CTL lun %d changed; "
1685 		    "removing", name(), l_ctl_lun);
1686 		return (true);
1687 	}
1688 	if (l_blocksize != newlun.l_blocksize) {
1689 		log_debugx("blocksize for lun \"%s\", CTL lun %d changed; "
1690 		    "removing", name(), l_ctl_lun);
1691 		return (true);
1692 	}
1693 	if (l_device_id != newlun.l_device_id) {
1694 		log_debugx("device-id for lun \"%s\", CTL lun %d changed; "
1695 		    "removing", name(), l_ctl_lun);
1696 		return (true);
1697 	}
1698 	if (l_path != newlun.l_path) {
1699 		log_debugx("path for lun \"%s\", CTL lun %d, changed; "
1700 		    "removing", name(), l_ctl_lun);
1701 		return (true);
1702 	}
1703 	if (l_serial != newlun.l_serial) {
1704 		log_debugx("serial for lun \"%s\", CTL lun %d changed; "
1705 		    "removing", name(), l_ctl_lun);
1706 		return (true);
1707 	}
1708 	return (false);
1709 }
1710 
1711 bool
option_new(nvlist_t * nvl,const char * name,const char * value)1712 option_new(nvlist_t *nvl, const char *name, const char *value)
1713 {
1714 	int error;
1715 
1716 	if (nvlist_exists_string(nvl, name)) {
1717 		log_warnx("duplicated option \"%s\"", name);
1718 		return (false);
1719 	}
1720 
1721 	nvlist_add_string(nvl, name, value);
1722 	error = nvlist_error(nvl);
1723 	if (error != 0) {
1724 		log_warnc(error, "failed to add option \"%s\"", name);
1725 		return (false);
1726 	}
1727 	return (true);
1728 }
1729 
1730 bool
verify()1731 lun::verify()
1732 {
1733 	if (l_backend.empty())
1734 		l_backend = "block";
1735 	if (l_backend == "block") {
1736 		if (l_path.empty()) {
1737 			log_warnx("missing path for lun \"%s\"",
1738 			    name());
1739 			return (false);
1740 		}
1741 	} else if (l_backend == "ramdisk") {
1742 		if (l_size == 0) {
1743 			log_warnx("missing size for ramdisk-backed lun \"%s\"",
1744 			    name());
1745 			return (false);
1746 		}
1747 		if (!l_path.empty()) {
1748 			log_warnx("path must not be specified "
1749 			    "for ramdisk-backed lun \"%s\"",
1750 			    name());
1751 			return (false);
1752 		}
1753 	}
1754 	if (l_blocksize == 0) {
1755 		if (l_device_type == T_CDROM)
1756 			l_blocksize = DEFAULT_CD_BLOCKSIZE;
1757 		else
1758 			l_blocksize = DEFAULT_BLOCKSIZE;
1759 	} else if (l_blocksize < 0) {
1760 		log_warnx("invalid blocksize %d for lun \"%s\"; "
1761 		    "must be larger than 0", l_blocksize, name());
1762 		return (false);
1763 	}
1764 	if (l_size != 0 && (l_size % l_blocksize) != 0) {
1765 		log_warnx("invalid size for lun \"%s\"; "
1766 		    "must be multiple of blocksize", name());
1767 		return (false);
1768 	}
1769 	return (true);
1770 }
1771 
1772 bool
verify()1773 conf::verify()
1774 {
1775 	if (conf_pidfile_path.empty())
1776 		conf_pidfile_path = DEFAULT_PIDFILE;
1777 
1778 	std::unordered_map<std::string, struct lun *> path_map;
1779 	for (const auto &kv : conf_luns) {
1780 		struct lun *lun = kv.second.get();
1781 		if (!lun->verify())
1782 			return (false);
1783 
1784 		const std::string &path = lun->path();
1785 		if (path.empty())
1786 			continue;
1787 
1788 		const auto &pair = path_map.try_emplace(path, lun);
1789 		if (!pair.second) {
1790 			struct lun *lun2 = pair.first->second;
1791 			log_debugx("WARNING: path \"%s\" duplicated "
1792 			    "between lun \"%s\", and "
1793 			    "lun \"%s\"", path.c_str(),
1794 			    lun->name(), lun2->name());
1795 		}
1796 	}
1797 
1798 	for (auto &kv : conf_targets) {
1799 		kv.second->verify();
1800 	}
1801 	for (auto &kv : conf_controllers) {
1802 		kv.second->verify();
1803 	}
1804 	for (auto &kv : conf_portal_groups) {
1805 		kv.second->verify(this);
1806 	}
1807 	for (auto &kv : conf_transport_groups) {
1808 		kv.second->verify(this);
1809 	}
1810 	for (const auto &kv : conf_auth_groups) {
1811 		const std::string &ag_name = kv.first;
1812 		if (ag_name == "default" ||
1813 		    ag_name == "no-authentication" ||
1814 		    ag_name == "no-access")
1815 			continue;
1816 
1817 		if (kv.second.use_count() == 1) {
1818 			log_warnx("auth-group \"%s\" not assigned "
1819 			    "to any target", ag_name.c_str());
1820 		}
1821 	}
1822 
1823 	return (true);
1824 }
1825 
1826 bool
reuse_socket(struct portal & oldp)1827 portal::reuse_socket(struct portal &oldp)
1828 {
1829 	struct kevent kev;
1830 
1831 	if (p_listen != oldp.p_listen)
1832 		return (false);
1833 
1834 	if (!oldp.p_socket)
1835 		return (false);
1836 
1837 	EV_SET(&kev, oldp.p_socket, EVFILT_READ, EV_ADD, 0, 0, this);
1838 	if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == -1)
1839 		return (false);
1840 
1841 	p_socket = std::move(oldp.p_socket);
1842 	return (true);
1843 }
1844 
1845 bool
init_socket()1846 portal::init_socket()
1847 {
1848 	struct portal_group *pg = portal_group();
1849 	struct kevent kev;
1850 	freebsd::fd_up s;
1851 	int error;
1852 	int one = 1;
1853 
1854 #ifdef ICL_KERNEL_PROXY
1855 	if (proxy_mode) {
1856 		int id = pg->conf()->add_proxy_portal(this);
1857 		log_debugx("listening on %s, %s \"%s\", "
1858 		    "portal id %d, using ICL proxy", listen(), pg->keyword(),
1859 		    pg->name(), id);
1860 		kernel_listen(ai(), protocol() == ISER, id);
1861 		return (true);
1862 	}
1863 #endif
1864 	assert(proxy_mode == false);
1865 	assert(protocol() != portal_protocol::ISER);
1866 
1867 	log_debugx("listening on %s, %s \"%s\"", listen(), pg->keyword(),
1868 	    pg->name());
1869 	s = ::socket(p_ai->ai_family, p_ai->ai_socktype, p_ai->ai_protocol);
1870 	if (!s) {
1871 		log_warn("socket(2) failed for %s", listen());
1872 		return (false);
1873 	}
1874 
1875 	if (setsockopt(s, SOL_SOCKET, SO_NO_DDP, &one,
1876 	    sizeof(one)) == -1)
1877 		log_warn("setsockopt(SO_NO_DDP) failed for %s", listen());
1878 	error = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one,
1879 	    sizeof(one));
1880 	if (error != 0) {
1881 		log_warn("setsockopt(SO_REUSEADDR) failed for %s", listen());
1882 		return (false);
1883 	}
1884 
1885 	if (pg->dscp() != -1) {
1886 		/* Only allow the 6-bit DSCP field to be modified */
1887 		int tos = pg->dscp() << 2;
1888 		switch (p_ai->ai_family) {
1889 		case AF_INET:
1890 			if (setsockopt(s, IPPROTO_IP, IP_TOS,
1891 			    &tos, sizeof(tos)) == -1)
1892 				log_warn("setsockopt(IP_TOS) failed for %s",
1893 				    listen());
1894 			break;
1895 		case AF_INET6:
1896 			if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS,
1897 			    &tos, sizeof(tos)) == -1)
1898 				log_warn("setsockopt(IPV6_TCLASS) failed for %s",
1899 				    listen());
1900 			break;
1901 		}
1902 	}
1903 	if (pg->pcp() != -1) {
1904 		int pcp = pg->pcp();
1905 		switch (p_ai->ai_family) {
1906 		case AF_INET:
1907 			if (setsockopt(s, IPPROTO_IP, IP_VLAN_PCP,
1908 			    &pcp, sizeof(pcp)) == -1)
1909 				log_warn("setsockopt(IP_VLAN_PCP) failed for %s",
1910 				    listen());
1911 			break;
1912 		case AF_INET6:
1913 			if (setsockopt(s, IPPROTO_IPV6, IPV6_VLAN_PCP,
1914 			    &pcp, sizeof(pcp)) == -1)
1915 				log_warn("setsockopt(IPV6_VLAN_PCP) failed for %s",
1916 				    listen());
1917 			break;
1918 		}
1919 	}
1920 
1921 	if (!init_socket_options(s))
1922 		return (false);
1923 
1924 	error = bind(s, p_ai->ai_addr, p_ai->ai_addrlen);
1925 	if (error != 0) {
1926 		log_warn("bind(2) failed for %s", listen());
1927 		return (false);
1928 	}
1929 	error = ::listen(s, -1);
1930 	if (error != 0) {
1931 		log_warn("listen(2) failed for %s", listen());
1932 		return (false);
1933 	}
1934 	EV_SET(&kev, s, EVFILT_READ, EV_ADD, 0, 0, this);
1935 	error = kevent(kqfd, &kev, 1, NULL, 0, NULL);
1936 	if (error == -1) {
1937 		log_warn("kevent(2) failed to register for %s", listen());
1938 		return (false);
1939 	}
1940 	p_socket = std::move(s);
1941 	return (true);
1942 }
1943 
1944 bool
reuse_portal_group_socket(struct portal & newp)1945 conf::reuse_portal_group_socket(struct portal &newp)
1946 {
1947 	for (auto &kv : conf_portal_groups) {
1948 		struct portal_group &pg = *kv.second;
1949 
1950 		if (pg.reuse_socket(newp))
1951 			return (true);
1952 	}
1953 	for (auto &kv : conf_transport_groups) {
1954 		struct portal_group &pg = *kv.second;
1955 
1956 		if (pg.reuse_socket(newp))
1957 			return (true);
1958 	}
1959 	return (false);
1960 }
1961 
1962 int
apply(struct conf * oldconf)1963 conf::apply(struct conf *oldconf)
1964 {
1965 	int cumulated_error = 0;
1966 
1967 	if (oldconf->conf_debug != conf_debug) {
1968 		log_debugx("changing debug level to %d", conf_debug);
1969 		log_init(conf_debug);
1970 	}
1971 
1972 	/*
1973 	 * On startup, oldconf created via conf_new_from_kernel will
1974 	 * not contain a valid pidfile_path, and the current
1975 	 * conf_pidfile will already own the pidfile.  On shutdown,
1976 	 * the temporary newconf will not contain a valid
1977 	 * pidfile_path, and the pidfile will be cleaned up when the
1978 	 * oldconf is deleted.
1979 	 */
1980 	if (!oldconf->conf_pidfile_path.empty() &&
1981 	    !conf_pidfile_path.empty()) {
1982 		if (oldconf->conf_pidfile_path != conf_pidfile_path) {
1983 			/* pidfile has changed.  rename it */
1984 			log_debugx("moving pidfile to %s",
1985 			    conf_pidfile_path.c_str());
1986 			if (rename(oldconf->conf_pidfile_path.c_str(),
1987 				conf_pidfile_path.c_str()) != 0) {
1988 				log_err(1, "renaming pidfile %s -> %s",
1989 				    oldconf->conf_pidfile_path.c_str(),
1990 				    conf_pidfile_path.c_str());
1991 			}
1992 		}
1993 		conf_pidfile = std::move(oldconf->conf_pidfile);
1994 	}
1995 
1996 	/*
1997 	 * Go through the new portal groups, assigning tags or preserving old.
1998 	 */
1999 	for (auto &kv : conf_portal_groups) {
2000 		struct portal_group &newpg = *kv.second;
2001 
2002 		if (newpg.tag() != 0)
2003 			continue;
2004 		auto it = oldconf->conf_portal_groups.find(kv.first);
2005 		if (it != oldconf->conf_portal_groups.end())
2006 			newpg.set_tag(it->second->tag());
2007 		else
2008 			newpg.allocate_tag();
2009 	}
2010 	for (auto &kv : conf_transport_groups) {
2011 		struct portal_group &newpg = *kv.second;
2012 
2013 		if (newpg.tag() != 0)
2014 			continue;
2015 		auto it = oldconf->conf_transport_groups.find(kv.first);
2016 		if (it != oldconf->conf_transport_groups.end())
2017 			newpg.set_tag(it->second->tag());
2018 		else
2019 			newpg.allocate_tag();
2020 	}
2021 
2022 	/* Deregister on removed iSNS servers. */
2023 	for (auto &kv : oldconf->conf_isns) {
2024 		if (conf_isns.count(kv.first) == 0)
2025 			oldconf->isns_deregister_targets(&kv.second);
2026 	}
2027 
2028 	/*
2029 	 * XXX: If target or lun removal fails, we should somehow "move"
2030 	 *      the old lun or target into this, so that subsequent
2031 	 *      conf::apply() would try to remove them again.  That would
2032 	 *      be somewhat hairy, though, and lun deletion failures don't
2033 	 *      really happen, so leave it as it is for now.
2034 	 */
2035 	/*
2036 	 * First, remove any ports present in the old configuration
2037 	 * and missing in the new one.
2038 	 */
2039 	for (const auto &kv : oldconf->conf_ports) {
2040 		const std::string &name = kv.first;
2041 		port *oldport = kv.second.get();
2042 
2043 		if (oldport->is_dummy())
2044 			continue;
2045 		const auto it = conf_ports.find(name);
2046 		if (it != conf_ports.end() && !it->second->is_dummy())
2047 			continue;
2048 		log_debugx("removing port \"%s\"", name.c_str());
2049 		if (!oldport->kernel_remove()) {
2050 			log_warnx("failed to remove port %s", name.c_str());
2051 			/*
2052 			 * XXX: Uncomment after fixing the root cause.
2053 			 *
2054 			 * cumulated_error++;
2055 			 */
2056 		}
2057 	}
2058 
2059 	/*
2060 	 * Second, remove any LUNs present in the old configuration
2061 	 * and missing in the new one.
2062 	 */
2063 	for (auto it = oldconf->conf_luns.begin();
2064 	     it != oldconf->conf_luns.end(); ) {
2065 		struct lun *oldlun = it->second.get();
2066 
2067 		auto newit = conf_luns.find(it->first);
2068 		if (newit == conf_luns.end()) {
2069 			log_debugx("lun \"%s\", CTL lun %d "
2070 			    "not found in new configuration; "
2071 			    "removing", oldlun->name(), oldlun->ctl_lun());
2072 			if (!oldlun->kernel_remove()) {
2073 				log_warnx("failed to remove lun \"%s\", "
2074 				    "CTL lun %d",
2075 				    oldlun->name(), oldlun->ctl_lun());
2076 				cumulated_error++;
2077 			}
2078 			it++;
2079 			continue;
2080 		}
2081 
2082 		/*
2083 		 * Also remove the LUNs changed by more than size.
2084 		 */
2085 		struct lun *newlun = newit->second.get();
2086 		if (oldlun->changed(*newlun)) {
2087 			if (!oldlun->kernel_remove()) {
2088 				log_warnx("failed to remove lun \"%s\", "
2089 				    "CTL lun %d",
2090 				    oldlun->name(), oldlun->ctl_lun());
2091 				cumulated_error++;
2092 			}
2093 
2094 			/*
2095 			 * Delete the lun from the old configuration
2096 			 * so it is added as a new LUN below.
2097 			 */
2098 			it = oldconf->conf_luns.erase(it);
2099 			continue;
2100 		}
2101 
2102 		newlun->set_ctl_lun(oldlun->ctl_lun());
2103 		it++;
2104 	}
2105 
2106 	for (auto it = conf_luns.begin(); it != conf_luns.end(); ) {
2107 		struct lun *newlun = it->second.get();
2108 
2109 		auto oldit = oldconf->conf_luns.find(it->first);
2110 		if (oldit != oldconf->conf_luns.end()) {
2111 			log_debugx("modifying lun \"%s\", CTL lun %d",
2112 			    newlun->name(), newlun->ctl_lun());
2113 			if (!newlun->kernel_modify()) {
2114 				log_warnx("failed to "
2115 				    "modify lun \"%s\", CTL lun %d",
2116 				    newlun->name(), newlun->ctl_lun());
2117 				cumulated_error++;
2118 			}
2119 			it++;
2120 			continue;
2121 		}
2122 
2123 		log_debugx("adding lun \"%s\"", newlun->name());
2124 		if (!newlun->kernel_add()) {
2125 			log_warnx("failed to add lun \"%s\"", newlun->name());
2126 			delete_target_luns(newlun);
2127 			it = conf_luns.erase(it);
2128 			cumulated_error++;
2129 		} else
2130 			it++;
2131 	}
2132 
2133 	/*
2134 	 * Now add new ports or modify existing ones.
2135 	 */
2136 	for (auto it = conf_ports.begin(); it != conf_ports.end(); ) {
2137 		const std::string &name = it->first;
2138 		port *newport = it->second.get();
2139 
2140 		if (newport->is_dummy()) {
2141 			it++;
2142 			continue;
2143 		}
2144 		const auto oldit = oldconf->conf_ports.find(name);
2145 		if (oldit == oldconf->conf_ports.end() ||
2146 		    oldit->second->is_dummy()) {
2147 			log_debugx("adding port \"%s\"", name.c_str());
2148 			if (!newport->kernel_add()) {
2149 				log_warnx("failed to add port %s",
2150 				    name.c_str());
2151 
2152 				/*
2153 				 * XXX: Uncomment after fixing the
2154 				 * root cause.
2155 				 *
2156 				 * cumulated_error++;
2157 				 */
2158 
2159 				/*
2160 				 * conf "owns" the port, but other
2161 				 * objects contain pointers to this
2162 				 * port that must be removed before
2163 				 * deleting the port.
2164 				 */
2165 				newport->clear_references();
2166 				it = conf_ports.erase(it);
2167 			} else
2168 				it++;
2169 		} else {
2170 			log_debugx("updating port \"%s\"", name.c_str());
2171 			if (!newport->kernel_update(oldit->second.get()))
2172 				log_warnx("failed to update port %s",
2173 				    name.c_str());
2174 			it++;
2175 		}
2176 	}
2177 
2178 	/*
2179 	 * Go through the new portals, opening the sockets as necessary.
2180 	 */
2181 	for (auto &kv : conf_portal_groups) {
2182 		cumulated_error += kv.second->open_sockets(*oldconf);
2183 	}
2184 	for (auto &kv : conf_transport_groups) {
2185 		cumulated_error += kv.second->open_sockets(*oldconf);
2186 	}
2187 
2188 	/*
2189 	 * Go through the no longer used sockets, closing them.
2190 	 */
2191 	for (auto &kv : oldconf->conf_portal_groups) {
2192 		kv.second->close_sockets();
2193 	}
2194 	for (auto &kv : oldconf->conf_transport_groups) {
2195 		kv.second->close_sockets();
2196 	}
2197 
2198 	/* (Re-)Register on remaining/new iSNS servers. */
2199 	for (auto &kv : conf_isns) {
2200 		auto it = oldconf->conf_isns.find(kv.first);
2201 		if (it == oldconf->conf_isns.end())
2202 			isns_register_targets(&kv.second, nullptr);
2203 		else
2204 			isns_register_targets(&kv.second, oldconf);
2205 	}
2206 
2207 	isns_schedule_update();
2208 
2209 	return (cumulated_error);
2210 }
2211 
2212 bool
timed_out(void)2213 timed_out(void)
2214 {
2215 
2216 	return (sigalrm_received);
2217 }
2218 
2219 static void
sigalrm_handler_fatal(int dummy __unused)2220 sigalrm_handler_fatal(int dummy __unused)
2221 {
2222 	/*
2223 	 * It would be easiest to just log an error and exit.  We can't
2224 	 * do this, though, because log_errx() is not signal safe, since
2225 	 * it calls syslog(3).  Instead, set a flag checked by pdu_send()
2226 	 * and pdu_receive(), to call log_errx() there.  Should they fail
2227 	 * to notice, we'll exit here one second later.
2228 	 */
2229 	if (sigalrm_received) {
2230 		/*
2231 		 * Oh well.  Just give up and quit.
2232 		 */
2233 		_exit(2);
2234 	}
2235 
2236 	sigalrm_received = true;
2237 }
2238 
2239 static void
sigalrm_handler(int dummy __unused)2240 sigalrm_handler(int dummy __unused)
2241 {
2242 
2243 	sigalrm_received = true;
2244 }
2245 
2246 void
stop_timer()2247 stop_timer()
2248 {
2249 	struct itimerval itv;
2250 	int error;
2251 
2252 	log_debugx("session timeout disabled");
2253 	bzero(&itv, sizeof(itv));
2254 	error = setitimer(ITIMER_REAL, &itv, NULL);
2255 	if (error != 0)
2256 		log_err(1, "setitimer");
2257 	sigalrm_received = false;
2258 }
2259 
2260 void
start_timer(int timeout,bool fatal)2261 start_timer(int timeout, bool fatal)
2262 {
2263 	struct sigaction sa;
2264 	struct itimerval itv;
2265 	int error;
2266 
2267 	if (timeout <= 0) {
2268 		stop_timer();
2269 		return;
2270 	}
2271 
2272 	sigalrm_received = false;
2273 	bzero(&sa, sizeof(sa));
2274 	if (fatal)
2275 		sa.sa_handler = sigalrm_handler_fatal;
2276 	else
2277 		sa.sa_handler = sigalrm_handler;
2278 	sigfillset(&sa.sa_mask);
2279 	error = sigaction(SIGALRM, &sa, NULL);
2280 	if (error != 0)
2281 		log_err(1, "sigaction");
2282 
2283 	/*
2284 	 * First SIGALRM will arive after timeout seconds.
2285 	 * If we do nothing, another one will arrive a second later.
2286 	 */
2287 	log_debugx("setting session timeout to %d seconds", timeout);
2288 	bzero(&itv, sizeof(itv));
2289 	itv.it_interval.tv_sec = 1;
2290 	itv.it_value.tv_sec = timeout;
2291 	error = setitimer(ITIMER_REAL, &itv, NULL);
2292 	if (error != 0)
2293 		log_err(1, "setitimer");
2294 }
2295 
2296 static int
wait_for_children(bool block)2297 wait_for_children(bool block)
2298 {
2299 	pid_t pid;
2300 	int status;
2301 	int num = 0;
2302 
2303 	for (;;) {
2304 		/*
2305 		 * If "block" is true, wait for at least one process.
2306 		 */
2307 		if (block && num == 0)
2308 			pid = wait4(-1, &status, 0, NULL);
2309 		else
2310 			pid = wait4(-1, &status, WNOHANG, NULL);
2311 		if (pid <= 0)
2312 			break;
2313 		if (WIFSIGNALED(status)) {
2314 			log_warnx("child process %d terminated with signal %d",
2315 			    pid, WTERMSIG(status));
2316 		} else if (WEXITSTATUS(status) != 0) {
2317 			log_warnx("child process %d terminated with exit status %d",
2318 			    pid, WEXITSTATUS(status));
2319 		} else {
2320 			log_debugx("child process %d terminated gracefully", pid);
2321 		}
2322 		num++;
2323 	}
2324 
2325 	return (num);
2326 }
2327 
2328 static void
handle_connection(struct portal * portal,freebsd::fd_up fd,const struct sockaddr * client_sa,bool dont_fork)2329 handle_connection(struct portal *portal, freebsd::fd_up fd,
2330     const struct sockaddr *client_sa, bool dont_fork)
2331 {
2332 	struct portal_group *pg;
2333 	int error;
2334 	pid_t pid;
2335 	char host[NI_MAXHOST + 1];
2336 	struct conf *conf;
2337 
2338 	pg = portal->portal_group();
2339 	conf = pg->conf();
2340 
2341 	if (dont_fork) {
2342 		log_debugx("incoming connection; not forking due to -d flag");
2343 	} else {
2344 		nchildren -= wait_for_children(false);
2345 		assert(nchildren >= 0);
2346 
2347 		while (conf->maxproc() > 0 && nchildren >= conf->maxproc()) {
2348 			log_debugx("maxproc limit of %d child processes hit; "
2349 			    "waiting for child process to exit",
2350 			    conf->maxproc());
2351 			nchildren -= wait_for_children(true);
2352 			assert(nchildren >= 0);
2353 		}
2354 		log_debugx("incoming connection; forking child process #%d",
2355 		    nchildren);
2356 		nchildren++;
2357 		pid = fork();
2358 		if (pid < 0)
2359 			log_err(1, "fork");
2360 		if (pid > 0)
2361 			return;
2362 		conf->close_pidfile();
2363 	}
2364 
2365 	error = getnameinfo(client_sa, client_sa->sa_len,
2366 	    host, sizeof(host), NULL, 0, NI_NUMERICHOST);
2367 	if (error != 0)
2368 		log_errx(1, "getnameinfo: %s", gai_strerror(error));
2369 
2370 	log_debugx("accepted connection from %s; portal group \"%s\"",
2371 	    host, pg->name());
2372 	log_set_peer_addr(host);
2373 	setproctitle("%s", host);
2374 
2375 	portal->handle_connection(std::move(fd), host, client_sa);
2376 	log_debugx("nothing more to do; exiting");
2377 	exit(0);
2378 }
2379 
2380 static void
main_loop(bool dont_fork)2381 main_loop(bool dont_fork)
2382 {
2383 	struct kevent kev;
2384 	struct portal *portal;
2385 	struct sockaddr_storage client_sa;
2386 	socklen_t client_salen;
2387 #ifdef ICL_KERNEL_PROXY
2388 	int connection_id;
2389 	int portal_id;
2390 #endif
2391 	int error, client_fd;
2392 
2393 	for (;;) {
2394 		if (sighup_received || sigterm_received || timed_out())
2395 			return;
2396 
2397 #ifdef ICL_KERNEL_PROXY
2398 		if (proxy_mode) {
2399 			client_salen = sizeof(client_sa);
2400 			kernel_accept(&connection_id, &portal_id,
2401 			    (struct sockaddr *)&client_sa, &client_salen);
2402 			assert(client_salen >= client_sa.ss_len);
2403 
2404 			log_debugx("incoming connection, id %d, portal id %d",
2405 			    connection_id, portal_id);
2406 			portal = conf->proxy_portal(portal_id);
2407 			if (portal == nullptr)
2408 				log_errx(1,
2409 				    "kernel returned invalid portal_id %d",
2410 				    portal_id);
2411 
2412 			handle_connection(portal, connection_id,
2413 			    (struct sockaddr *)&client_sa, dont_fork);
2414 		} else {
2415 #endif
2416 			assert(proxy_mode == false);
2417 
2418 			error = kevent(kqfd, NULL, 0, &kev, 1, NULL);
2419 			if (error == -1) {
2420 				if (errno == EINTR)
2421 					continue;
2422 				log_err(1, "kevent");
2423 			}
2424 
2425 			switch (kev.filter) {
2426 			case EVFILT_READ:
2427 				portal = reinterpret_cast<struct portal *>(kev.udata);
2428 				assert(portal->socket() == (int)kev.ident);
2429 
2430 				client_salen = sizeof(client_sa);
2431 				client_fd = accept(portal->socket(),
2432 				    (struct sockaddr *)&client_sa,
2433 				    &client_salen);
2434 				if (client_fd < 0) {
2435 					if (errno == ECONNABORTED)
2436 						continue;
2437 					log_err(1, "accept");
2438 				}
2439 				assert(client_salen >= client_sa.ss_len);
2440 
2441 				handle_connection(portal, client_fd,
2442 				    (struct sockaddr *)&client_sa, dont_fork);
2443 				break;
2444 			default:
2445 				__assert_unreachable();
2446 			}
2447 #ifdef ICL_KERNEL_PROXY
2448 		}
2449 #endif
2450 	}
2451 }
2452 
2453 static void
sighup_handler(int dummy __unused)2454 sighup_handler(int dummy __unused)
2455 {
2456 
2457 	sighup_received = true;
2458 }
2459 
2460 static void
sigterm_handler(int dummy __unused)2461 sigterm_handler(int dummy __unused)
2462 {
2463 
2464 	sigterm_received = true;
2465 }
2466 
2467 static void
sigchld_handler(int dummy __unused)2468 sigchld_handler(int dummy __unused)
2469 {
2470 
2471 	/*
2472 	 * The only purpose of this handler is to make SIGCHLD
2473 	 * interrupt the ISCSIDWAIT ioctl(2), so we can call
2474 	 * wait_for_children().
2475 	 */
2476 }
2477 
2478 static void
register_signals(void)2479 register_signals(void)
2480 {
2481 	struct sigaction sa;
2482 	int error;
2483 
2484 	bzero(&sa, sizeof(sa));
2485 	sa.sa_handler = sighup_handler;
2486 	sigfillset(&sa.sa_mask);
2487 	error = sigaction(SIGHUP, &sa, NULL);
2488 	if (error != 0)
2489 		log_err(1, "sigaction");
2490 
2491 	sa.sa_handler = sigterm_handler;
2492 	error = sigaction(SIGTERM, &sa, NULL);
2493 	if (error != 0)
2494 		log_err(1, "sigaction");
2495 
2496 	sa.sa_handler = sigterm_handler;
2497 	error = sigaction(SIGINT, &sa, NULL);
2498 	if (error != 0)
2499 		log_err(1, "sigaction");
2500 
2501 	sa.sa_handler = sigchld_handler;
2502 	error = sigaction(SIGCHLD, &sa, NULL);
2503 	if (error != 0)
2504 		log_err(1, "sigaction");
2505 }
2506 
2507 static void
check_perms(const char * path)2508 check_perms(const char *path)
2509 {
2510 	struct stat sb;
2511 	int error;
2512 
2513 	error = stat(path, &sb);
2514 	if (error != 0) {
2515 		log_warn("stat");
2516 		return;
2517 	}
2518 	if (sb.st_mode & S_IWOTH) {
2519 		log_warnx("%s is world-writable", path);
2520 	} else if (sb.st_mode & S_IROTH) {
2521 		log_warnx("%s is world-readable", path);
2522 	} else if (sb.st_mode & S_IXOTH) {
2523 		/*
2524 		 * Ok, this one doesn't matter, but still do it,
2525 		 * just for consistency.
2526 		 */
2527 		log_warnx("%s is world-executable", path);
2528 	}
2529 
2530 	/*
2531 	 * XXX: Should we also check for owner != 0?
2532 	 */
2533 }
2534 
2535 static conf_up
conf_new_from_file(const char * path,bool ucl)2536 conf_new_from_file(const char *path, bool ucl)
2537 {
2538 	struct auth_group *ag;
2539 	struct portal_group *pg;
2540 	bool valid;
2541 
2542 	log_debugx("obtaining configuration from %s", path);
2543 
2544 	conf_up conf = std::make_unique<struct conf>();
2545 
2546 	ag = conf->add_auth_group("default");
2547 	assert(ag != NULL);
2548 
2549 	ag = conf->add_auth_group("no-authentication");
2550 	assert(ag != NULL);
2551 	ag->set_type(auth_type::NO_AUTHENTICATION);
2552 
2553 	ag = conf->add_auth_group("no-access");
2554 	assert(ag != NULL);
2555 	ag->set_type(auth_type::DENY);
2556 
2557 	pg = conf->add_portal_group("default");
2558 	assert(pg != NULL);
2559 
2560 	pg = conf->add_transport_group("default");
2561 	assert(pg != NULL);
2562 
2563 	conf_start(conf.get());
2564 	if (ucl)
2565 		valid = uclparse_conf(path);
2566 	else
2567 		valid = parse_conf(path);
2568 	conf_finish();
2569 
2570 	if (!valid) {
2571 		conf.reset();
2572 		return {};
2573 	}
2574 
2575 	check_perms(path);
2576 
2577 	if (!conf->default_auth_group_defined()) {
2578 		log_debugx("auth-group \"default\" not defined; "
2579 		    "going with defaults");
2580 		ag = conf->find_auth_group("default").get();
2581 		assert(ag != NULL);
2582 		ag->set_type(auth_type::DENY);
2583 	}
2584 
2585 	if (!conf->default_portal_group_defined()) {
2586 		log_debugx("portal-group \"default\" not defined; "
2587 		    "going with defaults");
2588 		pg = conf->find_portal_group("default");
2589 		assert(pg != NULL);
2590 		pg->add_default_portals();
2591 	}
2592 
2593 	if (!conf->default_portal_group_defined()) {
2594 		log_debugx("transport-group \"default\" not defined; "
2595 		    "going with defaults");
2596 		pg = conf->find_transport_group("default");
2597 		assert(pg != NULL);
2598 		pg->add_default_portals();
2599 	}
2600 
2601 	if (!conf->verify()) {
2602 		conf.reset();
2603 		return {};
2604 	}
2605 
2606 	return (conf);
2607 }
2608 
2609 /*
2610  * If the config file specifies physical ports for any target, associate them
2611  * with the config file.  If necessary, create them.
2612  */
2613 bool
add_pports(struct kports & kports)2614 conf::add_pports(struct kports &kports)
2615 {
2616 	struct pport *pp;
2617 	int ret, i_pp, i_vp;
2618 
2619 	for (auto &kv : conf_targets) {
2620 		struct target *targ = kv.second.get();
2621 
2622 		if (!targ->has_pport())
2623 			continue;
2624 
2625 		ret = sscanf(targ->pport(), "ioctl/%d/%d", &i_pp, &i_vp);
2626 		if (ret > 0) {
2627 			if (!add_port(kports, targ, i_pp, i_vp)) {
2628 				log_warnx("can't create new ioctl port "
2629 				    "for %s", targ->label());
2630 				return (false);
2631 			}
2632 
2633 			continue;
2634 		}
2635 
2636 		pp = kports.find_port(targ->pport());
2637 		if (pp == NULL) {
2638 			log_warnx("unknown port \"%s\" for %s",
2639 			    targ->pport(), targ->label());
2640 			return (false);
2641 		}
2642 		if (pp->linked()) {
2643 			log_warnx("can't link port \"%s\" to %s, "
2644 			    "port already linked to some target",
2645 			    targ->pport(), targ->label());
2646 			return (false);
2647 		}
2648 		if (!add_port(targ, pp)) {
2649 			log_warnx("can't link port \"%s\" to %s",
2650 			    targ->pport(), targ->label());
2651 			return (false);
2652 		}
2653 	}
2654 	return (true);
2655 }
2656 
2657 int
main(int argc,char ** argv)2658 main(int argc, char **argv)
2659 {
2660 	struct kports kports;
2661 	const char *config_path = DEFAULT_CONFIG_PATH;
2662 	int debug = 0, ch, error;
2663 	bool daemonize = true;
2664 	bool test_config = false;
2665 	bool use_ucl = false;
2666 
2667 	while ((ch = getopt(argc, argv, "dtuf:R")) != -1) {
2668 		switch (ch) {
2669 		case 'd':
2670 			daemonize = false;
2671 			debug++;
2672 			break;
2673 		case 't':
2674 			test_config = true;
2675 			break;
2676 		case 'u':
2677 			use_ucl = true;
2678 			break;
2679 		case 'f':
2680 			config_path = optarg;
2681 			break;
2682 		case 'R':
2683 #ifndef ICL_KERNEL_PROXY
2684 			log_errx(1, "ctld(8) compiled without ICL_KERNEL_PROXY "
2685 			    "does not support iSER protocol");
2686 #endif
2687 			proxy_mode = true;
2688 			break;
2689 		case '?':
2690 		default:
2691 			usage();
2692 		}
2693 	}
2694 	argc -= optind;
2695 	if (argc != 0)
2696 		usage();
2697 
2698 	log_init(debug);
2699 	kernel_init();
2700 
2701 	conf_up newconf = conf_new_from_file(config_path, use_ucl);
2702 
2703 	if (newconf == NULL)
2704 		log_errx(1, "configuration error; exiting");
2705 
2706 	if (test_config)
2707 		return (0);
2708 
2709 	newconf->open_pidfile();
2710 
2711 	register_signals();
2712 
2713 	conf_up oldconf = conf_new_from_kernel(kports);
2714 
2715 	if (debug > 0) {
2716 		oldconf->set_debug(debug);
2717 		newconf->set_debug(debug);
2718 	}
2719 
2720 	if (!newconf->add_pports(kports))
2721 		log_errx(1, "Error associating physical ports; exiting");
2722 
2723 	if (daemonize) {
2724 		log_debugx("daemonizing");
2725 		if (daemon(0, 0) == -1) {
2726 			log_warn("cannot daemonize");
2727 			return (1);
2728 		}
2729 	}
2730 
2731 	kqfd = kqueue();
2732 	if (kqfd == -1) {
2733 		log_warn("Cannot create kqueue");
2734 		return (1);
2735 	}
2736 
2737 	error = newconf->apply(oldconf.get());
2738 	if (error != 0)
2739 		log_errx(1, "failed to apply configuration; exiting");
2740 
2741 	oldconf.reset();
2742 
2743 	newconf->write_pidfile();
2744 
2745 	newconf->isns_schedule_update();
2746 
2747 	for (;;) {
2748 		main_loop(!daemonize);
2749 		if (sighup_received) {
2750 			sighup_received = false;
2751 			log_debugx("received SIGHUP, reloading configuration");
2752 			conf_up tmpconf = conf_new_from_file(config_path,
2753 			    use_ucl);
2754 
2755 			if (tmpconf == NULL) {
2756 				log_warnx("configuration error, "
2757 				    "continuing with old configuration");
2758 			} else if (!tmpconf->add_pports(kports)) {
2759 				log_warnx("Error associating physical ports, "
2760 				    "continuing with old configuration");
2761 			} else {
2762 				if (debug > 0)
2763 					tmpconf->set_debug(debug);
2764 				oldconf = std::move(newconf);
2765 				newconf = std::move(tmpconf);
2766 
2767 				error = newconf->apply(oldconf.get());
2768 				if (error != 0)
2769 					log_warnx("failed to reload "
2770 					    "configuration");
2771 				oldconf.reset();
2772 			}
2773 		} else if (sigterm_received) {
2774 			log_debugx("exiting on signal; "
2775 			    "reloading empty configuration");
2776 
2777 			log_debugx("removing CTL iSCSI ports "
2778 			    "and terminating all connections");
2779 
2780 			oldconf = std::move(newconf);
2781 			newconf = std::make_unique<conf>();
2782 			if (debug > 0)
2783 				newconf->set_debug(debug);
2784 			error = newconf->apply(oldconf.get());
2785 			if (error != 0)
2786 				log_warnx("failed to apply configuration");
2787 			oldconf.reset();
2788 
2789 			log_warnx("exiting on signal");
2790 			return (0);
2791 		} else {
2792 			nchildren -= wait_for_children(false);
2793 			assert(nchildren >= 0);
2794 			if (timed_out()) {
2795 				newconf->isns_update();
2796 			}
2797 		}
2798 	}
2799 	/* NOTREACHED */
2800 }
2801