Commit Diff


commit - 444134c06cbc0ad8b7366aba187ea98566b758a5
commit + 4267117b60d80255740be96d5077585dc6fca353
blob - d0ea33ff297130b499703d8f068c954783abcdb3
blob + 92b8b6e1ead43b0bcc59c1e691a49c49be6c0698
--- Makefile
+++ Makefile
@@ -30,7 +30,7 @@ SRCS+=ctl.c show.c if.c version.c route.c conf.c compl
 SRCS+=bridge.c tunnel.c media.c sysctl.c passwd.c pfsync.c carp.c
 SRCS+=trunk.c who.c more.c stringlist.c utils.c sqlite3.c ppp.c prompt.c
 SRCS+=nopt.c pflow.c wg.c nameserver.c ndp.c umb.c utf8.c cmdargs.c ctlargs.c
-SRCS+=helpcommands.c makeargv.c
+SRCS+=helpcommands.c makeargv.c syslog.c
 CLEANFILES+=compile.c
 LDADD=-lutil -ledit -ltermcap -lsqlite3 -L/usr/local/lib #-static
 
blob - 2c6b28c32e26056d4f1939cbe118d5492a29d10d
blob + 226fed59c36b42ba4f74c649eff6bb1d3647f4ee
--- commands.c
+++ commands.c
@@ -132,6 +132,7 @@ static int	docmd(int, char **);
 static int	setenvcmd(int, char **);
 static int	unsetenvcmd(int, char **);
 static int	shell(int, char*[]);
+static int	syslog_cmd(int, char *[], char *);
 static int	ping(int, char*[]);
 static int	ping6(int, char*[]);
 static int	traceroute(int, char*[]);
@@ -1729,6 +1730,7 @@ static char
 	sshhelp[] =	"SSH connection to remote host",
 	telnethelp[] =	"Telnet connection to remote host",
 	crontabhelp[] =	"Configure scheduled background jobs",
+	sysloghelp[] =	"Configure system logging",
 	quithelp[] =	"Close current connection",
 	exithelp[] =	"Leave configuration mode and return to privileged mode",
 	verbosehelp[] =	"Set verbose diagnostics",
