commit 4267117b60d80255740be96d5077585dc6fca353 from: Stefan Sperling date: Tue Aug 22 15:30:27 2023 UTC add commands to control syslogd Currently supported syslog commands: syslog no syslog syslog reload syslog udp-af inet4 syslog udp-af inet6 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 + * + * 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 +#include +#include +#include +#include +#include + +#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); +}