git: 2567168dc498 - main - syslogd: Refresh configuration using libcasper
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 27 Nov 2024 22:27:11 UTC
The branch main has been updated by jfree: URL: https://cgit.FreeBSD.org/src/commit/?id=2567168dc49869475db79176bf5f6ae9761bc75a commit 2567168dc49869475db79176bf5f6ae9761bc75a Author: Jake Freeland <jfree@FreeBSD.org> AuthorDate: 2024-11-27 22:25:12 +0000 Commit: Jake Freeland <jfree@FreeBSD.org> CommitDate: 2024-11-27 22:25:12 +0000 syslogd: Refresh configuration using libcasper When a SIGHUP signal is sent to syslogd, the configuration is reparsed, leading to new resource acquisition. If syslogd is running in capability mode and a SIGHUP is received, new resources cannot be acquired. To mitigate this issue, libcasper is used to parse the configuration. The libcasper process runs outside of capability mode and is capable of parsing syslogd's configuration and obtaining new resources. These resources are then sent to the syslogd process via nvlist. Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D41464 --- usr.sbin/syslogd/Makefile | 3 +- usr.sbin/syslogd/syslogd.c | 234 ++++++++++++--------------- usr.sbin/syslogd/syslogd.h | 15 +- usr.sbin/syslogd/syslogd_cap.c | 9 +- usr.sbin/syslogd/syslogd_cap.h | 14 ++ usr.sbin/syslogd/syslogd_cap_config.c | 296 ++++++++++++++++++++++++++++++++++ 6 files changed, 436 insertions(+), 135 deletions(-) diff --git a/usr.sbin/syslogd/Makefile b/usr.sbin/syslogd/Makefile index e9e7455ed2cc..4088b2e03651 100644 --- a/usr.sbin/syslogd/Makefile +++ b/usr.sbin/syslogd/Makefile @@ -14,7 +14,8 @@ SYSLOGD_DPACAKGE= syslogd 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.c b/usr.sbin/syslogd/syslogd.c index 8937aa72804d..0c05884cc17d 100644 --- 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 int nulldesc; /* /dev/null descriptor */ 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 @@ struct iovlist; 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_first(struct filed *, const char *, const char *, 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 socklist_recv_sock(struct socklist *); 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 @@ skip_message(const char *name, const char *spec, int checkcase) int exclude = 0; /* Behaviour on explicit match */ - if (spec == NULL) + if (spec == NULL || *spec == '\0') return (0); switch (*spec) { case '-': @@ -1445,7 +1444,7 @@ evaluate_prop_filter(const struct prop_filter *filter, const char *value) /* 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 @@ cvthname(struct sockaddr *f) /* * Print syslogd errors some place. */ -static void +void logerror(const char *msg) { char buf[512]; @@ -2255,8 +2254,8 @@ configfiles(const struct dirent *dp) 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 @@ parseconfigfile(FILE *cf, bool allow_includes) 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 @@ parseconfigfile(FILE *cf, bool allow_includes) } 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 @@ closelogfiles(void) 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 @@ init(bool reload) Initialized = false; closelogfiles(); - readconfigfile(ConfFile); + fill_flist(readconfigfile(ConfFile)); Initialized = true; if (Debug) { @@ -2561,7 +2584,7 @@ init(bool reload) default: break; } - if (f->f_program) + if (*f->f_program != '\0') printf(" (%s)", f->f_program); printf("\n"); } @@ -2597,29 +2620,18 @@ init(bool reload) /* * 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 @@ prop_filter_compile(const char *cfilter) } 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 @@ prop_filter_compile(const char *cfilter) /* 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 @@ prop_filter_compile(const char *cfilter) /* 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 @@ parse_selector(const char *p, struct filed *f) { 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 @@ parse_selector(const char *p, struct filed *f) 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 @@ parse_selector(const char *p, struct filed *f) } 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 @@ parse_action(const char *p, struct filed *f) } else syncfile = true; + f->f_file = -1; switch (*p) { case '@': { @@ -2910,7 +2901,7 @@ parse_action(const char *p, struct filed *f) }; 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 @@ parse_action(const char *p, struct filed *f) 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 @@ parse_action(const char *p, struct filed *f) /* * 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.h b/usr.sbin/syslogd/syslogd.h index 012338d2c7c1..16de03590ada 100644 --- a/usr.sbin/syslogd/syslogd.h +++ b/usr.sbin/syslogd/syslogd.h @@ -64,6 +64,7 @@ #define _SYSLOGD_H_ #include <sys/param.h> +#include <sys/nv.h> #include <sys/queue.h> #include <sys/time.h> @@ -71,6 +72,8 @@ #include <sys/syslog.h> #include <regex.h> +#include <stdbool.h> +#include <stdio.h> #define MAXLINE 8192 /* maximum line length */ #define MAXSVLINE MAXLINE /* maximum saved line length */ @@ -107,7 +110,6 @@ struct prop_filter { #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 @@ struct filed { 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 @@ struct filed { 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_cap.c b/usr.sbin/syslogd/syslogd_cap.c index 71fc89854c58..6f64ee8878bf 100644 --- a/usr.sbin/syslogd/syslogd_cap.c +++ b/usr.sbin/syslogd/syslogd_cap.c @@ -32,6 +32,7 @@ #include <sys/socket.h> #include <libcasper.h> +#include <string.h> #include <casper/cap_net.h> @@ -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.h b/usr.sbin/syslogd/syslogd_cap.h index fdfc969b3d0f..24b448ff2352 100644 --- 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_config.c b/usr.sbin/syslogd/syslogd_cap_config.c new file mode 100644 index 000000000000..366c035925d6 --- /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 <jfree@FreeBSD.org> + * 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 <sys/types.h> +#include <sys/socket.h> + +#include <assert.h> +#include <err.h> +#include <libcasper.h> +#include <netdb.h> +#include <string.h> + +#include <casper/cap_net.h> + +#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); +}