@@ -1978,6 +1980,7 @@ Command cmdtab[] = {
 	{ "motd",       motdhelp,       CMPL(t) (char **)ctl_motd, ssctl, ctlhandler,    1, 1, 0, 1 },
 	{ "crontab",    crontabhelp,    CMPL(t) (char **)ctl_crontab, ssctl, ctlhandler,    1, 1, 0, 1 },
 	{ "scheduler",  crontabhelp,    CMPL(t) (char **)ctl_crontab, ssctl, ctlhandler,    1, 1, 0, 1 },
+	{ "syslog",	sysloghelp,     CMPL0 NULL, 0, syslog_cmd,	1, 1, 1, 0 },
 	{ "inet",	inethelp,	CMPL(t) (char **)ctl_inet, ssctl, ctlhandler,	1, 1, 0, 1 },
 	{ "ping",	pinghelp,	CMPL0 0, 0, ping,		0, 0, 0, 0 },
 	{ "ping6",	ping6help,	CMPL0 0, 0, ping6,		0, 0, 0, 0 },
@@ -2421,6 +2424,81 @@ shell(int argc, char **argv)
 	child = -1;
 
 	return 1;
+}
+
+/*
+ * syslog command.
+ */
+static int
+syslog_cmd(int argc, char *argv[], char *unused)
+{
+	int set = 1;
+
+	if (argc < 1) {
+		printf("%% Invalid arguments\n");
+		return 1;
+	}
+
+	if (NO_ARG(argv[0])) {
+		set = 0;
+		argc--;
+		argv++;
+	}
+
+	if (argc == 1) {
+		if (set) {
+			if (syslog_is_enabled())
+				return 0;
+			syslog_enable();
+		} else {
+			if (syslog_is_disabled())
+				return 0;
+			syslog_disable();
+		}
+
+		printf("%% system logging will be %s as soon as the "
+		    "\"syslog reload\" command is run\n",
+		    set ? "enabled" : "disabled");
+		return 0;
+	}
+
+	if (isprefix(argv[1], "reload")) {
+		if (argc != 2) {
+			printf("%% Invalid arguments\n");
+			return 1;
+		}
+		syslog_reload();
+		return 0;
+	}
+
+	if (isprefix(argv[1], "udp-af")) {
+		if (set) {
+			if (argc != 3) {
+				printf("%% Invalid arguments\n");
+				return 1;
+			}
+			if (isprefix(argv[2], "inet4"))
+				syslog_udp_af_v4();
+			else if (isprefix(argv[2], "inet6"))
+				syslog_udp_af_v6();
+			else {
+				printf("%% invalid UDP address family %s\n",
+				    argv[2]);
+				return 1;
+			}
+		} else {
+			if (argc != 2) {
+				printf("%% Invalid arguments\n");
+				return 1;
+			}
+			syslog_udp_af_disable();
+		}
+	} else {
+		printf("%% Invalid arguments\n");
+		return 1;
+	}
+
+	return 0;
 }
 
 /*
blob - 84ff64c42be556f8392417b7ba5f35c45332fff5
blob + d00bceecd642cedddf69c7a9abf21417dd5da150
--- conf.c
+++ conf.c
@@ -92,7 +92,6 @@ int default_rxprio(char *);
 int default_llpriority(char *);
 int islateif(char *);
 int isdefaultroute(struct sockaddr *, struct sockaddr *);
-int scantext(char *, char *);
 int ipv6ll_db_compare(struct sockaddr_in6 *, struct sockaddr_in6 *,
     char *);
 
@@ -296,6 +295,9 @@ conf(FILE *output)
 
 	fprintf(output, "!\n");
 	conf_nameserver(output);
+
+	fprintf(output, "!\n");
+	conf_syslog(output);
 
 	return(0);
 }
blob - 98be4c1f2a50bf22257eacd7a22db984d21c26e7
blob + 7863546b0296f84a69797ca438c9405e737071d8
--- externs.h
+++ externs.h
@@ -84,6 +84,7 @@ u_long default_mtu(char *);
 int conf_routes(FILE *, char *, int, int, int);
 int conf_dhcrelay(char *, char *, int);
 int dhcpleased_has_address(char *, const char *, const char *);
+int scantext(char *, char *);
 
 /* show.c */
 void p_rttables(int, u_int, int);
@@ -173,6 +174,7 @@ extern pid_t child;
 #define HALT		"/sbin/halt"
 #define SU		"/usr/bin/su"
 #define DOAS		"/usr/bin/doas"
+#define RCCTL		"/usr/sbin/rcctl"
 #define SAVESCRIPT	"/usr/local/bin/save.sh"
 #ifndef DHCPLEASES
 #define DHCPLEASES	"/var/db/dhcpd.leases"
@@ -564,3 +566,15 @@ int mbsavis(char**, int *, const char *);
 /* ctlargs.c */
 int pr_prot1(int, char **);
 char **step_optreq(char **, char **, int, char **, int);
+
+/* syslog.c */
+void syslog_enable(void);
+int syslog_is_enabled(void);
+void syslog_disable(void);
+int syslog_is_disabled(void);
+void syslog_udp_af_disable(void);
+void syslog_udp_af_v4(void);
+void syslog_udp_af_v6(void);
+void syslog_reload(void);
+void syslog_stop(void);
+void conf_syslog(FILE *);
blob - 746039c12f247f72374cc49c9792c96bcbe0ed52
blob + dfc6b3e3aefb2ff0426854de58f389e220ce5f16
--- main.c
+++ main.c
@@ -127,6 +127,8 @@ main(int argc, char *argv[])
 		printf("%% database pppoeipaddrmode creation failed\n");
 	if (db_create_table_flag_x("pin") < 0)
 		printf("%% database pin creation failed\n");
