xref: /freebsd-src/usr.sbin/syslogd/syslogd_cap_config.c (revision ae4f708f0b383277505daa191e21db399b558839)
12567168dSJake Freeland /*-
22567168dSJake Freeland  * SPDX-License-Identifier: BSD-2-Clause
32567168dSJake Freeland  *
42567168dSJake Freeland  * Copyright (c) 2023 The FreeBSD Foundation
52567168dSJake Freeland  *
62567168dSJake Freeland  * This software was developed by Jake Freeland <jfree@FreeBSD.org>
72567168dSJake Freeland  * under sponsorship from the FreeBSD Foundation.
82567168dSJake Freeland  *
92567168dSJake Freeland  * Redistribution and use in source and binary forms, with or without
102567168dSJake Freeland  * modification, are permitted provided that the following conditions
112567168dSJake Freeland  * are met:
122567168dSJake Freeland  * 1. Redistributions of source code must retain the above copyright
132567168dSJake Freeland  *    notice, this list of conditions and the following disclaimer.
142567168dSJake Freeland  * 2. Redistributions in binary form must reproduce the above copyright
152567168dSJake Freeland  *    notice, this list of conditions and the following disclaimer in the
162567168dSJake Freeland  *    documentation and/or other materials provided with the distribution.
172567168dSJake Freeland  *
182567168dSJake Freeland  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
192567168dSJake Freeland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
202567168dSJake Freeland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
212567168dSJake Freeland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
222567168dSJake Freeland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
232567168dSJake Freeland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
242567168dSJake Freeland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
252567168dSJake Freeland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
262567168dSJake Freeland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
272567168dSJake Freeland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
282567168dSJake Freeland  * SUCH DAMAGE.
292567168dSJake Freeland  */
302567168dSJake Freeland 
312567168dSJake Freeland #include <sys/types.h>
322567168dSJake Freeland #include <sys/socket.h>
332567168dSJake Freeland 
342567168dSJake Freeland #include <assert.h>
352567168dSJake Freeland #include <err.h>
362567168dSJake Freeland #include <libcasper.h>
372567168dSJake Freeland #include <netdb.h>
382567168dSJake Freeland #include <string.h>
392567168dSJake Freeland 
402567168dSJake Freeland #include <casper/cap_net.h>
412567168dSJake Freeland 
422567168dSJake Freeland #include "syslogd_cap.h"
432567168dSJake Freeland 
442567168dSJake Freeland /*
452567168dSJake Freeland  * Convert the given prop_filter structure into an nvlist.
462567168dSJake Freeland  * Return a heap allocated pointer to the resulting nvlist.
472567168dSJake Freeland  */
482567168dSJake Freeland nvlist_t *
492567168dSJake Freeland prop_filter_to_nvlist(const struct prop_filter *pfilter)
502567168dSJake Freeland {
512567168dSJake Freeland 	nvlist_t *nvl_prop_filter = nvlist_create(0);
522567168dSJake Freeland 
532567168dSJake Freeland 	nvlist_add_number(nvl_prop_filter, "prop_type", pfilter->prop_type);
542567168dSJake Freeland 	nvlist_add_number(nvl_prop_filter, "cmp_type", pfilter->cmp_type);
552567168dSJake Freeland 	nvlist_add_number(nvl_prop_filter, "cmp_flags", pfilter->cmp_flags);
562567168dSJake Freeland 	nvlist_add_string(nvl_prop_filter, "pflt_strval", pfilter->pflt_strval);
572567168dSJake Freeland 	/*
582567168dSJake Freeland 	 * Do not bother adding pflt_re. It will be recompiled
592567168dSJake Freeland 	 * using pflt_strval later, if applicable.
602567168dSJake Freeland 	 */
612567168dSJake Freeland 
622567168dSJake Freeland 	return (nvl_prop_filter);
632567168dSJake Freeland }
642567168dSJake Freeland 
652567168dSJake Freeland /*
662567168dSJake Freeland  * Convert the given nvlist into a prop_filter structure.
672567168dSJake Freeland  * Return a heap allocated pointer to the resulting prop_filter.
682567168dSJake Freeland  */
692567168dSJake Freeland struct prop_filter *
702567168dSJake Freeland nvlist_to_prop_filter(const nvlist_t *nvl_prop_filter)
712567168dSJake Freeland {
722567168dSJake Freeland 	struct prop_filter *pfilter;
732567168dSJake Freeland 
742567168dSJake Freeland 	pfilter = calloc(1, sizeof(*pfilter));
752567168dSJake Freeland 	if (pfilter == NULL)
762567168dSJake Freeland 		err(1, "calloc");
772567168dSJake Freeland 	pfilter->prop_type = nvlist_get_number(nvl_prop_filter, "prop_type");
782567168dSJake Freeland 	pfilter->cmp_type = nvlist_get_number(nvl_prop_filter, "cmp_type");
792567168dSJake Freeland 	pfilter->cmp_flags = nvlist_get_number(nvl_prop_filter, "cmp_flags");
802567168dSJake Freeland 	pfilter->pflt_strval = strdup(nvlist_get_string(nvl_prop_filter,
812567168dSJake Freeland 	    "pflt_strval"));
822567168dSJake Freeland 	if (pfilter->cmp_type == FILT_CMP_REGEX) {
832567168dSJake Freeland 		int re_flags = REG_NOSUB;
842567168dSJake Freeland 		pfilter->pflt_re = calloc(1, sizeof(*pfilter->pflt_re));
852567168dSJake Freeland 		if (pfilter->pflt_re == NULL)
862567168dSJake Freeland 			errx(1, "RE calloc() error");
872567168dSJake Freeland 		if ((pfilter->cmp_flags & FILT_FLAG_EXTENDED) != 0)
882567168dSJake Freeland 			re_flags |= REG_EXTENDED;
892567168dSJake Freeland 		if ((pfilter->cmp_flags & FILT_FLAG_ICASE) != 0)
902567168dSJake Freeland 			re_flags |= REG_ICASE;
912567168dSJake Freeland 		if (regcomp(pfilter->pflt_re, pfilter->pflt_strval,
922567168dSJake Freeland 		    re_flags) != 0)
932567168dSJake Freeland 			errx(1, "RE compilation error");
942567168dSJake Freeland 	}
952567168dSJake Freeland 
962567168dSJake Freeland 	return (pfilter);
972567168dSJake Freeland }
982567168dSJake Freeland 
992567168dSJake Freeland /*
1002567168dSJake Freeland  * Convert the given struct filed into an nvl_filed nvlist.
1012567168dSJake Freeland  * Return a heap allocated pointer to the resulting nvlist.
1022567168dSJake Freeland  */
1032567168dSJake Freeland nvlist_t *
1042567168dSJake Freeland filed_to_nvlist(const struct filed *filed)
1052567168dSJake Freeland {
1062567168dSJake Freeland 	nvlist_t *nvl_filed = nvlist_create(0);
1072567168dSJake Freeland 	enum f_type f_type = filed->f_type;
1082567168dSJake Freeland 	size_t i, sz;
1092567168dSJake Freeland 
1102567168dSJake Freeland 	nvlist_add_number(nvl_filed, "f_type", f_type);
1112567168dSJake Freeland 	nvlist_add_string(nvl_filed, "f_host", filed->f_host);
1122567168dSJake Freeland 	nvlist_add_string(nvl_filed, "f_program", filed->f_program);
1132567168dSJake Freeland 	if (filed->f_prop_filter != NULL) {
1142567168dSJake Freeland 		nvlist_add_nvlist(nvl_filed, "f_prop_filter",
1152567168dSJake Freeland 		    prop_filter_to_nvlist(filed->f_prop_filter));
1162567168dSJake Freeland 	}
1172567168dSJake Freeland 	sz = nitems(filed->f_pmask);
1182567168dSJake Freeland 	for (i = 0; i < sz; ++i) {
1192567168dSJake Freeland 		nvlist_append_number_array(nvl_filed, "f_pmask",
1202567168dSJake Freeland 		    filed->f_pmask[i]);
1212567168dSJake Freeland 	}
1222567168dSJake Freeland 	sz = nitems(filed->f_pcmp);
1232567168dSJake Freeland 	for (i = 0; i < sz; ++i) {
1242567168dSJake Freeland 		nvlist_append_number_array(nvl_filed, "f_pcmp",
1252567168dSJake Freeland 		    filed->f_pcmp[i]);
1262567168dSJake Freeland 	}
1272567168dSJake Freeland 
1282567168dSJake Freeland 	if (filed->f_file >= 0)
1292567168dSJake Freeland 		nvlist_add_descriptor(nvl_filed, "f_file", filed->f_file);
1302567168dSJake Freeland 	nvlist_add_number(nvl_filed, "f_flags", filed->f_flags);
1312567168dSJake Freeland 	if (f_type == F_WALL || f_type == F_USERS) {
1322567168dSJake Freeland 		sz = nitems(filed->f_uname);
1332567168dSJake Freeland 		for (i = 0; i < sz; ++i) {
1342567168dSJake Freeland 			nvlist_append_string_array(nvl_filed, "f_uname",
1352567168dSJake Freeland 			    filed->f_uname[i]);
1362567168dSJake Freeland 		}
1372567168dSJake Freeland 	} else if (f_type == F_FILE || f_type == F_CONSOLE || f_type == F_TTY) {
1382567168dSJake Freeland 		nvlist_add_string(nvl_filed, "f_fname", filed->f_fname);
1392567168dSJake Freeland 	} else if (f_type == F_FORW) {
1402567168dSJake Freeland 		nvlist_add_string(nvl_filed, "f_hname", filed->f_hname);
1414ecbee27SJake Freeland 		nvlist_add_descriptor_array(nvl_filed, "f_addr_fds",
1424ecbee27SJake Freeland 		    filed->f_addr_fds, filed->f_num_addr_fds);
143*ae4f708fSMark Johnston 		nvlist_add_binary(nvl_filed, "f_addrs", filed->f_addrs,
144*ae4f708fSMark Johnston 		    filed->f_num_addr_fds * sizeof(*filed->f_addrs));
1452567168dSJake Freeland 	} else if (filed->f_type == F_PIPE) {
1462567168dSJake Freeland 		nvlist_add_string(nvl_filed, "f_pname", filed->f_pname);
1472567168dSJake Freeland 		if (filed->f_procdesc >= 0) {
1482567168dSJake Freeland 			nvlist_add_descriptor(nvl_filed, "f_procdesc",
1492567168dSJake Freeland 			    filed->f_procdesc);
1502567168dSJake Freeland 		}
1512567168dSJake Freeland 	}
1522567168dSJake Freeland 
1532567168dSJake Freeland 	/*
1542567168dSJake Freeland 	 * Book-keeping fields are not transferred.
1552567168dSJake Freeland 	 */
1562567168dSJake Freeland 
1572567168dSJake Freeland 	return (nvl_filed);
1582567168dSJake Freeland }
1592567168dSJake Freeland 
1602567168dSJake Freeland /*
1612567168dSJake Freeland  * Convert the given nvl_filed nvlist into a struct filed.
1622567168dSJake Freeland  * Return a heap allocated pointer to the resulting struct
1632567168dSJake Freeland  * filed.
1642567168dSJake Freeland  */
1652567168dSJake Freeland struct filed *
1662567168dSJake Freeland nvlist_to_filed(const nvlist_t *nvl_filed)
1672567168dSJake Freeland {
1682567168dSJake Freeland 	struct filed *filed;
1692567168dSJake Freeland 	enum f_type f_type;
1702567168dSJake Freeland 	const uint64_t *narr;
1712567168dSJake Freeland 	size_t i, sz;
1722567168dSJake Freeland 
1732567168dSJake Freeland 	filed = calloc(1, sizeof(*filed));
1742567168dSJake Freeland 	if (filed == NULL)
1752567168dSJake Freeland 		err(1, "calloc");
1762567168dSJake Freeland 
1772567168dSJake Freeland 	f_type = filed->f_type = nvlist_get_number(nvl_filed, "f_type");
1782567168dSJake Freeland 	(void)strlcpy(filed->f_host, nvlist_get_string(nvl_filed, "f_host"),
1792567168dSJake Freeland 	    sizeof(filed->f_host));
1802567168dSJake Freeland 	(void)strlcpy(filed->f_program, nvlist_get_string(nvl_filed,
1812567168dSJake Freeland 	    "f_program"), sizeof(filed->f_program));
1822567168dSJake Freeland 	if (nvlist_exists_nvlist(nvl_filed, "f_prop_filter")) {
1832567168dSJake Freeland 		filed->f_prop_filter = nvlist_to_prop_filter(
1842567168dSJake Freeland 		    nvlist_get_nvlist(nvl_filed, "f_prop_filter"));
1852567168dSJake Freeland 	}
1862567168dSJake Freeland 	narr = nvlist_get_number_array(nvl_filed, "f_pmask", &sz);
1872567168dSJake Freeland 	assert(sz == nitems(filed->f_pmask));
1882567168dSJake Freeland 	for (i = 0; i < sz; ++i)
1892567168dSJake Freeland 		filed->f_pmask[i] = narr[i];
1902567168dSJake Freeland 	narr = nvlist_get_number_array(nvl_filed, "f_pcmp", &sz);
1912567168dSJake Freeland 	assert(sz == nitems(filed->f_pcmp));
1922567168dSJake Freeland 	for (i = 0; i < sz; ++i)
1932567168dSJake Freeland 		filed->f_pcmp[i] = narr[i];
1942567168dSJake Freeland 
1952567168dSJake Freeland 	if (nvlist_exists_descriptor(nvl_filed, "f_file"))
1962567168dSJake Freeland 		filed->f_file = dup(nvlist_get_descriptor(nvl_filed, "f_file"));
1972567168dSJake Freeland 	else
1982567168dSJake Freeland 		filed->f_file = -1;
1992567168dSJake Freeland 	filed->f_flags = nvlist_get_number(nvl_filed, "f_flags");
2002567168dSJake Freeland 	if (f_type == F_WALL || f_type == F_USERS) {
2012567168dSJake Freeland 		const char * const *f_uname;
2022567168dSJake Freeland 
2032567168dSJake Freeland 		f_uname = nvlist_get_string_array(nvl_filed, "f_uname", &sz);
2042567168dSJake Freeland 		assert(sz == nitems(filed->f_uname));
2052567168dSJake Freeland 		for (i = 0; i < sz; ++i) {
2062567168dSJake Freeland 			(void)strlcpy(filed->f_uname[i], f_uname[i],
2072567168dSJake Freeland 			    sizeof(filed->f_uname[i]));
2082567168dSJake Freeland 		}
2092567168dSJake Freeland 	} else if (f_type == F_FILE || f_type == F_CONSOLE || f_type == F_TTY) {
2102567168dSJake Freeland 		(void)strlcpy(filed->f_fname, nvlist_get_string(nvl_filed,
2112567168dSJake Freeland 		    "f_fname"), sizeof(filed->f_fname));
2122567168dSJake Freeland 	} else if (f_type == F_FORW) {
2134ecbee27SJake Freeland 		const int *f_addr_fds;
2142567168dSJake Freeland 
2152567168dSJake Freeland 		(void)strlcpy(filed->f_hname, nvlist_get_string(nvl_filed,
2162567168dSJake Freeland 		    "f_hname"), sizeof(filed->f_hname));
2174ecbee27SJake Freeland 
2184ecbee27SJake Freeland 		f_addr_fds = nvlist_get_descriptor_array(nvl_filed,
2194ecbee27SJake Freeland 		    "f_addr_fds", &filed->f_num_addr_fds);
2204ecbee27SJake Freeland 		filed->f_addr_fds = calloc(filed->f_num_addr_fds,
2214ecbee27SJake Freeland 		    sizeof(*f_addr_fds));
2224ecbee27SJake Freeland 		if (filed->f_addr_fds == NULL)
2234ecbee27SJake Freeland 			err(1, "calloc");
2244ecbee27SJake Freeland 		for (i = 0; i < filed->f_num_addr_fds; ++i) {
2254ecbee27SJake Freeland 			filed->f_addr_fds[i] = dup(f_addr_fds[i]);
2264ecbee27SJake Freeland 			if (filed->f_addr_fds[i] < 0)
2274ecbee27SJake Freeland 				err(1, "dup");
2282567168dSJake Freeland 		}
2292567168dSJake Freeland 	} else if (filed->f_type == F_PIPE) {
2302567168dSJake Freeland 		(void)strlcpy(filed->f_pname, nvlist_get_string(nvl_filed,
2312567168dSJake Freeland 		    "f_pname"), sizeof(filed->f_pname));
2322567168dSJake Freeland 		if (nvlist_exists_descriptor(nvl_filed, "f_procdesc")) {
2332567168dSJake Freeland 			filed->f_procdesc = dup(nvlist_get_descriptor(nvl_filed,
2342567168dSJake Freeland 			    "f_procdesc"));
2352567168dSJake Freeland 		} else {
2362567168dSJake Freeland 			filed->f_procdesc = -1;
2372567168dSJake Freeland 		}
2382567168dSJake Freeland 	}
2392567168dSJake Freeland 
2402567168dSJake Freeland 	/*
2412567168dSJake Freeland 	 * Book-keeping fields are not transferred.
2422567168dSJake Freeland 	 */
2432567168dSJake Freeland 
2442567168dSJake Freeland 	return (filed);
2452567168dSJake Freeland }
2462567168dSJake Freeland 
2472567168dSJake Freeland nvlist_t *
2482567168dSJake Freeland cap_readconfigfile(cap_channel_t *chan, const char *path)
2492567168dSJake Freeland {
2502567168dSJake Freeland 	nvlist_t *nvl, *nvl_conf;
2512567168dSJake Freeland 
2522567168dSJake Freeland 	nvl = nvlist_create(0);
2532567168dSJake Freeland 	nvlist_add_string(nvl, "cmd", "readconfigfile");
2542567168dSJake Freeland 	nvlist_add_string(nvl, "path", path);
2552567168dSJake Freeland 	/* It is possible that our hostname has changed. */
2562567168dSJake Freeland 	nvlist_add_string(nvl, "LocalHostName", LocalHostName);
2572567168dSJake Freeland 	nvl = cap_xfer_nvlist(chan, nvl);
2582567168dSJake Freeland 	if (nvl == NULL) {
2592567168dSJake Freeland 		logerror("Failed to xfer configuration nvlist");
2602567168dSJake Freeland 		exit(1);
2612567168dSJake Freeland 	}
2622567168dSJake Freeland 	nvl_conf = nvlist_take_nvlist(nvl, "nvl_conf");
2632567168dSJake Freeland 
2642567168dSJake Freeland 	nvlist_destroy(nvl);
2652567168dSJake Freeland 	return (nvl_conf);
2662567168dSJake Freeland }
2672567168dSJake Freeland 
2682567168dSJake Freeland /*
2692567168dSJake Freeland  * Now that we're executing as libcasper, we can obtain the
2702567168dSJake Freeland  * resources specified in the configuration.
2712567168dSJake Freeland  */
2722567168dSJake Freeland int
2732567168dSJake Freeland casper_readconfigfile(nvlist_t *nvlin, nvlist_t *nvlout)
2742567168dSJake Freeland {
27561a29ecaSJake Freeland 	const nvlist_t * const *filed_list;
27661a29ecaSJake Freeland 	nvlist_t *nvl_conf;
27761a29ecaSJake Freeland 	size_t n_fileds;
2782567168dSJake Freeland 	const char *path;
2792567168dSJake Freeland 
2802567168dSJake Freeland 	/*
2812567168dSJake Freeland 	 * Verify that syslogd did not manipulate the
2822567168dSJake Freeland 	 * configuration file path.
2832567168dSJake Freeland 	 */
2842567168dSJake Freeland 	path = nvlist_get_string(nvlin, "path");
2852567168dSJake Freeland 	if (strcmp(path, ConfFile) != 0)
2862567168dSJake Freeland 		err(1, "Configuration file mismatch: %s != %s", path, ConfFile);
2872567168dSJake Freeland 
2882567168dSJake Freeland 	/* Refresh our copy of LocalHostName, in case it changed. */
2892567168dSJake Freeland 	strlcpy(LocalHostName, nvlist_get_string(nvlin, "LocalHostName"),
2902567168dSJake Freeland 	    sizeof(LocalHostName));
2912567168dSJake Freeland 
29261a29ecaSJake Freeland 	nvl_conf = readconfigfile(path);
29361a29ecaSJake Freeland 
29461a29ecaSJake Freeland 	/* Remove old filed data in case we are reloading. */
29561a29ecaSJake Freeland 	while (!SLIST_EMPTY(&cfiled_head)) {
29661a29ecaSJake Freeland 		struct cap_filed *cfiled;
29761a29ecaSJake Freeland 
29861a29ecaSJake Freeland 		cfiled = SLIST_FIRST(&cfiled_head);
29961a29ecaSJake Freeland 		SLIST_REMOVE_HEAD(&cfiled_head, next);
30061a29ecaSJake Freeland 		free(cfiled);
30161a29ecaSJake Freeland 	}
30261a29ecaSJake Freeland 	/* Record F_PIPE filed data for use in p_open(). */
30361a29ecaSJake Freeland 	if (!nvlist_exists_nvlist_array(nvl_conf, "filed_list"))
30461a29ecaSJake Freeland 		return (0);
30561a29ecaSJake Freeland 	filed_list = nvlist_get_nvlist_array(nvl_conf, "filed_list", &n_fileds);
30661a29ecaSJake Freeland 	for (size_t i = 0; i < n_fileds; ++i) {
30761a29ecaSJake Freeland 		if (nvlist_get_number(filed_list[i], "f_type") == F_PIPE) {
30861a29ecaSJake Freeland 			struct cap_filed *cfiled;
30961a29ecaSJake Freeland 			const char *pipe_cmd;
31061a29ecaSJake Freeland 
31161a29ecaSJake Freeland 			cfiled = malloc(sizeof(*cfiled));
31261a29ecaSJake Freeland 			if (cfiled == NULL)
31361a29ecaSJake Freeland 				err(1, "malloc");
31461a29ecaSJake Freeland 			cfiled->idx = i;
31561a29ecaSJake Freeland 			pipe_cmd = nvlist_get_string(filed_list[i], "f_pname");
31661a29ecaSJake Freeland 			strlcpy(cfiled->pipe_cmd, pipe_cmd, sizeof(cfiled->pipe_cmd));
31761a29ecaSJake Freeland 			SLIST_INSERT_HEAD(&cfiled_head, cfiled, next);
31861a29ecaSJake Freeland 		}
31961a29ecaSJake Freeland 	}
32061a29ecaSJake Freeland 
32161a29ecaSJake Freeland 	nvlist_move_nvlist(nvlout, "nvl_conf", nvl_conf);
3222567168dSJake Freeland 	return (0);
3232567168dSJake Freeland }
324