diff --git a/usr.sbin/syslogd/Makefile b/usr.sbin/syslogd/Makefile --- a/usr.sbin/syslogd/Makefile +++ b/usr.sbin/syslogd/Makefile @@ -14,7 +14,8 @@ LIBADD= util .if ${MK_CASPER} != "no" -SRCS+= syslogd_cap.c +SRCS+= syslogd_cap.c \ + syslogd_cap_config.c CFLAGS+= -DWITH_CASPER LIBADD+= cap_net casper nv .endif diff --git a/usr.sbin/syslogd/syslogd.h b/usr.sbin/syslogd/syslogd.h --- a/usr.sbin/syslogd/syslogd.h +++ b/usr.sbin/syslogd/syslogd.h @@ -64,6 +64,7 @@ #define _SYSLOGD_H_ #include +#include #include #include @@ -71,6 +72,8 @@ #include #include +#include +#include #define MAXLINE 8192 /* maximum line length */ #define MAXSVLINE MAXLINE /* maximum saved line length */ @@ -107,7 +110,6 @@ #define FILT_FLAG_EXTENDED (1 << 1) #define FILT_FLAG_ICASE (1 << 2) char *pflt_strval; - size_t pflt_strlen; regex_t *pflt_re; }; @@ -132,8 +134,8 @@ enum f_type f_type; /* Used for filtering. */ - char *f_host; /* host from which to recd. */ - char *f_program; /* program this applies to */ + char f_host[MAXHOSTNAMELEN]; /* host from which to recd. */ + char f_program[MAXPATHLEN]; /* program this applies to */ struct prop_filter *f_prop_filter; /* property-based filter */ u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ u_char f_pcmp[LOG_NFACILITIES+1]; /* compare priority */ @@ -170,4 +172,11 @@ STAILQ_ENTRY(filed) next; /* next in linked list */ }; +extern const char *ConfFile; +extern char LocalHostName[MAXHOSTNAMELEN]; + +void closelogfiles(void); +void logerror(const char *); +nvlist_t *readconfigfile(const char *); + #endif /* !_SYSLOGD_H_ */ diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c --- a/usr.sbin/syslogd/syslogd.c +++ b/usr.sbin/syslogd/syslogd.c @@ -131,7 +131,7 @@ #include "syslogd_cap.h" #include "ttymsg.h" -static const char *ConfFile = _PATH_LOGCONF; +const char *ConfFile = _PATH_LOGCONF; static const char *PidFile = _PATH_LOGPID; static const char include_str[] = "include"; static const char include_ext[] = ".conf"; @@ -276,7 +276,7 @@ static bool Debug; /* debug flag */ static bool Foreground = false; /* Run in foreground, instead of daemonizing */ static bool resolve = true; /* resolve hostname */ -static char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */ +char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */ static const char *LocalDomain; /* our local domain name */ static bool Initialized; /* set when we have initialized ourselves */ static int MarkInterval = 20 * 60; /* interval between marks in seconds */ @@ -313,7 +313,7 @@ static bool allowaddr(char *); static void addpeer(const char *, const char *, mode_t); static void addsock(const char *, const char *, mode_t); -static void cfline(const char *, const char *, const char *, const char *); +static nvlist_t *cfline(const char *, const char *, const char *, const char *); static const char *cvthname(struct sockaddr *); static void deadq_enter(int); static void deadq_remove(struct deadq_entry *); @@ -325,7 +325,6 @@ static void fprintlog_write(struct filed *, struct iovlist *, int); static void fprintlog_successive(struct filed *, int); static void init(bool); -static void logerror(const char *); static void logmsg(int, const struct logtime *, const char *, const char *, const char *, const char *, const char *, const char *, int); static void markit(void); @@ -335,7 +334,7 @@ static int skip_message(const char *, const char *, int); static int evaluate_prop_filter(const struct prop_filter *filter, const char *value); -static struct prop_filter *prop_filter_compile(const char *); +static nvlist_t *prop_filter_compile(const char *); static void parsemsg(const char *, char *); static void printsys(char *); static int p_open(const char *, pid_t *); @@ -1387,7 +1386,7 @@ int exclude = 0; /* Behaviour on explicit match */ - if (spec == NULL) + if (spec == NULL || *spec == '\0') return (0); switch (*spec) { case '-': @@ -1445,7 +1444,7 @@ /* a shortcut for equal with different length is always false */ if (filter->cmp_type == FILT_CMP_EQUAL && - valuelen != filter->pflt_strlen) + valuelen != strlen(filter->pflt_strval)) return (!exclude); if (filter->cmp_flags & FILT_FLAG_ICASE) @@ -2178,7 +2177,7 @@ /* * Print syslogd errors some place. */ -static void +void logerror(const char *msg) { char buf[512]; @@ -2255,8 +2254,8 @@ return (1); } -static void -parseconfigfile(FILE *cf, bool allow_includes) +static nvlist_t * +parseconfigfile(FILE *cf, bool allow_includes, nvlist_t *nvl_conf) { FILE *cf2; struct dirent **ent; @@ -2316,7 +2315,7 @@ if (cf2 == NULL) continue; dprintf("reading %s\n", file); - parseconfigfile(cf2, false); + parseconfigfile(cf2, false, nvl_conf); fclose(cf2); } free(ent); @@ -2386,29 +2385,55 @@ } for (i = strlen(cline) - 1; i >= 0 && isspace(cline[i]); i--) cline[i] = '\0'; - cfline(cline, prog, host, pfilter); + nvlist_append_nvlist_array(nvl_conf, "filed_list", + cfline(cline, prog, host, pfilter)); + } + return (nvl_conf); } -static void +nvlist_t * readconfigfile(const char *path) { FILE *cf; + nvlist_t *nvl_conf = nvlist_create(0); if ((cf = fopen(path, "r")) != NULL) { - parseconfigfile(cf, true); + nvl_conf = parseconfigfile(cf, true, nvl_conf); (void)fclose(cf); } else { - dprintf("cannot open %s\n", ConfFile); - cfline("*.ERR\t/dev/console", "*", "*", "*"); - cfline("*.PANIC\t*", "*", "*", "*"); + dprintf("cannot open %s\n", path); + nvlist_append_nvlist_array(nvl_conf, "filed_list", + cfline("*.ERR\t/dev/console", "*", "*", "*")); + nvlist_append_nvlist_array(nvl_conf, "filed_list", + cfline("*.PANIC\t*", "*", "*", "*")); + } + return (nvl_conf); +} + +static void +fill_flist(nvlist_t *nvl_conf) +{ + const nvlist_t * const *filed_list; + size_t nfileds; + + if (!nvlist_exists_nvlist_array(nvl_conf, "filed_list")) + return; + filed_list = nvlist_get_nvlist_array(nvl_conf, "filed_list", + &nfileds); + for (size_t i = 0; i < nfileds; ++i) { + struct filed *f; + + f = nvlist_to_filed(filed_list[i]); + STAILQ_INSERT_TAIL(&fhead, f, next); } + nvlist_destroy(nvl_conf); } /* * Close all open log files. */ -static void +void closelogfiles(void) { struct filed *f; @@ -2433,14 +2458,12 @@ break; } - free(f->f_program); - free(f->f_host); if (f->f_prop_filter) { switch (f->f_prop_filter->cmp_type) { case FILT_CMP_REGEX: regfree(f->f_prop_filter->pflt_re); free(f->f_prop_filter->pflt_re); - break; + /* FALLTHROUGH */ case FILT_CMP_CONTAINS: case FILT_CMP_EQUAL: case FILT_CMP_STARTS: @@ -2504,7 +2527,7 @@ Initialized = false; closelogfiles(); - readconfigfile(ConfFile); + fill_flist(readconfigfile(ConfFile)); Initialized = true; if (Debug) { @@ -2561,7 +2584,7 @@ default: break; } - if (f->f_program) + if (*f->f_program != '\0') printf(" (%s)", f->f_program); printf("\n"); } @@ -2597,29 +2620,18 @@ /* * Compile property-based filter. */ -static struct prop_filter * +static nvlist_t * prop_filter_compile(const char *cfilter) { - struct prop_filter *pfilter; + nvlist_t *nvl_pfilter; + struct prop_filter pfilter = { }; char *filter, *filter_endpos, *filter_begpos, *p; char **ap, *argv[2] = {NULL, NULL}; - int re_flags = REG_NOSUB; int escaped; - pfilter = calloc(1, sizeof(*pfilter)); - if (pfilter == NULL) { - logerror("pfilter calloc"); - exit(1); - } - if (*cfilter == '*') { - pfilter->prop_type = FILT_PROP_NOOP; - return (pfilter); - } filter = strdup(cfilter); - if (filter == NULL) { - logerror("strdup"); - exit(1); - } + if (filter == NULL) + err(1, "strdup"); filter_begpos = filter; /* @@ -2640,48 +2652,48 @@ } if (argv[0] == NULL || argv[1] == NULL) { - logerror("filter parse error"); + dprintf("filter parse error"); goto error; } /* fill in prop_type */ if (strcasecmp(argv[0], "msg") == 0) - pfilter->prop_type = FILT_PROP_MSG; + pfilter.prop_type = FILT_PROP_MSG; else if (strcasecmp(argv[0], "hostname") == 0) - pfilter->prop_type = FILT_PROP_HOSTNAME; + pfilter.prop_type = FILT_PROP_HOSTNAME; else if (strcasecmp(argv[0], "source") == 0) - pfilter->prop_type = FILT_PROP_HOSTNAME; + pfilter.prop_type = FILT_PROP_HOSTNAME; else if (strcasecmp(argv[0], "programname") == 0) - pfilter->prop_type = FILT_PROP_PROGNAME; + pfilter.prop_type = FILT_PROP_PROGNAME; else { - logerror("unknown property"); + dprintf("unknown property"); goto error; } /* full in cmp_flags (i.e. !contains, icase_regex, etc.) */ if (*argv[1] == '!') { - pfilter->cmp_flags |= FILT_FLAG_EXCLUDE; + pfilter.cmp_flags |= FILT_FLAG_EXCLUDE; argv[1]++; } if (strncasecmp(argv[1], "icase_", (sizeof("icase_") - 1)) == 0) { - pfilter->cmp_flags |= FILT_FLAG_ICASE; + pfilter.cmp_flags |= FILT_FLAG_ICASE; argv[1] += sizeof("icase_") - 1; } /* fill in cmp_type */ if (strcasecmp(argv[1], "contains") == 0) - pfilter->cmp_type = FILT_CMP_CONTAINS; + pfilter.cmp_type = FILT_CMP_CONTAINS; else if (strcasecmp(argv[1], "isequal") == 0) - pfilter->cmp_type = FILT_CMP_EQUAL; + pfilter.cmp_type = FILT_CMP_EQUAL; else if (strcasecmp(argv[1], "startswith") == 0) - pfilter->cmp_type = FILT_CMP_STARTS; + pfilter.cmp_type = FILT_CMP_STARTS; else if (strcasecmp(argv[1], "regex") == 0) - pfilter->cmp_type = FILT_CMP_REGEX; + pfilter.cmp_type = FILT_CMP_REGEX; else if (strcasecmp(argv[1], "ereregex") == 0) { - pfilter->cmp_type = FILT_CMP_REGEX; - re_flags |= REG_EXTENDED; + pfilter.cmp_type = FILT_CMP_REGEX; + pfilter.cmp_flags |= REG_EXTENDED; } else { - logerror("unknown cmp function"); + dprintf("unknown cmp function"); goto error; } @@ -2693,7 +2705,7 @@ /* remove leading whitespace and check for '"' next character */ filter += strspn(filter, ", \t\n"); if (*filter != '"' || strlen(filter) < 3) { - logerror("property value parse error"); + dprintf("property value parse error"); goto error; } filter++; @@ -2725,33 +2737,18 @@ /* We should not have anything but whitespace left after closing '"' */ if (*p != '\0' && strspn(p, " \t\n") != strlen(p)) { - logerror("property value parse error"); + dprintf("property value parse error"); goto error; } - if (pfilter->cmp_type == FILT_CMP_REGEX) { - pfilter->pflt_re = calloc(1, sizeof(*pfilter->pflt_re)); - if (pfilter->pflt_re == NULL) { - logerror("RE calloc() error"); - goto error; - } - if (pfilter->cmp_flags & FILT_FLAG_ICASE) - re_flags |= REG_ICASE; - if (regcomp(pfilter->pflt_re, filter, re_flags) != 0) { - logerror("RE compilation error"); - goto error; - } - } else { - pfilter->pflt_strval = strdup(filter); - pfilter->pflt_strlen = strlen(filter); - } + pfilter.pflt_strval = filter; + /* An nvlist is heap allocated heap here. */ + nvl_pfilter = prop_filter_to_nvlist(&pfilter); free(filter_begpos); - return (pfilter); + return (nvl_pfilter); error: free(filter_begpos); - free(pfilter->pflt_re); - free(pfilter); return (NULL); } @@ -2760,7 +2757,7 @@ { int i, pri; int pri_done = 0, pri_cmp = 0, pri_invert = 0; - char *bp, buf[LINE_MAX], ebuf[100]; + char *bp, buf[LINE_MAX]; const char *q; /* find the end of this facility name list */ @@ -2812,10 +2809,7 @@ pri = decode(buf, prioritynames); if (pri < 0) { - errno = 0; - (void)snprintf(ebuf, sizeof(ebuf), - "unknown priority name \"%s\"", buf); - logerror(ebuf); + dprintf("unknown priority name \"%s\"", buf); free(f); return (NULL); } @@ -2839,11 +2833,7 @@ } else { i = decode(buf, facilitynames); if (i < 0) { - errno = 0; - (void)snprintf(ebuf, sizeof(ebuf), - "unknown facility name \"%s\"", - buf); - logerror(ebuf); + dprintf("unknown facility name \"%s\"", buf); free(f); return (NULL); } @@ -2870,6 +2860,7 @@ } else syncfile = true; + f->f_file = -1; switch (*p) { case '@': { @@ -2910,7 +2901,7 @@ }; error = getaddrinfo(f->f_hname, p ? p : "syslog", &hints, &res); if (error) { - logerror(gai_strerror(error)); + dprintf("%s\n", gai_strerror(error)); break; } f->f_addr = res; @@ -2920,7 +2911,7 @@ case '/': if ((f->f_file = open(p, logflags, 0600)) < 0) { f->f_type = F_UNUSED; - logerror(p); + dprintf("%s\n", p); break; } if (syncfile) @@ -2969,74 +2960,59 @@ /* * Crack a configuration file line */ -static void +static nvlist_t * cfline(const char *line, const char *prog, const char *host, const char *pfilter) { - struct filed *f; + nvlist_t *nvl_filed; + struct filed f = { }; const char *p; dprintf("cfline(\"%s\", f, \"%s\", \"%s\", \"%s\")\n", line, prog, host, pfilter); - f = calloc(1, sizeof(*f)); - if (f == NULL) { - logerror("malloc"); - exit(1); - } - errno = 0; /* keep strerror() stuff out of logerror messages */ - for (int i = 0; i <= LOG_NFACILITIES; i++) - f->f_pmask[i] = INTERNAL_NOPRI; + f.f_pmask[i] = INTERNAL_NOPRI; /* save hostname if any */ - if (host && *host == '*') - host = NULL; - if (host) { + if (host != NULL && *host != '*') { int hl; - f->f_host = strdup(host); - if (f->f_host == NULL) { - logerror("strdup"); - exit(1); - } - hl = strlen(f->f_host); - if (hl > 0 && f->f_host[hl-1] == '.') - f->f_host[--hl] = '\0'; + strlcpy(f.f_host, host, sizeof(f.f_host)); + hl = strlen(f.f_host); + if (hl > 0 && f.f_host[hl-1] == '.') + f.f_host[--hl] = '\0'; /* RFC 5424 prefers logging FQDNs. */ if (RFC3164OutputFormat) - trimdomain(f->f_host, hl); + trimdomain(f.f_host, hl); } /* save program name if any */ - if (prog && *prog == '*') - prog = NULL; - if (prog) { - f->f_program = strdup(prog); - if (f->f_program == NULL) { - logerror("strdup"); - exit(1); - } - } - - if (pfilter) { - f->f_prop_filter = prop_filter_compile(pfilter); - if (f->f_prop_filter == NULL) { - logerror("filter compile error"); - exit(1); - } - } + if (prog != NULL && *prog != '*') + strlcpy(f.f_program, prog, sizeof(f.f_program)); /* scan through the list of selectors */ for (p = line; *p != '\0' && *p != '\t' && *p != ' ';) - p = parse_selector(p, f); + p = parse_selector(p, &f); /* skip to action part */ while (*p == '\t' || *p == ' ') p++; - parse_action(p, f); + parse_action(p, &f); + + /* An nvlist is heap allocated heap here. */ + nvl_filed = filed_to_nvlist(&f); + + if (pfilter && *pfilter != '*') { + nvlist_t *nvl_pfilter; + + nvl_pfilter = prop_filter_compile(pfilter); + if (nvl_pfilter == NULL) + err(1, "filter compile error"); + nvlist_add_nvlist(nvl_filed, "f_prop_filter", nvl_pfilter); + } - STAILQ_INSERT_TAIL(&fhead, f, next); + return (nvl_filed); } /* diff --git a/usr.sbin/syslogd/syslogd_cap.h b/usr.sbin/syslogd/syslogd_cap.h --- a/usr.sbin/syslogd/syslogd_cap.h +++ b/usr.sbin/syslogd/syslogd_cap.h @@ -47,6 +47,20 @@ #include "syslogd.h" +nvlist_t *cap_readconfigfile(cap_channel_t *, const char *); +int casper_readconfigfile(nvlist_t *, nvlist_t *); + +nvlist_t *filed_to_nvlist(const struct filed *); +nvlist_t *prop_filter_to_nvlist(const struct prop_filter *pfilter); + +struct filed *nvlist_to_filed(const nvlist_t *); +struct prop_filter *nvlist_to_prop_filter(const nvlist_t *nvl_prop_filter); + +#else /* !WITH_CASPER */ + +#define cap_readconfigfile(chan, cf) \ + readconfigfile(cf) + #endif /* WITH_CASPER */ #endif /* !_SYSLOGD_CAP_H_ */ diff --git a/usr.sbin/syslogd/syslogd_cap.c b/usr.sbin/syslogd/syslogd_cap.c --- a/usr.sbin/syslogd/syslogd_cap.c +++ b/usr.sbin/syslogd/syslogd_cap.c @@ -32,6 +32,7 @@ #include #include +#include #include @@ -39,10 +40,14 @@ /* This is where libcasper receives commands via nvlist. */ static int -casper_command(const char *cmd __unused, const nvlist_t *limits __unused, - nvlist_t *nvlin __unused, nvlist_t *nvlout __unused) +casper_command(const char *cmd, const nvlist_t *limits __unused, + nvlist_t *nvlin, nvlist_t *nvlout) { int error = EINVAL; + + if (strcmp(cmd, "readconfigfile") == 0) + error = casper_readconfigfile(nvlin, nvlout); + return (error); } diff --git a/usr.sbin/syslogd/syslogd_cap_config.c b/usr.sbin/syslogd/syslogd_cap_config.c new file mode 100644 --- /dev/null +++ b/usr.sbin/syslogd/syslogd_cap_config.c @@ -0,0 +1,296 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 The FreeBSD Foundation + * + * This software was developed by Jake Freeland + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "syslogd_cap.h" + +/* + * Convert the given prop_filter structure into an nvlist. + * Return a heap allocated pointer to the resulting nvlist. + */ +nvlist_t * +prop_filter_to_nvlist(const struct prop_filter *pfilter) +{ + nvlist_t *nvl_prop_filter = nvlist_create(0); + + nvlist_add_number(nvl_prop_filter, "prop_type", pfilter->prop_type); + nvlist_add_number(nvl_prop_filter, "cmp_type", pfilter->cmp_type); + nvlist_add_number(nvl_prop_filter, "cmp_flags", pfilter->cmp_flags); + nvlist_add_string(nvl_prop_filter, "pflt_strval", pfilter->pflt_strval); + /* + * Do not bother adding pflt_re. It will be recompiled + * using pflt_strval later, if applicable. + */ + + return (nvl_prop_filter); +} + +/* + * Convert the given nvlist into a prop_filter structure. + * Return a heap allocated pointer to the resulting prop_filter. + */ +struct prop_filter * +nvlist_to_prop_filter(const nvlist_t *nvl_prop_filter) +{ + struct prop_filter *pfilter; + + pfilter = calloc(1, sizeof(*pfilter)); + if (pfilter == NULL) + err(1, "calloc"); + pfilter->prop_type = nvlist_get_number(nvl_prop_filter, "prop_type"); + pfilter->cmp_type = nvlist_get_number(nvl_prop_filter, "cmp_type"); + pfilter->cmp_flags = nvlist_get_number(nvl_prop_filter, "cmp_flags"); + pfilter->pflt_strval = strdup(nvlist_get_string(nvl_prop_filter, + "pflt_strval")); + if (pfilter->cmp_type == FILT_CMP_REGEX) { + int re_flags = REG_NOSUB; + pfilter->pflt_re = calloc(1, sizeof(*pfilter->pflt_re)); + if (pfilter->pflt_re == NULL) + errx(1, "RE calloc() error"); + if ((pfilter->cmp_flags & FILT_FLAG_EXTENDED) != 0) + re_flags |= REG_EXTENDED; + if ((pfilter->cmp_flags & FILT_FLAG_ICASE) != 0) + re_flags |= REG_ICASE; + if (regcomp(pfilter->pflt_re, pfilter->pflt_strval, + re_flags) != 0) + errx(1, "RE compilation error"); + } + + return (pfilter); +} + +/* + * Convert the given struct filed into an nvl_filed nvlist. + * Return a heap allocated pointer to the resulting nvlist. + */ +nvlist_t * +filed_to_nvlist(const struct filed *filed) +{ + nvlist_t *nvl_filed = nvlist_create(0); + enum f_type f_type = filed->f_type; + size_t i, sz; + + nvlist_add_number(nvl_filed, "f_type", f_type); + nvlist_add_string(nvl_filed, "f_host", filed->f_host); + nvlist_add_string(nvl_filed, "f_program", filed->f_program); + if (filed->f_prop_filter != NULL) { + nvlist_add_nvlist(nvl_filed, "f_prop_filter", + prop_filter_to_nvlist(filed->f_prop_filter)); + } + sz = nitems(filed->f_pmask); + for (i = 0; i < sz; ++i) { + nvlist_append_number_array(nvl_filed, "f_pmask", + filed->f_pmask[i]); + } + sz = nitems(filed->f_pcmp); + for (i = 0; i < sz; ++i) { + nvlist_append_number_array(nvl_filed, "f_pcmp", + filed->f_pcmp[i]); + } + + if (filed->f_file >= 0) + nvlist_add_descriptor(nvl_filed, "f_file", filed->f_file); + nvlist_add_number(nvl_filed, "f_flags", filed->f_flags); + if (f_type == F_WALL || f_type == F_USERS) { + sz = nitems(filed->f_uname); + for (i = 0; i < sz; ++i) { + nvlist_append_string_array(nvl_filed, "f_uname", + filed->f_uname[i]); + } + } else if (f_type == F_FILE || f_type == F_CONSOLE || f_type == F_TTY) { + nvlist_add_string(nvl_filed, "f_fname", filed->f_fname); + } else if (f_type == F_FORW) { + struct addrinfo *ai = filed->f_addr, *cur; + nvlist_t *nvl_addrinfo; + + nvlist_add_string(nvl_filed, "f_hname", filed->f_hname); + if (filed->f_addr != NULL) { + for (cur = ai; cur != NULL; cur = cur->ai_next) { + nvl_addrinfo = addrinfo_pack(cur); + nvlist_append_nvlist_array(nvl_filed, + "f_addr", nvl_addrinfo); + nvlist_destroy(nvl_addrinfo); + } + } + } else if (filed->f_type == F_PIPE) { + nvlist_add_string(nvl_filed, "f_pname", filed->f_pname); + if (filed->f_procdesc >= 0) { + nvlist_add_descriptor(nvl_filed, "f_procdesc", + filed->f_procdesc); + } + } + + /* + * Book-keeping fields are not transferred. + */ + + return (nvl_filed); +} + +/* + * Convert the given nvl_filed nvlist into a struct filed. + * Return a heap allocated pointer to the resulting struct + * filed. + */ +struct filed * +nvlist_to_filed(const nvlist_t *nvl_filed) +{ + struct filed *filed; + enum f_type f_type; + const uint64_t *narr; + size_t i, sz; + + filed = calloc(1, sizeof(*filed)); + if (filed == NULL) + err(1, "calloc"); + + f_type = filed->f_type = nvlist_get_number(nvl_filed, "f_type"); + (void)strlcpy(filed->f_host, nvlist_get_string(nvl_filed, "f_host"), + sizeof(filed->f_host)); + (void)strlcpy(filed->f_program, nvlist_get_string(nvl_filed, + "f_program"), sizeof(filed->f_program)); + if (nvlist_exists_nvlist(nvl_filed, "f_prop_filter")) { + filed->f_prop_filter = nvlist_to_prop_filter( + nvlist_get_nvlist(nvl_filed, "f_prop_filter")); + } + narr = nvlist_get_number_array(nvl_filed, "f_pmask", &sz); + assert(sz == nitems(filed->f_pmask)); + for (i = 0; i < sz; ++i) + filed->f_pmask[i] = narr[i]; + narr = nvlist_get_number_array(nvl_filed, "f_pcmp", &sz); + assert(sz == nitems(filed->f_pcmp)); + for (i = 0; i < sz; ++i) + filed->f_pcmp[i] = narr[i]; + + if (nvlist_exists_descriptor(nvl_filed, "f_file")) + filed->f_file = dup(nvlist_get_descriptor(nvl_filed, "f_file")); + else + filed->f_file = -1; + filed->f_flags = nvlist_get_number(nvl_filed, "f_flags"); + if (f_type == F_WALL || f_type == F_USERS) { + const char * const *f_uname; + + f_uname = nvlist_get_string_array(nvl_filed, "f_uname", &sz); + assert(sz == nitems(filed->f_uname)); + for (i = 0; i < sz; ++i) { + (void)strlcpy(filed->f_uname[i], f_uname[i], + sizeof(filed->f_uname[i])); + } + } else if (f_type == F_FILE || f_type == F_CONSOLE || f_type == F_TTY) { + (void)strlcpy(filed->f_fname, nvlist_get_string(nvl_filed, + "f_fname"), sizeof(filed->f_fname)); + } else if (f_type == F_FORW) { + const nvlist_t * const *f_addr; + struct addrinfo *ai, **next = NULL; + + (void)strlcpy(filed->f_hname, nvlist_get_string(nvl_filed, + "f_hname"), sizeof(filed->f_hname)); + f_addr = nvlist_get_nvlist_array(nvl_filed, "f_addr", &sz); + for (i = 0; i < sz; ++i) { + ai = addrinfo_unpack(f_addr[i]); + if (next == NULL) + filed->f_addr = ai; + else + *next = ai; + next = &ai->ai_next; + } + } else if (filed->f_type == F_PIPE) { + (void)strlcpy(filed->f_pname, nvlist_get_string(nvl_filed, + "f_pname"), sizeof(filed->f_pname)); + if (nvlist_exists_descriptor(nvl_filed, "f_procdesc")) { + filed->f_procdesc = dup(nvlist_get_descriptor(nvl_filed, + "f_procdesc")); + } else { + filed->f_procdesc = -1; + } + } + + /* + * Book-keeping fields are not transferred. + */ + + return (filed); +} + +nvlist_t * +cap_readconfigfile(cap_channel_t *chan, const char *path) +{ + nvlist_t *nvl, *nvl_conf; + + nvl = nvlist_create(0); + nvlist_add_string(nvl, "cmd", "readconfigfile"); + nvlist_add_string(nvl, "path", path); + /* It is possible that our hostname has changed. */ + nvlist_add_string(nvl, "LocalHostName", LocalHostName); + nvl = cap_xfer_nvlist(chan, nvl); + if (nvl == NULL) { + logerror("Failed to xfer configuration nvlist"); + exit(1); + } + nvl_conf = nvlist_take_nvlist(nvl, "nvl_conf"); + + nvlist_destroy(nvl); + return (nvl_conf); +} + +/* + * Now that we're executing as libcasper, we can obtain the + * resources specified in the configuration. + */ +int +casper_readconfigfile(nvlist_t *nvlin, nvlist_t *nvlout) +{ + const char *path; + + /* + * Verify that syslogd did not manipulate the + * configuration file path. + */ + path = nvlist_get_string(nvlin, "path"); + if (strcmp(path, ConfFile) != 0) + err(1, "Configuration file mismatch: %s != %s", path, ConfFile); + + /* Refresh our copy of LocalHostName, in case it changed. */ + strlcpy(LocalHostName, nvlist_get_string(nvlin, "LocalHostName"), + sizeof(LocalHostName)); + + nvlist_move_nvlist(nvlout, "nvl_conf", readconfigfile(path)); + return (0); +}