+	if (db_create_table_flag_x("syslog") < 0)
+		printf("%% database syslog table creation failed\n");
 
 	if (iflag) {
 		/*
blob - /dev/null
blob + 50a0ccf832a0ce794a40f59bf5f1bbe304fe99cc (mode 644)
--- /dev/null
+++ syslog.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2023 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include "stringlist.h"
+#include "externs.h"
+
+void
+syslog_enable(void)
+{
+	/* prevent duplicate rows */
+	if (db_delete_flag_x_ctl("ctl", "syslog", 0) < 0)
+		printf("%% database deletion failure: ctl syslog\n");
+
+	if (db_insert_flag_x("ctl", "syslog", 0, DB_X_ENABLE, "") < 0)
+		printf("%% database insert failure: ctl syslog enable\n");
+}
+
+int
+syslog_is_enabled(void)
+{
+	int dbflag;
+
+	dbflag = db_select_flag_x_dbflag_rtable("ctl", "syslog", 0);
+	return (dbflag < 0 || dbflag == DB_X_ENABLE);
+}
+
+void
+syslog_disable(void)
+{
+	/* prevent duplicate rows */
+	if (db_delete_flag_x_ctl("ctl", "syslog", 0) < 0)
+		printf("%% database deletion failure: ctl syslog\n");
+
+	if (db_insert_flag_x("ctl", "syslog", 0, DB_X_DISABLE_ALWAYS, "") < 0)
+		printf("%% database insert failure: ctl syslog disable\n");
+}
+
+int
+syslog_is_disabled(void)
+{
+	int dbflag;
+
+	dbflag = db_select_flag_x_dbflag_rtable("ctl", "syslog", 0);
+	return (dbflag == DB_X_DISABLE_ALWAYS);
+}
+
+void
+syslog_udp_af_disable(void)
+{
+	if (db_delete_flag_x_ctl("syslog", "udp-af", 0) < 0)
+		printf("%% database delete failure syslog udp-af\n");
+}
+
+void
+syslog_udp_af_v4(void)
+{
+	syslog_udp_af_disable(); /* prevent duplicate rows */
+
+	if (db_insert_flag_x("syslog", "udp-af", 0, 0, "-4") < 0)
+		printf("%% database insert failure: syslog udp-af v4\n");
+}
+
+void
+syslog_udp_af_v6(void)
+{
+	syslog_udp_af_disable(); /* prevent duplicate rows */
+
+	if (db_insert_flag_x("syslog", "udp-af", 0, 0, "-6") < 0)
+		printf("%% database insert failure: syslog udp-af v6\n");
+}
+
+void
+conf_syslog(FILE *output)
+{
+	int dbflag;
+	StringList *data;
+	int reload = 0;
+
+	dbflag = db_select_flag_x_dbflag_rtable("ctl", "syslog", 0);
+	if (dbflag < 0)
+		dbflag = DB_X_ENABLE;
+
+	switch (dbflag) {
+	case DB_X_ENABLE:
+		/* syslogd is enabled unless explicitly disabled */
+		break;
+	case DB_X_DISABLE_ALWAYS:
+		fprintf(output, "no syslog\n");
+		reload = 1;
+		break;
+	default:
+		printf("%% bad ctl syslog flag 0x%x in database\n", dbflag);
+		return;
+	}
+
+	data = sl_init();
+	if (db_select_flag_x_ctl(data, "syslog", "udp-af") < 0) {
+		printf("%% database select failure: syslog udp-af\n");
+		goto done;
+	}
+	if (data->sl_cur) {
+		fprintf(output, "syslog udp-af %s\n", data->sl_str[0]);
+		reload = 1;
+	}
+
+	if (reload)
+		fprintf(output, "syslog reload\n");
+done:
+	sl_free(data, 1);
+}
+
+static int
+run_rcctl(char *argv[], int outfd)
+{
+	int ret;
+
+	ret = cmdargs_output(RCCTL, argv, outfd, -1);
+	if (ret < 0)
+		printf("%% could not run %s\n", RCCTL);
+	return ret;
+}
+
+void
+syslog_stop(void)
+{
+	char *stop_argv[] = { RCCTL, "stop", "syslogd", NULL };
+
+	printf("%% stopping syslogd\n");
+	run_rcctl(stop_argv, -1);
+}
+
+static void
+syslog_start(void)
+{
+	char *start_argv[] = { RCCTL, "start", "syslogd", NULL };
+
+	printf("%% starting syslogd\n");
+	run_rcctl(start_argv, -1);
+}
+
+static int
+daemon_has_status(char *name, char *status)
+{
+	char *argv[] = { RCCTL, "ls", status, NULL };
+	char outpath[PATH_MAX];
+	char text[128];
+	int fd = -1, found = 0, len;
+
+	len = snprintf(text, sizeof(text), "%s\n", name);
+	if (len < 0) {
+		printf("%% snprintf: %s\n", strerror(errno));
+		return 0;
+	}
+	if ((size_t)len >= sizeof(text)) {
+		printf("%% daemon name too long: %s\n", name);
+		return 0;
+	}
+
+	strlcpy(outpath, "/tmp/nsh-XXXXXX", sizeof(outpath));
+	fd = mkstemp(outpath);
+	if (fd == -1) {
+		printf("%% mkstemp: %s\n", strerror(errno));
+		return 0;
+	}
+
+	/* rcctl will exit with code 1 if a daemon is matching */
+	if (run_rcctl(argv, fd) == 1 && scantext(outpath, text))
+		found = 1;
+
+	unlink(outpath);
+	close(fd);
+	return found;
+}
+
+void
+syslog_reload(void)
+{
+	char *setflags_argv[] = { RCCTL, "set", "syslogd", "flags", "", NULL };
+	char *reload_argv[] = { RCCTL, "reload", "syslogd", NULL };
+	char *enable_argv[] = { RCCTL, "enable", "syslogd", NULL };
+	char *disable_argv[] = { RCCTL, "disable", "syslogd", NULL };
+	StringList *data, *flags;
+	char *s = NULL;
+	int i;
+	size_t len = 0;
+
+	if (syslog_is_disabled()) {
+		run_rcctl(disable_argv, -1);
+		if (daemon_has_status("syslogd", "rogue"))
+			syslog_stop();
+		return;
+	}
+
+	data = sl_init();
+	flags = sl_init();
+
+	if (db_select_flag_x_ctl(data, "syslog", "udp-af") < 0) {
+		printf("%% database select failure: syslog udp-af\n");
+		goto done;
+	}
+	if (data->sl_cur) {
+		s = strdup(data->sl_str[0]);
+		if (s == NULL) {
+			printf("%% strdup: %s\n", strerror(errno));
+			goto done;
+		}
+		sl_add(flags, s);
+	}
+
+	for (i = 0; i < flags->sl_cur; i++)
+		len += strlen(flags->sl_str[i]) + 1;
+
+	if (len) {
+		size_t sz = len + 1;
+
+		s = calloc(sz, 1);
+		if (s == NULL) {
+			printf("%% strdup: %s\n", strerror(errno));
+			goto done;
+		}
+		for (i = 0; i < flags->sl_cur; i++) {
+			if (strlcat(s, flags->sl_str[i], sz) >= sz) {
+				printf("%% flags too long\n");
+				goto done;
+			}
+			if (strlcat(s, " ", sz) >= sz) {
+				printf("%% flags too long\n");
+				goto done;
+			}
+		}
+
+		setflags_argv[4] = s;
+	}
+
+	if (run_rcctl(enable_argv, -1) != 0) {
+		printf("%% could not enable syslogd\n");
+		goto done;
+	}
+
+	printf("%% setting syslogd flags: %s\n", setflags_argv[4]);
+	if (run_rcctl(setflags_argv, -1) != 0) {
+		printf("%% could not set syslogd flags\n");
+		goto done;
+	}
+
+	if (daemon_has_status("syslogd", "failed")) {
+		syslog_start();
+	} else {
+		printf("%% reloading syslogd\n");
+		run_rcctl(reload_argv, -1);
+	}
+done:
+	sl_free(data, 1);
+	sl_free(flags, 1);
+	free(s);
+}