diff --git a/MANIFEST b/MANIFEST index acf328c52..96f2a489a 100644 --- a/MANIFEST +++ b/MANIFEST @@ -120,6 +120,8 @@ lib/util/isblank.c lib/util/key_val.c lib/util/lbuf.c lib/util/locking.c +lib/util/logfac.c +lib/util/logpri.c lib/util/memrchr.c lib/util/memset_s.c lib/util/mkdir_parents.c @@ -243,6 +245,7 @@ logsrvd/Makefile.in logsrvd/log_server.pb-c.c logsrvd/log_server.pb-c.h logsrvd/log_server.proto +logsrvd/eventlog.c logsrvd/iolog_writer.c logsrvd/logsrvd.c logsrvd/logsrvd.h diff --git a/examples/sudo_logsrvd.conf b/examples/sudo_logsrvd.conf index 3dbd274fa..179aefe91 100644 --- a/examples/sudo_logsrvd.conf +++ b/examples/sudo_logsrvd.conf @@ -6,12 +6,12 @@ # The host name or IP address and port to listen on. If no port is # specified, port 30344 will be used. # The following forms are accepted: -# listent_address = hostname -# listent_address = hostname:port -# listent_address = IPv4_address -# listent_address = IPv4_address:port -# listent_address = [IPv6_address] -# listent_address = [IPv6_address]:port +# listen_address = hostname +# listen_address = hostname:port +# listen_address = IPv4_address +# listen_address = IPv4_address:port +# listen_address = [IPv6_address] +# listen_address = [IPv6_address]:port # # Multiple listen_address settings may be specified. # The default is to listen on all addresses. @@ -20,21 +20,21 @@ [iolog] # The top-level directory to use when constructing the path name for the # I/O log directory. The session sequence number, if any, is stored here. -iolog_dir = /var/log/sudo-io +#iolog_dir = /var/log/sudo-io # The path name, relative to iolog_dir, in which to store I/O logs. # Note that iolog_file may contain directory components. -iolog_file = %{seq} +#iolog_file = %{seq} # If set, I/O log data is flushed to disk after each write instead of # buffering it. This makes it possible to view the logs in real-time # as the program is executing but may significantly reduce the effectiveness # of I/O log compression. -iolog_flush = true +#iolog_flush = true # If set, I/O logs will be compressed using zlib. Enabling compression can # make it harder to view the logs in real-time as the program is executing. -iolog_compress = false +#iolog_compress = false # The group name to look up when setting the group-ID on new I/O log files # and directories. If iolog_group is not set, the primary group-ID of the @@ -54,7 +54,7 @@ iolog_compress = false # write bits, even if they are not present in the specified mode. When # creating I/O log directories, search (execute) bits are added to match # the read and write bits specified by iolog_mode. -iolog_mode = 0600 +#iolog_mode = 0600 # The maximum sequence number that will be substituted for the %{seq} # escape in the I/O log file (see the iolog_dir description below for @@ -62,4 +62,52 @@ iolog_mode = 0600 # base 36, maxseq itself should be expressed in decimal. Values larger # than 2176782336 (which corresponds to the base 36 sequence number # ZZZZZZ) will be silently truncated to 2176782336. -maxseq = 2176782336 +#maxseq = 2176782336 + +[eventlog] +# Where to log accept, reject and alert events. +# Accepted values are syslog, logfile, or none. +# Defaults to syslog +#log_type = syslog + +# Event log format. +# Currently only supports sudo-style event logs. +#log_format = sudo + +[syslog] +# The maximum length of a syslog payload. +# On many systems, syslog(3) has a relatively small log buffer. +# IETF RFC 5424 states that syslog servers must support messages +# of at least 480 bytes and should support messages up to 2048 bytes. +# Messages larger than this value will be split into multiple messages. +#maxlen = 960 + +# The syslog facility to use for event log messages. +# The following syslog facilities are supported: authpriv (if your OS +# supports it), auth, daemon, user, local0, local1, local2, local3, local4, +# local5, local6, and local7. +#facility = authpriv + +# The syslog priority to use for event log accept messages, when +# the command is allowed by the security policy. The following syslog +# priorities are supported: alert, crit, debug, emerg, err, info, +# notice, warning, and none. +#accept_priority = notice + +# The syslog priority to use for event log reject messages, when the +# command is not allowed by the security policy. +#reject_priority = alert + +# The syslog priority to use for event log alert messages reported +# by the security policy. +#alert_priority = alert + +[logfile] +# The format string used when formatting the date and time for +# file-based event logs. Formatting is performed via strftime(3) so +# any format string supported by that function is allowed. +#time_format = %h %e %T + +# The path to the file-based event log. +# This path must be fully-qualified and start with a '/' character. +#path = /var/log/sudo diff --git a/include/sudo_util.h b/include/sudo_util.h index 4434c61c2..d6ee26261 100644 --- a/include/sudo_util.h +++ b/include/sudo_util.h @@ -220,6 +220,18 @@ __dso_public bool sudo_lock_file_v1(int fd, int action); __dso_public bool sudo_lock_region_v1(int fd, int action, off_t len); #define sudo_lock_region(_a, _b, _c) sudo_lock_region_v1((_a), (_b), (_c)) +/* logfac.c */ +__dso_public bool sudo_str2logfac_v1(const char *str, int *logfac); +#define sudo_str2logfac(_a, _b) sudo_str2logfac_v1((_a), (_b)) +__dso_public const char *sudo_logfac2str_v1(int num); +#define sudo_logfac2str(_a) sudo_logfac2str_v1((_a)) + +/* logpri.c */ +__dso_public bool sudo_str2logpri_v1(const char *str, int *logpri); +#define sudo_str2logpri(_a, _b) sudo_str2logpri_v1((_a), (_b)) +__dso_public const char *sudo_logpri2str_v1(int num); +#define sudo_logpri2str(_a) sudo_logpri2str_v1((_a)) + /* mkdir_parents.c */ __dso_public bool sudo_mkdir_parents_v1(char *path, uid_t uid, gid_t gid, mode_t mode, bool quiet); #define sudo_mkdir_parents(_a, _b, _c, _d, _e) sudo_mkdir_parents_v1((_a), (_b), (_c), (_d), (_e)) diff --git a/lib/util/Makefile.in b/lib/util/Makefile.in index eee353638..f7612ea2b 100644 --- a/lib/util/Makefile.in +++ b/lib/util/Makefile.in @@ -117,10 +117,11 @@ SHELL = @SHELL@ LTOBJS = @DIGEST@ event.lo fatal.lo key_val.lo gethostname.lo \ gettime.lo getgrouplist.lo gidlist.lo lbuf.lo locking.lo \ - mkdir_parents.lo parseln.lo progname.lo secure_path.lo \ - setgroups.lo strsplit.lo strtobool.lo strtoid.lo strtomode.lo \ - strtonum.lo sudo_conf.lo sudo_debug.lo sudo_dso.lo term.lo \ - ttyname_dev.lo ttysize.lo @COMMON_OBJS@ @LTLIBOBJS@ + logfac.lo logpri.lo mkdir_parents.lo parseln.lo progname.lo \ + secure_path.lo setgroups.lo strsplit.lo strtobool.lo \ + strtoid.lo strtomode.lo strtonum.lo sudo_conf.lo \ + sudo_debug.lo sudo_dso.lo term.lo ttyname_dev.lo \ + ttysize.lo @COMMON_OBJS@ @LTLIBOBJS@ IOBJS = $(LTOBJS:.lo=.i) @@ -771,6 +772,26 @@ locking.i: $(srcdir)/locking.c $(incdir)/compat/stdbool.h \ $(CC) -E -o $@ $(CPPFLAGS) $< locking.plog: locking.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/locking.c --i-file $< --output-file $@ +logfac.lo: $(srcdir)/logfac.c $(incdir)/compat/stdbool.h \ + $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ + $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(top_builddir)/config.h + $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/logfac.c +logfac.i: $(srcdir)/logfac.c $(incdir)/compat/stdbool.h \ + $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ + $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +logfac.plog: logfac.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/logfac.c --i-file $< --output-file $@ +logpri.lo: $(srcdir)/logpri.c $(incdir)/compat/stdbool.h \ + $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ + $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(top_builddir)/config.h + $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/logpri.c +logpri.i: $(srcdir)/logpri.c $(incdir)/compat/stdbool.h \ + $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ + $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +logpri.plog: logpri.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/logpri.c --i-file $< --output-file $@ memrchr.lo: $(srcdir)/memrchr.c $(incdir)/sudo_compat.h $(top_builddir)/config.h $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/memrchr.c memrchr.i: $(srcdir)/memrchr.c $(incdir)/sudo_compat.h $(top_builddir)/config.h diff --git a/lib/util/logfac.c b/lib/util/logfac.c new file mode 100644 index 000000000..afce291fd --- /dev/null +++ b/lib/util/logfac.c @@ -0,0 +1,93 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 1999-2005, 2007-2019 + * Todd C. Miller + * + * 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. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +/* + * This is an open source non-commercial project. Dear PVS-Studio, please check it. + * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + */ + +#include + +#include +#include +#include +#include +#include + +#include "sudo_compat.h" +#include "sudo_debug.h" +#include "sudo_util.h" + +/* + * For converting between syslog numbers and strings. + */ +struct strmap { + char *name; + int num; +}; + +static const struct strmap facilities[] = { +#ifdef LOG_AUTHPRIV + { "authpriv", LOG_AUTHPRIV }, +#endif + { "auth", LOG_AUTH }, + { "daemon", LOG_DAEMON }, + { "user", LOG_USER }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, + { NULL, -1 } +}; + +bool +sudo_str2logfac_v1(const char *str, int *logfac) +{ + const struct strmap *fac; + debug_decl(sudo_str2logfac, SUDO_DEBUG_UTIL) + + for (fac = facilities; fac->name != NULL; fac++) { + if (strcmp(str, fac->name) == 0) { + *logfac = fac->num; + debug_return_bool(true); + } + } + debug_return_bool(false); +} + +const char * +sudo_logfac2str_v1(int num) +{ + const struct strmap *fac; + debug_decl(sudo_logfac2str, SUDO_DEBUG_UTIL) + + for (fac = facilities; fac->name != NULL; fac++) { + if (fac->num == num) + break; + } + debug_return_const_str(fac->name); +} diff --git a/lib/util/logpri.c b/lib/util/logpri.c new file mode 100644 index 000000000..1b28c8745 --- /dev/null +++ b/lib/util/logpri.c @@ -0,0 +1,88 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 1999-2005, 2007-2019 + * Todd C. Miller + * + * 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. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +/* + * This is an open source non-commercial project. Dear PVS-Studio, please check it. + * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + */ + +#include + +#include +#include +#include +#include +#include + +#include "sudo_compat.h" +#include "sudo_debug.h" +#include "sudo_util.h" + +/* + * For converting between syslog numbers and strings. + */ +struct strmap { + char *name; + int num; +}; + +static const struct strmap priorities[] = { + { "alert", LOG_ALERT }, + { "crit", LOG_CRIT }, + { "debug", LOG_DEBUG }, + { "emerg", LOG_EMERG }, + { "err", LOG_ERR }, + { "info", LOG_INFO }, + { "notice", LOG_NOTICE }, + { "warning", LOG_WARNING }, + { "none", -1 }, + { NULL, -1 } +}; + +bool +sudo_str2logpri_v1(const char *str, int *logpri) +{ + const struct strmap *pri; + debug_decl(sudo_str2logpri, SUDO_DEBUG_UTIL) + + for (pri = priorities; pri->name != NULL; pri++) { + if (strcmp(str, pri->name) == 0) { + *logpri = pri->num; + debug_return_bool(true); + } + } + debug_return_bool(false); +} + +const char * +sudo_logpri2str_v1(int num) +{ + const struct strmap *pri; + debug_decl(sudo_logpri2str, SUDO_DEBUG_UTIL) + + for (pri = priorities; pri->name != NULL; pri++) { + if (pri->num == num) + break; + } + debug_return_const_str(pri->name); +} diff --git a/lib/util/util.exp.in b/lib/util/util.exp.in index d364fec86..bf92a9800 100644 --- a/lib/util/util.exp.in +++ b/lib/util/util.exp.in @@ -88,6 +88,8 @@ sudo_lbuf_init_v1 sudo_lbuf_print_v1 sudo_lock_file_v1 sudo_lock_region_v1 +sudo_logfac2str_v1 +sudo_logpri2str_v1 sudo_mkdir_parents_v1 sudo_new_key_val_v1 sudo_parse_gids_v1 @@ -96,6 +98,8 @@ sudo_parseln_v2 sudo_secure_dir_v1 sudo_secure_file_v1 sudo_setgroups_v1 +sudo_str2logfac_v1 +sudo_str2logpri_v1 sudo_strsplit_v1 sudo_strtobool_v1 sudo_strtoid_v1 diff --git a/logsrvd/Makefile.in b/logsrvd/Makefile.in index 9dd9046c0..6b4706844 100644 --- a/logsrvd/Makefile.in +++ b/logsrvd/Makefile.in @@ -107,7 +107,7 @@ SHELL = @SHELL@ PROGS = sudo_logsrvd sudo_sendlog -LOGSRVD_OBJS = iolog_writer.o logsrvd.o \ +LOGSRVD_OBJS = eventlog.o iolog_writer.o logsrvd.o \ logsrvd_conf.o log_server.pb-c.o protobuf-c.o SENDLOG_OBJS = sendlog.o log_server.pb-c.o protobuf-c.o @@ -211,6 +211,22 @@ realclean: distclean cleandir: realclean # Autogenerated dependencies, do not modify +eventlog.o: $(srcdir)/eventlog.c $(devdir)/log_server.pb-c.h \ + $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ + $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \ + $(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \ + $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/logsrvd.h \ + $(srcdir)/protobuf-c/protobuf-c.h $(top_builddir)/config.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/eventlog.c +eventlog.i: $(srcdir)/eventlog.c $(devdir)/log_server.pb-c.h \ + $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ + $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \ + $(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \ + $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/logsrvd.h \ + $(srcdir)/protobuf-c/protobuf-c.h $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +eventlog.plog: eventlog.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/eventlog.c --i-file $< --output-file $@ iolog_writer.o: $(srcdir)/iolog_writer.c $(devdir)/log_server.pb-c.h \ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ $(incdir)/sudo_debug.h $(incdir)/sudo_iolog.h \ diff --git a/logsrvd/eventlog.c b/logsrvd/eventlog.c new file mode 100644 index 000000000..38731741f --- /dev/null +++ b/logsrvd/eventlog.c @@ -0,0 +1,459 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 1994-1996, 1998-2019 Todd C. Miller + * + * 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. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +/* + * This is an open source non-commercial project. Dear PVS-Studio, please check it. + * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log_server.pb-c.h" +#include "sudo_gettext.h" /* must be included before sudo_compat.h */ +#include "sudo_compat.h" +#include "sudo_fatal.h" +#include "sudo_queue.h" +#include "sudo_debug.h" +#include "sudo_util.h" +#include "sudo_iolog.h" +#include "logsrvd.h" + +#define LL_HOST_STR "HOST=" +#define LL_TTY_STR "TTY=" +#define LL_CWD_STR "PWD=" +#define LL_USER_STR "USER=" +#define LL_GROUP_STR "GROUP=" +#define LL_ENV_STR "ENV=" +#define LL_CMND_STR "COMMAND=" +#define LL_TSID_STR "TSID=" + +#define IS_SESSID(s) ( \ + isalnum((unsigned char)(s)[0]) && isalnum((unsigned char)(s)[1]) && \ + (s)[2] == '/' && \ + isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \ + (s)[5] == '/' && \ + isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \ + (s)[8] == '\0') + +/* + * Allocate and fill in a new logline. + */ +static char * +new_logline(const char *message, const char *errstr, + const struct iolog_details *details) +{ + char *line = NULL, *evstr = NULL; + const char *iolog_file = details->iolog_file; + char sessid[7]; + const char *tsid = NULL; + size_t len = 0; + int i; + debug_decl(new_logline, SUDO_DEBUG_UTIL) + + /* A TSID may be a sudoers-style session ID or a free-form string. */ + if (iolog_file != NULL) { + if (IS_SESSID(iolog_file)) { + sessid[0] = iolog_file[0]; + sessid[1] = iolog_file[1]; + sessid[2] = iolog_file[3]; + sessid[3] = iolog_file[4]; + sessid[4] = iolog_file[6]; + sessid[5] = iolog_file[7]; + sessid[6] = '\0'; + tsid = sessid; + } else { + tsid = iolog_file; + } + } + + /* + * Compute line length + */ + if (message != NULL) + len += strlen(message) + 3; + if (errstr != NULL) + len += strlen(errstr) + 3; + len += sizeof(LL_HOST_STR) + 2 + strlen(details->submithost); + len += sizeof(LL_TTY_STR) + 2 + strlen(details->ttyname); + len += sizeof(LL_CWD_STR) + 2 + strlen(details->cwd); + if (details->runuser != NULL) + len += sizeof(LL_USER_STR) + 2 + strlen(details->runuser); + if (details->rungroup != NULL) + len += sizeof(LL_GROUP_STR) + 2 + strlen(details->rungroup); + if (tsid != NULL) + len += sizeof(LL_TSID_STR) + 2 + strlen(tsid); + if (details->env_add != NULL) { + size_t evlen = 0; + char * const *ep; + + for (ep = details->env_add; *ep != NULL; ep++) + evlen += strlen(*ep) + 1; + if (evlen != 0) { + if ((evstr = malloc(evlen)) == NULL) + goto oom; + ep = details->env_add; + if (strlcpy(evstr, *ep, evlen) >= evlen) + goto toobig; + while (*++ep != NULL) { + if (strlcat(evstr, " ", evlen) >= evlen || + strlcat(evstr, *ep, evlen) >= evlen) + goto toobig; + } + len += sizeof(LL_ENV_STR) + 2 + evlen; + } + } + if (details->command != NULL) { + len += sizeof(LL_CMND_STR) - 1 + strlen(details->command); + if (details->argc > 1) { + for (i = 1; i < details->argc; i++) + len += strlen(details->argv[i]) + 1; + } + } + + /* + * Allocate and build up the line. + */ + if ((line = malloc(++len)) == NULL) + goto oom; + line[0] = '\0'; + + if (message != NULL) { + if (strlcat(line, message, len) >= len || + strlcat(line, errstr ? " : " : " ; ", len) >= len) + goto toobig; + } + if (errstr != NULL) { + if (strlcat(line, errstr, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + } + if (strlcat(line, LL_HOST_STR, len) >= len || + strlcat(line, details->submithost, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + if (strlcat(line, LL_TTY_STR, len) >= len || + strlcat(line, details->ttyname, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + if (strlcat(line, LL_CWD_STR, len) >= len || + strlcat(line, details->cwd, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + if (details->runuser != NULL) { + if (strlcat(line, LL_USER_STR, len) >= len || + strlcat(line, details->runuser, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + } + if (details->rungroup != NULL) { + if (strlcat(line, LL_GROUP_STR, len) >= len || + strlcat(line, details->rungroup, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + } + if (tsid != NULL) { + if (strlcat(line, LL_TSID_STR, len) >= len || + strlcat(line, tsid, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + } + if (evstr != NULL) { + if (strlcat(line, LL_ENV_STR, len) >= len || + strlcat(line, evstr, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + free(evstr); + evstr = NULL; + } + if (details->command != NULL) { + if (strlcat(line, LL_CMND_STR, len) >= len) + goto toobig; + if (strlcat(line, details->command, len) >= len) + goto toobig; + if (details->argc > 1) { + for (i = 1; i < details->argc; i++) { + if (strlcat(line, " ", len) >= len || + strlcat(line, details->argv[i], len) >= len) + goto toobig; + } + } + } + + debug_return_str(line); +oom: + free(evstr); + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + debug_return_str(NULL); +toobig: + free(evstr); + free(line); + sudo_warnx(U_("internal error, %s overflow"), __func__); + debug_return_str(NULL); +} + +/* + * We do an openlog(3)/closelog(3) for each message because some + * authentication methods (notably PAM) use syslog(3) for their + * own nefarious purposes and may call openlog(3) and closelog(3). + * XXX - no longer need openlog/closelog dance, move openlog call + */ +static void +mysyslog(int pri, const char *fmt, ...) +{ + va_list ap; + debug_decl(mysyslog, SUDO_DEBUG_UTIL) + + openlog("sudo", 0, logsrvd_conf_syslog_facility()); + va_start(ap, fmt); + vsyslog(pri, fmt, ap); + va_end(ap); + closelog(); + debug_return; +} + +/* + * Log a message to syslog, pre-pending the username and splitting the + * message into parts if it is longer than syslog_maxlen. + */ +static void +do_syslog(int pri, const struct iolog_details *details, char *msg) +{ + size_t len, maxlen; + char *p, *tmp, save; + const char *fmt; + debug_decl(do_syslog, SUDO_DEBUG_UTIL) + + /* A priority of -1 corresponds to "none". */ + if (pri == -1) + debug_return; + + /* + * Log the full line, breaking into multiple syslog(3) calls if necessary + */ + fmt = _("%8s : %s"); + maxlen = logsrvd_conf_syslog_maxlen() - + (strlen(fmt) - 5 + strlen(details->submituser)); + for (p = msg; *p != '\0'; ) { + len = strlen(p); + if (len > maxlen) { + /* + * Break up the line into what will fit on one syslog(3) line + * Try to avoid breaking words into several lines if possible. + */ + tmp = memrchr(p, ' ', maxlen); + if (tmp == NULL) + tmp = p + maxlen; + + /* NULL terminate line, but save the char to restore later */ + save = *tmp; + *tmp = '\0'; + + mysyslog(pri, fmt, details->submituser, p); + + *tmp = save; /* restore saved character */ + + /* Advance p and eliminate leading whitespace */ + for (p = tmp; *p == ' '; p++) + continue; + } else { + mysyslog(pri, fmt, details->submituser, p); + p += len; + } + fmt = _("%8s : (command continued) %s"); + maxlen = logsrvd_conf_syslog_maxlen() - + (strlen(fmt) - 5 + strlen(details->submituser)); + } + + debug_return; +} + +static bool +do_logfile(const char *logfile, const struct iolog_details *details, + const char *msg) +{ + const char *timefmt = logsrvd_conf_logfile_time_format(); + char timebuf[8192], *timestr = NULL; + struct tm *timeptr; + bool ret = false; + mode_t oldmask; + FILE *fp; + debug_decl(do_logfile, SUDO_DEBUG_UTIL) + + oldmask = umask(S_IRWXG|S_IRWXO); + fp = fopen(logfile, "a"); + (void) umask(oldmask); + if (fp == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "unable to open log file %s", logfile); + goto done; + } + if (!sudo_lock_file(fileno(fp), SUDO_LOCK)) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "unable to lock log file %s", logfile); + goto done; + } + + if ((timeptr = localtime(&details->submit_time)) != NULL) { + /* strftime() does not guarantee to NUL-terminate so we must check. */ + timebuf[sizeof(timebuf) - 1] = '\0'; + if (strftime(timebuf, sizeof(timebuf), timefmt, timeptr) != 0 && + timebuf[sizeof(timebuf) - 1] == '\0') { + timestr = timebuf; + } + } + (void)fprintf(fp, "%s : %s : %s", timestr ? timestr : "invalid date", + details->submituser, msg); + (void)fflush(fp); + if (ferror(fp)) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "unable to write log file %s", logfile); + goto done; + } + ret = true; + +done: + if (fp != NULL) + (void) fclose(fp); + debug_return_bool(ret); +} + +bool +log_accept(const struct iolog_details *details) +{ + const enum logsrvd_eventlog_type log_type = logsrvd_conf_eventlog_type(); + char *logline; + bool ret = true; + int pri; + debug_decl(log_accept, SUDO_DEBUG_UTIL) + + if (log_type == EVLOG_NONE) + debug_return_bool(true); + + if ((logline = new_logline(NULL, NULL, details)) == NULL) + debug_return_bool(false); + + switch (log_type) { + case EVLOG_SYSLOG: + pri = logsrvd_conf_syslog_acceptpri(); + if (pri != -1) + do_syslog(pri, details, logline); + break; + case EVLOG_FILE: + ret = do_logfile(logsrvd_conf_logfile_path(), details, logline); + break; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unexpected eventlog type %d", log_type); + ret = false; + } + free(logline); + + debug_return_bool(ret); +} + +bool +log_reject(const struct iolog_details *details, const char *reason) +{ + const enum logsrvd_eventlog_type log_type = logsrvd_conf_eventlog_type(); + char *logline; + bool ret = true; + int pri; + debug_decl(log_reject, SUDO_DEBUG_UTIL) + + if (log_type == EVLOG_NONE) + debug_return_bool(true); + + if ((logline = new_logline(reason, NULL, details)) == NULL) + debug_return_bool(false); + + switch (log_type) { + case EVLOG_SYSLOG: + pri = logsrvd_conf_syslog_rejectpri(); + if (pri != -1) + do_syslog(pri, details, logline); + break; + case EVLOG_FILE: + ret = do_logfile(logsrvd_conf_logfile_path(), details, logline); + break; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unexpected eventlog type %d", log_type); + ret = false; + } + free(logline); + + debug_return_bool(ret); +} + +bool +log_alert(const struct iolog_details *details, TimeSpec *alert_time, + const char *reason) +{ + const enum logsrvd_eventlog_type log_type = logsrvd_conf_eventlog_type(); + char *logline; + bool ret = true; + int pri; + debug_decl(log_alert, SUDO_DEBUG_UTIL) + + if (log_type == EVLOG_NONE) + debug_return_bool(true); + + if ((logline = new_logline(reason, NULL, details)) == NULL) + debug_return_bool(false); + + /* TODO: log alert_time */ + switch (log_type) { + case EVLOG_SYSLOG: + pri = logsrvd_conf_syslog_alertpri(); + if (pri != -1) + do_syslog(pri, details, logline); + break; + case EVLOG_FILE: + ret = do_logfile(logsrvd_conf_logfile_path(), details, logline); + break; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unexpected eventlog type %d", log_type); + ret = false; + } + free(logline); + + debug_return_bool(ret); +} diff --git a/logsrvd/iolog_writer.c b/logsrvd/iolog_writer.c index 6f671f06a..501cb501b 100644 --- a/logsrvd/iolog_writer.c +++ b/logsrvd/iolog_writer.c @@ -63,29 +63,94 @@ has_strlistval(InfoMessage *info) } /* - * Fill in I/O log details from an AcceptMessage - * Only makes a shallow copy of strings and string lists. + * Copy the specified string list. + * The input string list need not be NULL-terminated. + * Returns a NULL-terminated string vector. */ -static bool -iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) +static char ** +strlist_copy(InfoMessage__StringList *strlist) +{ + char **dst, **src = strlist->strings; + size_t i, len = strlist->n_strings; + debug_decl(strlist_copy, SUDO_DEBUG_UTIL) + + dst = reallocarray(NULL, len + 1, sizeof(char *)); + if (dst == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "reallocarray(NULL, %zu, %zu)", len + 1, sizeof(char *)); + goto bad; + } + for (i = 0; i < len; i++) { + if ((dst[i] = strdup(src[i])) == NULL) { + sudo_debug_printf( + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, "strdup"); + goto bad; + } + } + dst[i] = NULL; + debug_return_ptr(dst); + +bad: + if (dst != NULL) { + while (i--) + free(dst[i]); + free(dst); + } + debug_return_ptr(NULL); +} + +/* + * Free the strings in a struct iolog_details. + */ +void +iolog_details_free(struct iolog_details *details) +{ + int i; + debug_decl(iolog_details_free, SUDO_DEBUG_UTIL) + + if (details != NULL) { + free(details->iolog_path); + free(details->command); + free(details->cwd); + free(details->rungroup); + free(details->runuser); + free(details->submithost); + free(details->submituser); + free(details->submitgroup); + free(details->ttyname); + for (i = 0; i < details->argc; i++) + free(details->argv[i]); + free(details->argv); + } + + debug_return; +} + +/* + * Fill in I/O log details from an AcceptMessage + * Caller is responsible for freeing strings in struct iolog_details. + * Returns true on success and false on failure. + */ +bool +iolog_details_fill(struct iolog_details *details, TimeSpec *submit_time, + InfoMessage **info_msgs, size_t infolen) { size_t idx; - bool ret = true; + bool ret = false; debug_decl(iolog_details_fill, SUDO_DEBUG_UTIL) memset(details, 0, sizeof(*details)); /* Submit time. */ - details->submit_time = msg->submit_time->tv_sec; + details->submit_time = submit_time->tv_sec; /* Default values */ details->lines = 24; details->columns = 80; - details->submitgroup = "unknown"; /* Pull out values by key from info array. */ - for (idx = 0; idx < msg->n_info_msgs; idx++) { - InfoMessage *info = msg->info_msgs[idx]; + for (idx = 0; idx < infolen; idx++) { + InfoMessage *info = info_msgs[idx]; const char *key = info->key; switch (key[0]) { case 'c': @@ -103,7 +168,12 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) } if (strcmp(key, "command") == 0) { if (has_strval(info)) { - details->command = info->strval; + if ((details->command = strdup(info->strval)) == NULL) { + sudo_debug_printf( + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "strdup"); + goto done; + } } else { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "command specified but not a string"); @@ -112,7 +182,12 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) } if (strcmp(key, "cwd") == 0) { if (has_strval(info)) { - details->cwd = info->strval; + if ((details->cwd = strdup(info->strval)) == NULL) { + sudo_debug_printf( + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "strdup"); + goto done; + } } else { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "cwd specified but not a string"); @@ -137,7 +212,9 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) case 'r': if (strcmp(key, "runargv") == 0) { if (has_strlistval(info)) { - details->argv = info->strlistval->strings; + details->argv = strlist_copy(info->strlistval); + if (details->argv == NULL) + goto done; details->argc = info->strlistval->n_strings; } else { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, @@ -147,7 +224,12 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) } if (strcmp(key, "rungroup") == 0) { if (has_strval(info)) { - details->rungroup = info->strval; + if ((details->rungroup = strdup(info->strval)) == NULL) { + sudo_debug_printf( + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "strdup"); + goto done; + } } else { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "rungroup specified but not a string"); @@ -156,7 +238,12 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) } if (strcmp(key, "runuser") == 0) { if (has_strval(info)) { - details->runuser = info->strval; + if ((details->runuser = strdup(info->strval)) == NULL) { + sudo_debug_printf( + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "strdup"); + goto done; + } } else { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "runuser specified but not a string"); @@ -167,7 +254,12 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) case 's': if (strcmp(key, "submithost") == 0) { if (has_strval(info)) { - details->submithost = info->strval; + if ((details->submithost = strdup(info->strval)) == NULL) { + sudo_debug_printf( + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "strdup"); + goto done; + } } else { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "submithost specified but not a string"); @@ -176,7 +268,12 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) } if (strcmp(key, "submitgroup") == 0) { if (has_strval(info)) { - details->submitgroup = info->strval; + if ((details->submitgroup = strdup(info->strval)) == NULL) { + sudo_debug_printf( + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "strdup"); + goto done; + } } else { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "submitgroup specified but not a string"); @@ -185,7 +282,12 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) } if (strcmp(key, "submituser") == 0) { if (has_strval(info)) { - details->submituser = info->strval; + if ((details->submituser = strdup(info->strval)) == NULL) { + sudo_debug_printf( + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "strdup"); + goto done; + } } else { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "submituser specified but not a string"); @@ -196,7 +298,12 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) case 't': if (strcmp(key, "ttyname") == 0) { if (has_strval(info)) { - details->ttyname = info->strval; + if ((details->ttyname = strdup(info->strval)) == NULL) { + sudo_debug_printf( + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "strdup"); + goto done; + } } else { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "ttyname specified but not a string"); @@ -207,23 +314,38 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) } } + /* TODO: make submitgroup required */ + if (details->submitgroup == NULL) { + if ((details->submitgroup = strdup("unknown")) == NULL) { + sudo_debug_printf( + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "strdup"); + goto done; + } + } + /* Check for required settings */ if (details->submituser == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "missing user in AcceptMessage"); - ret = false; + goto done; } if (details->submithost == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "missing host in AcceptMessage"); - ret = false; + goto done; } if (details->command == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "missing command in AcceptMessage"); - ret = false; + goto done; } + ret = true; + +done: + if (!ret) + iolog_details_free(details); debug_return_bool(ret); } @@ -351,54 +473,58 @@ static const struct iolog_path_escape path_escapes[] = { /* * Create I/O log path - * Sets iolog_dir and iolog_dir_fd in the closure + * Sets iolog_path, iolog_file and iolog_dir_fd in the closure */ static bool -create_iolog_dir(struct iolog_details *details, struct connection_closure *closure) +create_iolog_path(struct connection_closure *closure) { + struct iolog_details *details = &closure->details; char pathbuf[PATH_MAX]; - size_t len; - debug_decl(create_iolog_dir, SUDO_DEBUG_UTIL) + size_t len, pathlen; + debug_decl(create_iolog_path, SUDO_DEBUG_UTIL) - /* XXX - awkward api */ - closure->iolog_dir = expand_iolog_path(NULL, logsrvd_conf_iolog_dir(), - logsrvd_conf_iolog_file(), NULL, &path_escapes[0], details); - if (closure->iolog_dir == NULL) { + details->iolog_path = expand_iolog_path(NULL, logsrvd_conf_iolog_dir(), + logsrvd_conf_iolog_file(), &details->iolog_file, &path_escapes[0], + details); + if (details->iolog_path == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "unable to expand iolog path %s/%s", logsrvd_conf_iolog_dir(), logsrvd_conf_iolog_file()); goto bad; } + pathlen = details->iolog_file - details->iolog_path; /* * Make local copy of I/O log path and create it, along with any * intermediate subdirs. Calls mkdtemp() if iolog_path ends in XXXXXX. */ - len = mkdir_iopath(closure->iolog_dir, pathbuf, sizeof(pathbuf)); + len = mkdir_iopath(details->iolog_path, pathbuf, sizeof(pathbuf)); if (len >= sizeof(pathbuf)) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, - "unable to mkdir iolog path %s", closure->iolog_dir); + "unable to mkdir iolog path %s", details->iolog_path); goto bad; } - free(closure->iolog_dir); - if ((closure->iolog_dir = strdup(pathbuf)) == NULL) { + free(details->iolog_path); + if ((details->iolog_path = strdup(pathbuf)) == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, "strdup"); goto bad; } + details->iolog_file = details->iolog_path + pathlen + 1; /* We use iolog_dir_fd in calls to openat(2) */ closure->iolog_dir_fd = - iolog_openat(AT_FDCWD, closure->iolog_dir, O_RDONLY); + iolog_openat(AT_FDCWD, details->iolog_path, O_RDONLY); if (closure->iolog_dir_fd == -1) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, - "%s", closure->iolog_dir); + "%s", details->iolog_path); goto bad; } debug_return_bool(true); bad: - free(closure->iolog_dir); + free(details->iolog_path); + details->iolog_path = NULL; debug_return_bool(false); } @@ -424,7 +550,7 @@ iolog_details_write(struct iolog_details *details, log_info.cols = details->columns; debug_return_bool(iolog_write_info_file(closure->iolog_dir_fd, - closure->iolog_dir, &log_info, details->argv)); + details->iolog_path, &log_info, details->argv)); } static bool @@ -467,19 +593,14 @@ iolog_close_all(struct connection_closure *closure) bool iolog_init(AcceptMessage *msg, struct connection_closure *closure) { - struct iolog_details details; debug_decl(iolog_init, SUDO_DEBUG_UTIL) - /* Fill in iolog_details */ - if (!iolog_details_fill(&details, msg)) - debug_return_bool(false); - - /* Create I/O log dir */ - if (!create_iolog_dir(&details, closure)) + /* Create I/O log path */ + if (!create_iolog_path(closure)) debug_return_bool(false); /* Write sudo I/O log info file */ - if (!iolog_details_write(&details, closure)) + if (!iolog_details_write(&closure->details, closure)) debug_return_bool(false); /* @@ -541,7 +662,7 @@ iolog_restart(RestartMessage *msg, struct connection_closure *closure) target.tv_sec = msg->resume_point->tv_sec; target.tv_nsec = msg->resume_point->tv_nsec; - if ((closure->iolog_dir = strdup(msg->log_id)) == NULL) { + if ((closure->details.iolog_path = strdup(msg->log_id)) == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, "strdup"); goto bad; @@ -555,7 +676,7 @@ iolog_restart(RestartMessage *msg, struct connection_closure *closure) if (errno != ENOENT) { sudo_debug_printf( SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, - "unable to open %s/%s", closure->iolog_dir, + "unable to open %s/%s", closure->details.iolog_path, iolog_fd_to_name(iofd)); goto bad; } @@ -563,7 +684,7 @@ iolog_restart(RestartMessage *msg, struct connection_closure *closure) } if (!closure->iolog_files[IOFD_TIMING].enabled) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "missing timing file in %s", closure->iolog_dir); + "missing timing file in %s", closure->details.iolog_path); goto bad; } @@ -666,7 +787,7 @@ store_iobuf(int iofd, IoBuffer *msg, struct connection_closure *closure) if (!iolog_write(&closure->iolog_files[iofd], msg->data.data, msg->data.len, &errstr)) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to write to %s/%s: %s", closure->iolog_dir, + "unable to write to %s/%s: %s", closure->details.iolog_path, iolog_fd_to_name(iofd), errstr); debug_return_int(-1); } @@ -675,7 +796,7 @@ store_iobuf(int iofd, IoBuffer *msg, struct connection_closure *closure) if (!iolog_write(&closure->iolog_files[IOFD_TIMING], tbuf, len, &errstr)) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to write to %s/%s: %s", closure->iolog_dir, + "unable to write to %s/%s: %s", closure->details.iolog_path, iolog_fd_to_name(IOFD_TIMING), errstr); debug_return_int(-1); } @@ -707,7 +828,7 @@ store_suspend(CommandSuspend *msg, struct connection_closure *closure) if (!iolog_write(&closure->iolog_files[IOFD_TIMING], tbuf, len, &errstr)) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to write to %s/%s: %s", closure->iolog_dir, + "unable to write to %s/%s: %s", closure->details.iolog_path, iolog_fd_to_name(IOFD_TIMING), errstr); debug_return_int(-1); } @@ -739,7 +860,7 @@ store_winsize(ChangeWindowSize *msg, struct connection_closure *closure) if (!iolog_write(&closure->iolog_files[IOFD_TIMING], tbuf, len, &errstr)) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unable to write to %s/%s: %s", closure->iolog_dir, + "unable to write to %s/%s: %s", closure->details.iolog_path, iolog_fd_to_name(IOFD_TIMING), errstr); debug_return_int(-1); } diff --git a/logsrvd/logsrvd.c b/logsrvd/logsrvd.c index 426b54ee2..420de8199 100644 --- a/logsrvd/logsrvd.c +++ b/logsrvd/logsrvd.c @@ -87,9 +87,9 @@ connection_closure_free(struct connection_closure *closure) sudo_ev_free(closure->commit_ev); sudo_ev_free(closure->read_ev); sudo_ev_free(closure->write_ev); + iolog_details_free(&closure->details); free(closure->read_buf.data); free(closure->write_buf.data); - free(closure->iolog_dir); free(closure); if (shutting_down && TAILQ_EMPTY(&connections)) @@ -206,20 +206,32 @@ handle_accept(AcceptMessage *msg, struct connection_closure *closure) closure->submit_time.tv_sec = msg->submit_time->tv_sec; closure->submit_time.tv_nsec = msg->submit_time->tv_nsec; - /* TODO: handle event logging via syslog */ + if (!iolog_details_fill(&closure->details, msg->submit_time, msg->info_msgs, + msg->n_info_msgs)) { + closure->errstr = _("error parsing AcceptMessage"); + debug_return_bool(false); + } + + /* Create I/O log info file and parent directories. */ + if (msg->expect_iobufs) { + if (!iolog_init(msg, closure)) { + closure->errstr = _("error creating I/O log"); + debug_return_bool(false); + } + } + + if (!log_accept(&closure->details)) { + closure->errstr = _("error logging accept event"); + debug_return_bool(false); + } + if (!msg->expect_iobufs) { closure->state = FLUSHED; debug_return_bool(true); } - /* Create I/O log info file and parent directories. */ - if (!iolog_init(msg, closure)) { - closure->errstr = _("error creating I/O log"); - debug_return_bool(false); - } - /* Send log ID to client for restarting connectoins. */ - if (!fmt_log_id_message(closure->iolog_dir, &closure->write_buf)) + if (!fmt_log_id_message(closure->details.iolog_path, &closure->write_buf)) debug_return_bool(false); if (sudo_ev_add(NULL, closure->write_ev, NULL, false) == -1) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, @@ -260,7 +272,16 @@ handle_reject(RejectMessage *msg, struct connection_closure *closure) closure->submit_time.tv_sec = msg->submit_time->tv_sec; closure->submit_time.tv_nsec = msg->submit_time->tv_nsec; - /* TODO: handle event logging via syslog */ + if (!iolog_details_fill(&closure->details, msg->submit_time, msg->info_msgs, + msg->n_info_msgs)) { + closure->errstr = _("error parsing RejectMessage"); + debug_return_bool(false); + } + + if (!log_reject(&closure->details, msg->reason)) { + closure->errstr = _("error logging reject event"); + debug_return_bool(false); + } closure->state = FLUSHED; debug_return_bool(true); @@ -346,8 +367,12 @@ handle_alert(AlertMessage *msg, struct connection_closure *closure) { debug_decl(handle_alert, SUDO_DEBUG_UTIL) - /* TODO */ - debug_return_bool(false); + if (!log_alert(&closure->details, msg->alert_time, msg->reason)) { + closure->errstr = _("error logging alert event"); + debug_return_bool(false); + } + + debug_return_bool(true); } static bool diff --git a/logsrvd/logsrvd.h b/logsrvd/logsrvd.h index f5723cacd..65c351ccc 100644 --- a/logsrvd/logsrvd.h +++ b/logsrvd/logsrvd.h @@ -35,9 +35,10 @@ * I/O log details from the AcceptMessage + iolog path and sessid. */ struct iolog_details { + char *iolog_path; + char *iolog_file; /* substring of iolog_path, do not free */ char *command; char *cwd; - char *iolog_dir; char *rungroup; char *runuser; char *submithost; @@ -45,6 +46,7 @@ struct iolog_details { char *submitgroup; char *ttyname; char **argv; + char **env_add; time_t submit_time; int argc; int lines; @@ -78,6 +80,7 @@ struct connection_buffer { */ struct connection_closure { TAILQ_ENTRY(connection_closure) entries; + struct iolog_details details; struct timespec submit_time; struct timespec elapsed_time; struct connection_buffer read_buf; @@ -85,7 +88,6 @@ struct connection_closure { struct sudo_event *commit_ev; struct sudo_event *read_ev; struct sudo_event *write_ev; - char *iolog_dir; const char *errstr; struct iolog_file iolog_files[IOFD_MAX]; int iolog_dir_fd; @@ -111,18 +113,46 @@ struct listen_address { }; TAILQ_HEAD(listen_address_list, listen_address); +/* Supported eventlog types */ +enum logsrvd_eventlog_type { + EVLOG_NONE, + EVLOG_SYSLOG, + EVLOG_FILE, +}; + +/* Supported eventlog formats (currently just sudo) */ +enum logsrvd_eventlog_format { + EVLOG_SUDO +}; + +/* eventlog.c */ +bool log_accept(const struct iolog_details *details); +bool log_reject(const struct iolog_details *details, const char *reason); +bool log_alert(const struct iolog_details *details, TimeSpec *alert_time, const char *reason); + /* iolog_writer.c */ +bool iolog_details_fill(struct iolog_details *details, TimeSpec *submit_time, InfoMessage **info_msgs, size_t infolen); bool iolog_init(AcceptMessage *msg, struct connection_closure *closure); bool iolog_restart(RestartMessage *msg, struct connection_closure *closure); int store_iobuf(int iofd, IoBuffer *msg, struct connection_closure *closure); int store_suspend(CommandSuspend *msg, struct connection_closure *closure); int store_winsize(ChangeWindowSize *msg, struct connection_closure *closure); void iolog_close_all(struct connection_closure *closure); +void iolog_details_free(struct iolog_details *details); /* logsrvd_conf.c */ bool logsrvd_conf_read(const char *path); const char *logsrvd_conf_iolog_dir(void); const char *logsrvd_conf_iolog_file(void); struct listen_address_list *logsrvd_conf_listen_address(void); +enum logsrvd_eventlog_type logsrvd_conf_eventlog_type(void); +enum logsrvd_eventlog_format logsrvd_conf_eventlog_format(void); +unsigned int logsrvd_conf_syslog_maxlen(void); +int logsrvd_conf_syslog_facility(void); +int logsrvd_conf_syslog_acceptpri(void); +int logsrvd_conf_syslog_rejectpri(void); +int logsrvd_conf_syslog_alertpri(void); +const char *logsrvd_conf_logfile_path(void); +const char *logsrvd_conf_logfile_time_format(void); #endif /* SUDO_LOGSRVD_H */ diff --git a/logsrvd/logsrvd_conf.c b/logsrvd/logsrvd_conf.c index 900904631..bc09faace 100644 --- a/logsrvd/logsrvd_conf.c +++ b/logsrvd/logsrvd_conf.c @@ -64,30 +64,114 @@ struct logsrvd_config_section { struct logsrvd_config_entry *entries; }; -static char *logsrvd_iolog_dir; +static struct logsrvd_config { + struct logsrvd_config_server { + struct listen_address_list addresses; + } server; + struct logsrvd_config_iolog { + /* XXX - others private to iolog */ + char *iolog_dir; + char *iolog_file; + } iolog; + struct logsrvd_config_eventlog { + enum logsrvd_eventlog_type log_type; + enum logsrvd_eventlog_format log_format; + } eventlog; + struct logsrvd_config_syslog { + unsigned int maxlen; + int facility; + int acceptpri; + int rejectpri; + int alertpri; + } syslog; + struct logsrvd_config_logfile { + char *path; + char *time_format; + } logfile; +} logsrvd_config = { + { TAILQ_HEAD_INITIALIZER(logsrvd_config.server.addresses) } +}; +/* iolog getters */ const char * logsrvd_conf_iolog_dir(void) { - return logsrvd_iolog_dir; + return logsrvd_config.iolog.iolog_dir; } -static char *logsrvd_iolog_file; - const char * logsrvd_conf_iolog_file(void) { - return logsrvd_iolog_file; + return logsrvd_config.iolog.iolog_file; } -static struct listen_address_list addresses = TAILQ_HEAD_INITIALIZER(addresses); - +/* server getters */ struct listen_address_list * logsrvd_conf_listen_address(void) { - return &addresses; + return &logsrvd_config.server.addresses; } +/* eventlog getters */ +enum logsrvd_eventlog_type +logsrvd_conf_eventlog_type(void) +{ + return logsrvd_config.eventlog.log_type; +} + +enum logsrvd_eventlog_format +logsrvd_conf_eventlog_format(void) +{ + return logsrvd_config.eventlog.log_format; +} + +/* syslog getters */ +unsigned int +logsrvd_conf_syslog_maxlen(void) +{ + return logsrvd_config.syslog.maxlen; +} + +int +logsrvd_conf_syslog_facility(void) +{ + return logsrvd_config.syslog.facility; +} + +int +logsrvd_conf_syslog_acceptpri(void) +{ + return logsrvd_config.syslog.acceptpri; +} + +int +logsrvd_conf_syslog_rejectpri(void) +{ + return logsrvd_config.syslog.rejectpri; +} + +int +logsrvd_conf_syslog_alertpri(void) +{ + return logsrvd_config.syslog.alertpri; +} + +/* logfile getters */ +const char * +logsrvd_conf_logfile_path(void) +{ + return logsrvd_config.logfile.path; +} + +const char * +logsrvd_conf_logfile_time_format(void) +{ + return logsrvd_config.logfile.time_format; +} + +/* + * Reset logsrvd_config to default values and reset I/O log values. + */ static void logsrvd_conf_reset(void) { @@ -95,26 +179,30 @@ logsrvd_conf_reset(void) debug_decl(logsrvd_conf_reset, SUDO_DEBUG_UTIL) iolog_set_defaults(); - free(logsrvd_iolog_dir); - logsrvd_iolog_dir = NULL; - free(logsrvd_iolog_file); - logsrvd_iolog_file = NULL; + free(logsrvd_config.iolog.iolog_dir); + logsrvd_config.iolog.iolog_dir = NULL; + free(logsrvd_config.iolog.iolog_file); + logsrvd_config.iolog.iolog_file = NULL; - while ((addr = TAILQ_FIRST(&addresses))) { - TAILQ_REMOVE(&addresses, addr, entries); + while ((addr = TAILQ_FIRST(&logsrvd_config.server.addresses))) { + TAILQ_REMOVE(&logsrvd_config.server.addresses, addr, entries); free(addr); } + free(logsrvd_config.logfile.path); + free(logsrvd_config.logfile.time_format); + debug_return; } +/* I/O log callbacks */ static bool cb_iolog_dir(const char *path) { debug_decl(cb_iolog_dir, SUDO_DEBUG_UTIL) - free(logsrvd_iolog_dir); - if ((logsrvd_iolog_dir = strdup(path)) == NULL) { + free(logsrvd_config.iolog.iolog_dir); + if ((logsrvd_config.iolog.iolog_dir = strdup(path)) == NULL) { sudo_warn(NULL); debug_return_bool(false); } @@ -126,8 +214,8 @@ cb_iolog_file(const char *path) { debug_decl(cb_iolog_file, SUDO_DEBUG_UTIL) - free(logsrvd_iolog_file); - if ((logsrvd_iolog_file = strdup(path)) == NULL) { + free(logsrvd_config.iolog.iolog_file); + if ((logsrvd_config.iolog.iolog_file = strdup(path)) == NULL) { sudo_warn(NULL); debug_return_bool(false); } @@ -192,6 +280,13 @@ cb_iolog_mode(const char *str) debug_return_bool(iolog_set_mode(mode)); } +static bool +cb_iolog_maxseq(const char *str) +{ + return iolog_set_maxseq(str); +} + +/* Server callbacks */ /* TODO: unit test */ static bool cb_listen_address(const char *str) @@ -256,7 +351,7 @@ cb_listen_address(const char *str) } memcpy(&addr->sa_un, res->ai_addr, res->ai_addrlen); addr->sa_len = res->ai_addrlen; - TAILQ_INSERT_TAIL(&addresses, addr, entries); + TAILQ_INSERT_TAIL(&logsrvd_config.server.addresses, addr, entries); } ret = true; @@ -267,10 +362,157 @@ done: debug_return_bool(ret); } +/* eventlog callbacks */ static bool -cb_maxseq(const char *str) +cb_eventlog_type(const char *str) { - return iolog_set_maxseq(str); + debug_decl(cb_eventlog_type, SUDO_DEBUG_UTIL) + + if (strcmp(str, "none") == 0) + logsrvd_config.eventlog.log_type = EVLOG_NONE; + else if (strcmp(str, "syslog") == 0) + logsrvd_config.eventlog.log_type = EVLOG_SYSLOG; + else if (strcmp(str, "logfile") == 0) + logsrvd_config.eventlog.log_type = EVLOG_FILE; + else + debug_return_bool(false); + + debug_return_bool(true); +} + +static bool +cb_eventlog_format(const char *str) +{ + debug_decl(cb_eventlog_format, SUDO_DEBUG_UTIL) + + if (strcmp(str, "sudo") == 0) + logsrvd_config.eventlog.log_format = EVLOG_SUDO; + else + debug_return_bool(false); + + debug_return_bool(true); +} + +/* syslog callbacks */ +static bool +cb_syslog_maxlen(const char *str) +{ + unsigned int maxlen; + const char *errstr; + debug_decl(cb_syslog_maxlen, SUDO_DEBUG_UTIL) + + maxlen = sudo_strtonum(str, 1, UINT_MAX, &errstr); + if (errstr != NULL) + debug_return_bool(false); + + logsrvd_config.syslog.maxlen = maxlen; + + debug_return_bool(true); +} + +static bool +cb_syslog_facility(const char *str) +{ + int logfac; + debug_decl(cb_syslog_facility, SUDO_DEBUG_UTIL) + + if (!sudo_str2logfac(str, &logfac)) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "invalid syslog priority %s", str); + debug_return_bool(false); + } + + logsrvd_config.syslog.facility = logfac; + + debug_return_bool(true); +} + +static bool +cb_syslog_acceptpri(const char *str) +{ + int logpri; + debug_decl(cb_syslog_acceptpri, SUDO_DEBUG_UTIL) + + if (!sudo_str2logpri(str, &logpri)) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "invalid syslog priority %s", str); + debug_return_bool(false); + } + + logsrvd_config.syslog.acceptpri = logpri; + + debug_return_bool(true); +} + +static bool +cb_syslog_rejectpri(const char *str) +{ + int logpri; + debug_decl(cb_syslog_rejectpri, SUDO_DEBUG_UTIL) + + if (!sudo_str2logpri(str, &logpri)) + debug_return_bool(false); + + logsrvd_config.syslog.rejectpri = logpri; + + debug_return_bool(true); +} + +static bool +cb_syslog_alertpri(const char *str) +{ + int logpri; + debug_decl(cb_syslog_alertpri, SUDO_DEBUG_UTIL) + + if (!sudo_str2logpri(str, &logpri)) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "invalid syslog priority %s", str); + debug_return_bool(false); + } + + logsrvd_config.syslog.alertpri = logpri; + + debug_return_bool(true); +} + +/* logfile callbacks */ +static bool +cb_logfile_path(const char *str) +{ + char *copy = NULL; + debug_decl(cb_logfile_path, SUDO_DEBUG_UTIL) + + if (*str != '/') { + debug_return_bool(false); + sudo_warnx(U_("%s: not a fully qualified path"), str); + debug_return_bool(false); + } + if ((copy = strdup(str)) == NULL) { + sudo_warn(NULL); + debug_return_bool(false); + } + + free(logsrvd_config.logfile.path); + logsrvd_config.logfile.path = copy; + + debug_return_bool(true); +} + +static bool +cb_logfile_time_format(const char *str) +{ + char *copy = NULL; + debug_decl(cb_logfile_time_format, SUDO_DEBUG_UTIL) + + if ((copy = strdup(str)) == NULL) { + sudo_warn(NULL); + debug_return_bool(false); + } + + free(logsrvd_config.logfile.time_format); + logsrvd_config.logfile.time_format = copy; + + debug_return_bool(true); } static struct logsrvd_config_entry server_conf_entries[] = { @@ -286,13 +528,37 @@ static struct logsrvd_config_entry iolog_conf_entries[] = { { "iolog_user", cb_iolog_user }, { "iolog_group", cb_iolog_group }, { "iolog_mode", cb_iolog_mode }, - { "maxseq", cb_maxseq }, + { "maxseq", cb_iolog_maxseq }, + { NULL } +}; + +static struct logsrvd_config_entry eventlog_conf_entries[] = { + { "log_type", cb_eventlog_type }, + { "log_format", cb_eventlog_format }, + { NULL } +}; + +static struct logsrvd_config_entry syslog_conf_entries[] = { + { "maxlen", cb_syslog_maxlen }, + { "facility", cb_syslog_facility }, + { "reject_priority", cb_syslog_rejectpri }, + { "accept_priority", cb_syslog_acceptpri }, + { "alert_priority", cb_syslog_alertpri }, + { NULL } +}; + +static struct logsrvd_config_entry logfile_conf_entries[] = { + { "path", cb_logfile_path }, + { "time_format", cb_logfile_time_format }, { NULL } }; static struct logsrvd_config_section logsrvd_config_sections[] = { { "server", server_conf_entries }, { "iolog", iolog_conf_entries }, + { "eventlog", eventlog_conf_entries }, + { "syslog", syslog_conf_entries }, + { "logfile", logfile_conf_entries }, { NULL } }; @@ -300,7 +566,7 @@ static struct logsrvd_config_section logsrvd_config_sections[] = { * Read .ini style logsrvd.conf file. * Note that we use '#' not ';' for the comment character. */ -/* XXX - on reload we should preserve old config if there is an error */ +/* XXX - split into read and apply so we don't overwrite good config with bad */ bool logsrvd_conf_read(const char *path) { @@ -318,7 +584,27 @@ logsrvd_conf_read(const char *path) debug_return_bool(false); } + /* Initialize default values for settings that take int values. */ logsrvd_conf_reset(); + logsrvd_config.eventlog.log_type = EVLOG_SYSLOG; + logsrvd_config.eventlog.log_format = EVLOG_SUDO; + logsrvd_config.syslog.maxlen = 960; + if (!cb_syslog_facility(LOGFAC)) { + sudo_warnx(U_("unknown syslog facility %s"), LOGFAC); + debug_return_bool(false); + } + if (!cb_syslog_acceptpri(PRI_SUCCESS)) { + sudo_warnx(U_("unknown syslog priority %s"), PRI_SUCCESS); + debug_return_bool(false); + } + if (!cb_syslog_rejectpri(PRI_FAILURE)) { + sudo_warnx(U_("unknown syslog priority %s"), PRI_FAILURE); + debug_return_bool(false); + } + if (!cb_syslog_alertpri(PRI_FAILURE)) { + sudo_warnx(U_("unknown syslog priority %s"), PRI_FAILURE); + debug_return_bool(false); + } while (sudo_parseln(&line, &linesize, &lineno, fp, 0) != -1) { struct logsrvd_config_entry *entry; @@ -386,23 +672,27 @@ logsrvd_conf_read(const char *path) } } - /* All the others have default values. */ - if (logsrvd_iolog_dir == NULL) { - if ((logsrvd_iolog_dir = strdup(_PATH_SUDO_IO_LOGDIR)) == NULL) { - sudo_warn(NULL); + /* For settings with pointer values we can tell what is unset. */ + if (logsrvd_config.iolog.iolog_dir == NULL) { + if (!cb_iolog_dir(_PATH_SUDO_IO_LOGDIR)) debug_return_bool(false); - } } - if (logsrvd_iolog_file == NULL) { - if ((logsrvd_iolog_file = strdup("%{seq}")) == NULL) { - sudo_warn(NULL); + if (logsrvd_config.iolog.iolog_file == NULL) { + if (!cb_iolog_file("%{seq}")) debug_return_bool(false); - } } - if (TAILQ_EMPTY(&addresses)) { + if (TAILQ_EMPTY(&logsrvd_config.server.addresses)) { if (!cb_listen_address("*:30344")) debug_return_bool(false); } + if (logsrvd_config.logfile.time_format == NULL) { + if (!cb_logfile_time_format("%h %e %T")) + debug_return_bool(false); + } + if (logsrvd_config.logfile.path == NULL) { + if (!cb_logfile_path(_PATH_SUDO_LOGFILE)) + debug_return_bool(false); + } debug_return_bool(true); } diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c index edf96bc29..6fd3899b5 100644 --- a/plugins/sudoers/defaults.c +++ b/plugins/sudoers/defaults.c @@ -46,45 +46,6 @@ #include "sudoers.h" #include -/* - * For converting between syslog numbers and strings. - */ -struct strmap { - char *name; - int num; -}; - -static struct strmap facilities[] = { -#ifdef LOG_AUTHPRIV - { "authpriv", LOG_AUTHPRIV }, -#endif - { "auth", LOG_AUTH }, - { "daemon", LOG_DAEMON }, - { "user", LOG_USER }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, -1 } -}; - -static struct strmap priorities[] = { - { "alert", LOG_ALERT }, - { "crit", LOG_CRIT }, - { "debug", LOG_DEBUG }, - { "emerg", LOG_EMERG }, - { "err", LOG_ERR }, - { "info", LOG_INFO }, - { "notice", LOG_NOTICE }, - { "warning", LOG_WARNING }, - { "none", -1 }, - { NULL, -1 } -}; - static struct early_default early_defaults[] = { { I_IGNORE_UNKNOWN_DEFAULTS }, #ifdef FQDN @@ -113,8 +74,6 @@ static bool store_tuple(const char *str, union sudo_defs_val *sd_un, struct def_ static bool store_uint(const char *str, union sudo_defs_val *sd_un); static bool store_timespec(const char *str, union sudo_defs_val *sd_un); static bool list_op(const char *str, size_t, union sudo_defs_val *sd_un, enum list_ops op); -static const char *logfac2str(int); -static const char *logpri2str(int); /* * Table describing compile-time and run-time options. @@ -150,14 +109,14 @@ dump_defaults(void) case T_LOGFAC: if (cur->sd_un.ival) { sudo_printf(SUDO_CONV_INFO_MSG, desc, - logfac2str(cur->sd_un.ival)); + sudo_logfac2str(cur->sd_un.ival)); sudo_printf(SUDO_CONV_INFO_MSG, "\n"); } break; case T_LOGPRI: if (cur->sd_un.ival) { sudo_printf(SUDO_CONV_INFO_MSG, desc, - logpri2str(cur->sd_un.ival)); + sudo_logpri2str(cur->sd_un.ival)); sudo_printf(SUDO_CONV_INFO_MSG, "\n"); } break; @@ -990,63 +949,25 @@ store_list(const char *str, union sudo_defs_val *sd_un, int op) static bool store_syslogfac(const char *str, union sudo_defs_val *sd_un) { - struct strmap *fac; debug_decl(store_syslogfac, SUDOERS_DEBUG_DEFAULTS) if (str == NULL) { sd_un->ival = false; debug_return_bool(true); } - for (fac = facilities; fac->name != NULL; fac++) { - if (strcmp(str, fac->name) == 0) { - sd_un->ival = fac->num; - debug_return_bool(true); - } - } - debug_return_bool(false); /* not found */ -} - -static const char * -logfac2str(int n) -{ - struct strmap *fac; - debug_decl(logfac2str, SUDOERS_DEBUG_DEFAULTS) - - for (fac = facilities; fac->name && fac->num != n; fac++) - continue; - debug_return_const_str(fac->name); + debug_return_bool(sudo_str2logfac(str, &sd_un->ival)); } static bool store_syslogpri(const char *str, union sudo_defs_val *sd_un) { - struct strmap *pri; debug_decl(store_syslogpri, SUDOERS_DEBUG_DEFAULTS) if (str == NULL) { sd_un->ival = -1; debug_return_bool(true); } - for (pri = priorities; pri->name != NULL; pri++) { - if (strcmp(str, pri->name) == 0) { - sd_un->ival = pri->num; - debug_return_bool(true); - } - } - debug_return_bool(false); /* not found */ -} - -static const char * -logpri2str(int n) -{ - struct strmap *pri; - debug_decl(logpri2str, SUDOERS_DEBUG_DEFAULTS) - - for (pri = priorities; pri->name != NULL; pri++) { - if (pri->num == n) - debug_return_const_str(pri->name); - } - debug_return_const_str("unknown"); + debug_return_bool(sudo_str2logpri(str, &sd_un->ival)); } static bool