diff --git a/usr.sbin/syslogd/Makefile b/usr.sbin/syslogd/Makefile --- a/usr.sbin/syslogd/Makefile +++ b/usr.sbin/syslogd/Makefile @@ -17,7 +17,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 @@ -71,6 +71,8 @@ #include #include +#include +#include #define MAXLINE 8192 /* maximum line length */ #define MAXSVLINE MAXLINE /* maximum saved line length */ @@ -178,5 +180,11 @@ u_int f_repeatcount; /* number of "repeated" msgs */ STAILQ_ENTRY(filed) next; /* next in linked list */ }; +extern STAILQ_HEAD(filed_list, filed) fhead; + +extern char LocalHostName[MAXHOSTNAMELEN]; + +void closelogfiles(void); +void parseconfigfile(FILE *, bool); #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 @@ -198,8 +198,10 @@ #define RFC3164_DATELEN 15 #define RFC3164_DATEFMT "%b %e %H:%M:%S" -static STAILQ_HEAD(, filed) fhead = - STAILQ_HEAD_INITIALIZER(fhead); /* Log files that we write to */ +/* + * List of log files. + */ +struct filed_list fhead = STAILQ_HEAD_INITIALIZER(fhead); static struct filed consfile; /* Console */ /* @@ -279,7 +281,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 */ @@ -2226,7 +2228,7 @@ return (1); } -static void +void parseconfigfile(FILE *cf, bool allow_includes) { FILE *cf2; @@ -2379,7 +2381,7 @@ /* * Close all open log files. */ -static void +void closelogfiles(void) { struct filed *f; 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 @@ -43,9 +43,17 @@ #include "syslogd.h" +void cap_readconfigfile(cap_channel_t *, const char *); +int casper_readconfigfile(nvlist_t *, nvlist_t *); + nvlist_t *filed_to_nvlist(const struct filed *); struct filed *nvlist_to_filed(const nvlist_t *); +#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 @@ -198,10 +198,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,139 @@ +/*- + * 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 "syslogd_cap.h" + +/* + * Return an nvlist "environment" containing global variables + * that are subject to change during runtime. + */ +static nvlist_t * +create_cap_env(void) +{ + struct filed *f; + nvlist_t *env = nvlist_create(0); + uint64_t count = 0; + + nvlist_add_string(env, "LocalHostName", LocalHostName); + STAILQ_FOREACH(f, &fhead, next) { + nvlist_t *nvl_filed = filed_to_nvlist(f); + nvlist_append_nvlist_array(env, "filed_list", nvl_filed); + nvlist_destroy(nvl_filed); + ++count; + } + if (count > 0) + nvlist_add_number(env, "filed_count", count); + + return (env); +} + +/* + * Populate the program's global variables using the values + * stored in the provided nvlist, @env. + */ +static void +populate_cap_env(const nvlist_t *env) +{ + if (nvlist_exists_string(env, "LocalHostName")) { + strlcpy(LocalHostName, nvlist_get_string(env, "LocalHostName"), + sizeof(LocalHostName)); + } + if (nvlist_exists_nvlist_array(env, "filed_list")) { + struct filed *f; + const nvlist_t * const *filed_list; + uint64_t filed_count, i; + + filed_count = nvlist_get_number(env, "filed_count"); + filed_list = nvlist_get_nvlist_array(env, "filed_list", + &filed_count); + for (i = 0; i < filed_count; ++i) { + f = nvlist_to_filed(filed_list[i]); + STAILQ_INSERT_TAIL(&fhead, f, next); + } + } +} + +/* + * Parse the configuration and populate our global environment + * with the resulting nvlist. + */ +void +cap_readconfigfile(cap_channel_t *chan, const char *path) +{ + nvlist_t *nvl = nvlist_create(0); + int error; + + nvlist_add_string(nvl, "cmd", "readconfigfile"); + nvlist_add_string(nvl, "path", path); + nvlist_move_nvlist(nvl, "env", create_cap_env()); + nvl = cap_xfer_nvlist(chan, nvl); + if (nvl == NULL) + err(1, "Failed to xfer configuration nvlist"); + error = nvlist_get_number(nvl, "error"); + if (error != 0) { + nvlist_destroy(nvl); + errc(1, error, "Failed to parse configuration file: %s", path); + } + populate_cap_env(nvlist_get_nvlist(nvl, "env")); + nvlist_destroy(nvl); +} + +/* + * Now that we're executing as libcasper, we can parse the syslogd + * configuration. Return our global environment via nvlist. + */ +int +casper_readconfigfile(nvlist_t *nvlin, nvlist_t *nvlout) +{ + FILE *cf = fopen(nvlist_get_string(nvlin, "path"), "r"); + if (cf == NULL) + return (errno); + populate_cap_env(nvlist_get_nvlist(nvlin, "env")); + + /* + * If we're here, the config has been reset + * and syslogd's global filed list has been + * cleared. Do the same here. + */ + closelogfiles(); + + /* + * Parse the configuration file and create + * a snapshot of our global env for syslogd. + */ + parseconfigfile(cf, true); + nvlist_add_nvlist(nvlout, "env", create_cap_env()); + + (void)fclose(cf); + return (0); +}