Add basic support for event logging using a sudo-style log format.

This commit is contained in:
Todd C. Miller
2019-10-24 20:04:32 -06:00
parent 402820e8cf
commit 76eec78a33
14 changed files with 1330 additions and 199 deletions

View File

@@ -120,6 +120,8 @@ lib/util/isblank.c
lib/util/key_val.c lib/util/key_val.c
lib/util/lbuf.c lib/util/lbuf.c
lib/util/locking.c lib/util/locking.c
lib/util/logfac.c
lib/util/logpri.c
lib/util/memrchr.c lib/util/memrchr.c
lib/util/memset_s.c lib/util/memset_s.c
lib/util/mkdir_parents.c lib/util/mkdir_parents.c
@@ -243,6 +245,7 @@ logsrvd/Makefile.in
logsrvd/log_server.pb-c.c logsrvd/log_server.pb-c.c
logsrvd/log_server.pb-c.h logsrvd/log_server.pb-c.h
logsrvd/log_server.proto logsrvd/log_server.proto
logsrvd/eventlog.c
logsrvd/iolog_writer.c logsrvd/iolog_writer.c
logsrvd/logsrvd.c logsrvd/logsrvd.c
logsrvd/logsrvd.h logsrvd/logsrvd.h

View File

@@ -6,12 +6,12 @@
# The host name or IP address and port to listen on. If no port is # The host name or IP address and port to listen on. If no port is
# specified, port 30344 will be used. # specified, port 30344 will be used.
# The following forms are accepted: # The following forms are accepted:
# listent_address = hostname # listen_address = hostname
# listent_address = hostname:port # listen_address = hostname:port
# listent_address = IPv4_address # listen_address = IPv4_address
# listent_address = IPv4_address:port # listen_address = IPv4_address:port
# listent_address = [IPv6_address] # listen_address = [IPv6_address]
# listent_address = [IPv6_address]:port # listen_address = [IPv6_address]:port
# #
# Multiple listen_address settings may be specified. # Multiple listen_address settings may be specified.
# The default is to listen on all addresses. # The default is to listen on all addresses.
@@ -20,21 +20,21 @@
[iolog] [iolog]
# The top-level directory to use when constructing the path name for the # 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. # 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. # The path name, relative to iolog_dir, in which to store I/O logs.
# Note that iolog_file may contain directory components. # 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 # 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 # buffering it. This makes it possible to view the logs in real-time
# as the program is executing but may significantly reduce the effectiveness # as the program is executing but may significantly reduce the effectiveness
# of I/O log compression. # of I/O log compression.
iolog_flush = true #iolog_flush = true
# If set, I/O logs will be compressed using zlib. Enabling compression can # 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. # 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 # 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 # 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 # 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 # creating I/O log directories, search (execute) bits are added to match
# the read and write bits specified by iolog_mode. # 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} # 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 # 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 # base 36, maxseq itself should be expressed in decimal. Values larger
# than 2176782336 (which corresponds to the base 36 sequence number # than 2176782336 (which corresponds to the base 36 sequence number
# ZZZZZZ) will be silently truncated to 2176782336. # 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

View File

@@ -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); __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)) #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 */ /* mkdir_parents.c */
__dso_public bool sudo_mkdir_parents_v1(char *path, uid_t uid, gid_t gid, mode_t mode, bool quiet); __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)) #define sudo_mkdir_parents(_a, _b, _c, _d, _e) sudo_mkdir_parents_v1((_a), (_b), (_c), (_d), (_e))

View File

@@ -117,10 +117,11 @@ SHELL = @SHELL@
LTOBJS = @DIGEST@ event.lo fatal.lo key_val.lo gethostname.lo \ LTOBJS = @DIGEST@ event.lo fatal.lo key_val.lo gethostname.lo \
gettime.lo getgrouplist.lo gidlist.lo lbuf.lo locking.lo \ gettime.lo getgrouplist.lo gidlist.lo lbuf.lo locking.lo \
mkdir_parents.lo parseln.lo progname.lo secure_path.lo \ logfac.lo logpri.lo mkdir_parents.lo parseln.lo progname.lo \
setgroups.lo strsplit.lo strtobool.lo strtoid.lo strtomode.lo \ secure_path.lo setgroups.lo strsplit.lo strtobool.lo \
strtonum.lo sudo_conf.lo sudo_debug.lo sudo_dso.lo term.lo \ strtoid.lo strtomode.lo strtonum.lo sudo_conf.lo \
ttyname_dev.lo ttysize.lo @COMMON_OBJS@ @LTLIBOBJS@ sudo_debug.lo sudo_dso.lo term.lo ttyname_dev.lo \
ttysize.lo @COMMON_OBJS@ @LTLIBOBJS@
IOBJS = $(LTOBJS:.lo=.i) IOBJS = $(LTOBJS:.lo=.i)
@@ -771,6 +772,26 @@ locking.i: $(srcdir)/locking.c $(incdir)/compat/stdbool.h \
$(CC) -E -o $@ $(CPPFLAGS) $< $(CC) -E -o $@ $(CPPFLAGS) $<
locking.plog: locking.i 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 $@ 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 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 $(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 memrchr.i: $(srcdir)/memrchr.c $(incdir)/sudo_compat.h $(top_builddir)/config.h

93
lib/util/logfac.c Normal file
View File

@@ -0,0 +1,93 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 1999-2005, 2007-2019
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* 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 <config.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#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);
}

88
lib/util/logpri.c Normal file
View File

@@ -0,0 +1,88 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 1999-2005, 2007-2019
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* 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 <config.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#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);
}

View File

@@ -88,6 +88,8 @@ sudo_lbuf_init_v1
sudo_lbuf_print_v1 sudo_lbuf_print_v1
sudo_lock_file_v1 sudo_lock_file_v1
sudo_lock_region_v1 sudo_lock_region_v1
sudo_logfac2str_v1
sudo_logpri2str_v1
sudo_mkdir_parents_v1 sudo_mkdir_parents_v1
sudo_new_key_val_v1 sudo_new_key_val_v1
sudo_parse_gids_v1 sudo_parse_gids_v1
@@ -96,6 +98,8 @@ sudo_parseln_v2
sudo_secure_dir_v1 sudo_secure_dir_v1
sudo_secure_file_v1 sudo_secure_file_v1
sudo_setgroups_v1 sudo_setgroups_v1
sudo_str2logfac_v1
sudo_str2logpri_v1
sudo_strsplit_v1 sudo_strsplit_v1
sudo_strtobool_v1 sudo_strtobool_v1
sudo_strtoid_v1 sudo_strtoid_v1

View File

@@ -107,7 +107,7 @@ SHELL = @SHELL@
PROGS = sudo_logsrvd sudo_sendlog 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 logsrvd_conf.o log_server.pb-c.o protobuf-c.o
SENDLOG_OBJS = sendlog.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 cleandir: realclean
# Autogenerated dependencies, do not modify # 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 \ iolog_writer.o: $(srcdir)/iolog_writer.c $(devdir)/log_server.pb-c.h \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_debug.h $(incdir)/sudo_iolog.h \ $(incdir)/sudo_debug.h $(incdir)/sudo_iolog.h \

459
logsrvd/eventlog.c Normal file
View File

@@ -0,0 +1,459 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 1994-1996, 1998-2019 Todd C. Miller <Todd.Miller@sudo.ws>
*
* 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 <config.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#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);
}

View File

@@ -63,29 +63,94 @@ has_strlistval(InfoMessage *info)
} }
/* /*
* Fill in I/O log details from an AcceptMessage * Copy the specified string list.
* Only makes a shallow copy of strings and string lists. * The input string list need not be NULL-terminated.
* Returns a NULL-terminated string vector.
*/ */
static bool static char **
iolog_details_fill(struct iolog_details *details, AcceptMessage *msg) 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; size_t idx;
bool ret = true; bool ret = false;
debug_decl(iolog_details_fill, SUDO_DEBUG_UTIL) debug_decl(iolog_details_fill, SUDO_DEBUG_UTIL)
memset(details, 0, sizeof(*details)); memset(details, 0, sizeof(*details));
/* Submit time. */ /* Submit time. */
details->submit_time = msg->submit_time->tv_sec; details->submit_time = submit_time->tv_sec;
/* Default values */ /* Default values */
details->lines = 24; details->lines = 24;
details->columns = 80; details->columns = 80;
details->submitgroup = "unknown";
/* Pull out values by key from info array. */ /* Pull out values by key from info array. */
for (idx = 0; idx < msg->n_info_msgs; idx++) { for (idx = 0; idx < infolen; idx++) {
InfoMessage *info = msg->info_msgs[idx]; InfoMessage *info = info_msgs[idx];
const char *key = info->key; const char *key = info->key;
switch (key[0]) { switch (key[0]) {
case 'c': case 'c':
@@ -103,7 +168,12 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg)
} }
if (strcmp(key, "command") == 0) { if (strcmp(key, "command") == 0) {
if (has_strval(info)) { 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 { } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"command specified but not a string"); "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 (strcmp(key, "cwd") == 0) {
if (has_strval(info)) { 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 { } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"cwd specified but not a string"); "cwd specified but not a string");
@@ -137,7 +212,9 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg)
case 'r': case 'r':
if (strcmp(key, "runargv") == 0) { if (strcmp(key, "runargv") == 0) {
if (has_strlistval(info)) { 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; details->argc = info->strlistval->n_strings;
} else { } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, 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 (strcmp(key, "rungroup") == 0) {
if (has_strval(info)) { 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 { } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"rungroup specified but not a string"); "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 (strcmp(key, "runuser") == 0) {
if (has_strval(info)) { 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 { } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"runuser specified but not a string"); "runuser specified but not a string");
@@ -167,7 +254,12 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg)
case 's': case 's':
if (strcmp(key, "submithost") == 0) { if (strcmp(key, "submithost") == 0) {
if (has_strval(info)) { 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 { } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"submithost specified but not a string"); "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 (strcmp(key, "submitgroup") == 0) {
if (has_strval(info)) { 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 { } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"submitgroup specified but not a string"); "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 (strcmp(key, "submituser") == 0) {
if (has_strval(info)) { 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 { } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"submituser specified but not a string"); "submituser specified but not a string");
@@ -196,7 +298,12 @@ iolog_details_fill(struct iolog_details *details, AcceptMessage *msg)
case 't': case 't':
if (strcmp(key, "ttyname") == 0) { if (strcmp(key, "ttyname") == 0) {
if (has_strval(info)) { 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 { } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"ttyname specified but not a string"); "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 */ /* Check for required settings */
if (details->submituser == NULL) { if (details->submituser == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"missing user in AcceptMessage"); "missing user in AcceptMessage");
ret = false; goto done;
} }
if (details->submithost == NULL) { if (details->submithost == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"missing host in AcceptMessage"); "missing host in AcceptMessage");
ret = false; goto done;
} }
if (details->command == NULL) { if (details->command == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"missing command in AcceptMessage"); "missing command in AcceptMessage");
ret = false; goto done;
} }
ret = true;
done:
if (!ret)
iolog_details_free(details);
debug_return_bool(ret); debug_return_bool(ret);
} }
@@ -351,54 +473,58 @@ static const struct iolog_path_escape path_escapes[] = {
/* /*
* Create I/O log path * 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 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]; char pathbuf[PATH_MAX];
size_t len; size_t len, pathlen;
debug_decl(create_iolog_dir, SUDO_DEBUG_UTIL) debug_decl(create_iolog_path, SUDO_DEBUG_UTIL)
/* XXX - awkward api */ details->iolog_path = expand_iolog_path(NULL, logsrvd_conf_iolog_dir(),
closure->iolog_dir = expand_iolog_path(NULL, logsrvd_conf_iolog_dir(), logsrvd_conf_iolog_file(), &details->iolog_file, &path_escapes[0],
logsrvd_conf_iolog_file(), NULL, &path_escapes[0], details); details);
if (closure->iolog_dir == NULL) { if (details->iolog_path == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to expand iolog path %s/%s", "unable to expand iolog path %s/%s",
logsrvd_conf_iolog_dir(), logsrvd_conf_iolog_file()); logsrvd_conf_iolog_dir(), logsrvd_conf_iolog_file());
goto bad; goto bad;
} }
pathlen = details->iolog_file - details->iolog_path;
/* /*
* Make local copy of I/O log path and create it, along with any * Make local copy of I/O log path and create it, along with any
* intermediate subdirs. Calls mkdtemp() if iolog_path ends in XXXXXX. * 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)) { if (len >= sizeof(pathbuf)) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, 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; goto bad;
} }
free(closure->iolog_dir); free(details->iolog_path);
if ((closure->iolog_dir = strdup(pathbuf)) == NULL) { if ((details->iolog_path = strdup(pathbuf)) == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"strdup"); "strdup");
goto bad; goto bad;
} }
details->iolog_file = details->iolog_path + pathlen + 1;
/* We use iolog_dir_fd in calls to openat(2) */ /* We use iolog_dir_fd in calls to openat(2) */
closure->iolog_dir_fd = 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) { if (closure->iolog_dir_fd == -1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"%s", closure->iolog_dir); "%s", details->iolog_path);
goto bad; goto bad;
} }
debug_return_bool(true); debug_return_bool(true);
bad: bad:
free(closure->iolog_dir); free(details->iolog_path);
details->iolog_path = NULL;
debug_return_bool(false); debug_return_bool(false);
} }
@@ -424,7 +550,7 @@ iolog_details_write(struct iolog_details *details,
log_info.cols = details->columns; log_info.cols = details->columns;
debug_return_bool(iolog_write_info_file(closure->iolog_dir_fd, 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 static bool
@@ -467,19 +593,14 @@ iolog_close_all(struct connection_closure *closure)
bool bool
iolog_init(AcceptMessage *msg, struct connection_closure *closure) iolog_init(AcceptMessage *msg, struct connection_closure *closure)
{ {
struct iolog_details details;
debug_decl(iolog_init, SUDO_DEBUG_UTIL) debug_decl(iolog_init, SUDO_DEBUG_UTIL)
/* Fill in iolog_details */ /* Create I/O log path */
if (!iolog_details_fill(&details, msg)) if (!create_iolog_path(closure))
debug_return_bool(false);
/* Create I/O log dir */
if (!create_iolog_dir(&details, closure))
debug_return_bool(false); debug_return_bool(false);
/* Write sudo I/O log info file */ /* Write sudo I/O log info file */
if (!iolog_details_write(&details, closure)) if (!iolog_details_write(&closure->details, closure))
debug_return_bool(false); 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_sec = msg->resume_point->tv_sec;
target.tv_nsec = msg->resume_point->tv_nsec; 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, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"strdup"); "strdup");
goto bad; goto bad;
@@ -555,7 +676,7 @@ iolog_restart(RestartMessage *msg, struct connection_closure *closure)
if (errno != ENOENT) { if (errno != ENOENT) {
sudo_debug_printf( sudo_debug_printf(
SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, 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)); iolog_fd_to_name(iofd));
goto bad; goto bad;
} }
@@ -563,7 +684,7 @@ iolog_restart(RestartMessage *msg, struct connection_closure *closure)
} }
if (!closure->iolog_files[IOFD_TIMING].enabled) { if (!closure->iolog_files[IOFD_TIMING].enabled) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, 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; 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, if (!iolog_write(&closure->iolog_files[iofd], msg->data.data,
msg->data.len, &errstr)) { msg->data.len, &errstr)) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, 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); iolog_fd_to_name(iofd), errstr);
debug_return_int(-1); 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, if (!iolog_write(&closure->iolog_files[IOFD_TIMING], tbuf,
len, &errstr)) { len, &errstr)) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, 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); iolog_fd_to_name(IOFD_TIMING), errstr);
debug_return_int(-1); 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, if (!iolog_write(&closure->iolog_files[IOFD_TIMING], tbuf,
len, &errstr)) { len, &errstr)) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, 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); iolog_fd_to_name(IOFD_TIMING), errstr);
debug_return_int(-1); 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, if (!iolog_write(&closure->iolog_files[IOFD_TIMING], tbuf,
len, &errstr)) { len, &errstr)) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, 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); iolog_fd_to_name(IOFD_TIMING), errstr);
debug_return_int(-1); debug_return_int(-1);
} }

View File

@@ -87,9 +87,9 @@ connection_closure_free(struct connection_closure *closure)
sudo_ev_free(closure->commit_ev); sudo_ev_free(closure->commit_ev);
sudo_ev_free(closure->read_ev); sudo_ev_free(closure->read_ev);
sudo_ev_free(closure->write_ev); sudo_ev_free(closure->write_ev);
iolog_details_free(&closure->details);
free(closure->read_buf.data); free(closure->read_buf.data);
free(closure->write_buf.data); free(closure->write_buf.data);
free(closure->iolog_dir);
free(closure); free(closure);
if (shutting_down && TAILQ_EMPTY(&connections)) 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_sec = msg->submit_time->tv_sec;
closure->submit_time.tv_nsec = msg->submit_time->tv_nsec; 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) { if (!msg->expect_iobufs) {
closure->state = FLUSHED; closure->state = FLUSHED;
debug_return_bool(true); 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. */ /* 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); debug_return_bool(false);
if (sudo_ev_add(NULL, closure->write_ev, NULL, false) == -1) { if (sudo_ev_add(NULL, closure->write_ev, NULL, false) == -1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, 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_sec = msg->submit_time->tv_sec;
closure->submit_time.tv_nsec = msg->submit_time->tv_nsec; 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; closure->state = FLUSHED;
debug_return_bool(true); debug_return_bool(true);
@@ -346,8 +367,12 @@ handle_alert(AlertMessage *msg, struct connection_closure *closure)
{ {
debug_decl(handle_alert, SUDO_DEBUG_UTIL) debug_decl(handle_alert, SUDO_DEBUG_UTIL)
/* TODO */ if (!log_alert(&closure->details, msg->alert_time, msg->reason)) {
debug_return_bool(false); closure->errstr = _("error logging alert event");
debug_return_bool(false);
}
debug_return_bool(true);
} }
static bool static bool

View File

@@ -35,9 +35,10 @@
* I/O log details from the AcceptMessage + iolog path and sessid. * I/O log details from the AcceptMessage + iolog path and sessid.
*/ */
struct iolog_details { struct iolog_details {
char *iolog_path;
char *iolog_file; /* substring of iolog_path, do not free */
char *command; char *command;
char *cwd; char *cwd;
char *iolog_dir;
char *rungroup; char *rungroup;
char *runuser; char *runuser;
char *submithost; char *submithost;
@@ -45,6 +46,7 @@ struct iolog_details {
char *submitgroup; char *submitgroup;
char *ttyname; char *ttyname;
char **argv; char **argv;
char **env_add;
time_t submit_time; time_t submit_time;
int argc; int argc;
int lines; int lines;
@@ -78,6 +80,7 @@ struct connection_buffer {
*/ */
struct connection_closure { struct connection_closure {
TAILQ_ENTRY(connection_closure) entries; TAILQ_ENTRY(connection_closure) entries;
struct iolog_details details;
struct timespec submit_time; struct timespec submit_time;
struct timespec elapsed_time; struct timespec elapsed_time;
struct connection_buffer read_buf; struct connection_buffer read_buf;
@@ -85,7 +88,6 @@ struct connection_closure {
struct sudo_event *commit_ev; struct sudo_event *commit_ev;
struct sudo_event *read_ev; struct sudo_event *read_ev;
struct sudo_event *write_ev; struct sudo_event *write_ev;
char *iolog_dir;
const char *errstr; const char *errstr;
struct iolog_file iolog_files[IOFD_MAX]; struct iolog_file iolog_files[IOFD_MAX];
int iolog_dir_fd; int iolog_dir_fd;
@@ -111,18 +113,46 @@ struct listen_address {
}; };
TAILQ_HEAD(listen_address_list, 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 */ /* 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_init(AcceptMessage *msg, struct connection_closure *closure);
bool iolog_restart(RestartMessage *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_iobuf(int iofd, IoBuffer *msg, struct connection_closure *closure);
int store_suspend(CommandSuspend *msg, struct connection_closure *closure); int store_suspend(CommandSuspend *msg, struct connection_closure *closure);
int store_winsize(ChangeWindowSize *msg, struct connection_closure *closure); int store_winsize(ChangeWindowSize *msg, struct connection_closure *closure);
void iolog_close_all(struct connection_closure *closure); void iolog_close_all(struct connection_closure *closure);
void iolog_details_free(struct iolog_details *details);
/* logsrvd_conf.c */ /* logsrvd_conf.c */
bool logsrvd_conf_read(const char *path); bool logsrvd_conf_read(const char *path);
const char *logsrvd_conf_iolog_dir(void); const char *logsrvd_conf_iolog_dir(void);
const char *logsrvd_conf_iolog_file(void); const char *logsrvd_conf_iolog_file(void);
struct listen_address_list *logsrvd_conf_listen_address(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 */ #endif /* SUDO_LOGSRVD_H */

View File

@@ -64,30 +64,114 @@ struct logsrvd_config_section {
struct logsrvd_config_entry *entries; 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 * const char *
logsrvd_conf_iolog_dir(void) logsrvd_conf_iolog_dir(void)
{ {
return logsrvd_iolog_dir; return logsrvd_config.iolog.iolog_dir;
} }
static char *logsrvd_iolog_file;
const char * const char *
logsrvd_conf_iolog_file(void) 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 * struct listen_address_list *
logsrvd_conf_listen_address(void) 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 static void
logsrvd_conf_reset(void) logsrvd_conf_reset(void)
{ {
@@ -95,26 +179,30 @@ logsrvd_conf_reset(void)
debug_decl(logsrvd_conf_reset, SUDO_DEBUG_UTIL) debug_decl(logsrvd_conf_reset, SUDO_DEBUG_UTIL)
iolog_set_defaults(); iolog_set_defaults();
free(logsrvd_iolog_dir); free(logsrvd_config.iolog.iolog_dir);
logsrvd_iolog_dir = NULL; logsrvd_config.iolog.iolog_dir = NULL;
free(logsrvd_iolog_file); free(logsrvd_config.iolog.iolog_file);
logsrvd_iolog_file = NULL; logsrvd_config.iolog.iolog_file = NULL;
while ((addr = TAILQ_FIRST(&addresses))) { while ((addr = TAILQ_FIRST(&logsrvd_config.server.addresses))) {
TAILQ_REMOVE(&addresses, addr, entries); TAILQ_REMOVE(&logsrvd_config.server.addresses, addr, entries);
free(addr); free(addr);
} }
free(logsrvd_config.logfile.path);
free(logsrvd_config.logfile.time_format);
debug_return; debug_return;
} }
/* I/O log callbacks */
static bool static bool
cb_iolog_dir(const char *path) cb_iolog_dir(const char *path)
{ {
debug_decl(cb_iolog_dir, SUDO_DEBUG_UTIL) debug_decl(cb_iolog_dir, SUDO_DEBUG_UTIL)
free(logsrvd_iolog_dir); free(logsrvd_config.iolog.iolog_dir);
if ((logsrvd_iolog_dir = strdup(path)) == NULL) { if ((logsrvd_config.iolog.iolog_dir = strdup(path)) == NULL) {
sudo_warn(NULL); sudo_warn(NULL);
debug_return_bool(false); debug_return_bool(false);
} }
@@ -126,8 +214,8 @@ cb_iolog_file(const char *path)
{ {
debug_decl(cb_iolog_file, SUDO_DEBUG_UTIL) debug_decl(cb_iolog_file, SUDO_DEBUG_UTIL)
free(logsrvd_iolog_file); free(logsrvd_config.iolog.iolog_file);
if ((logsrvd_iolog_file = strdup(path)) == NULL) { if ((logsrvd_config.iolog.iolog_file = strdup(path)) == NULL) {
sudo_warn(NULL); sudo_warn(NULL);
debug_return_bool(false); debug_return_bool(false);
} }
@@ -192,6 +280,13 @@ cb_iolog_mode(const char *str)
debug_return_bool(iolog_set_mode(mode)); 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 */ /* TODO: unit test */
static bool static bool
cb_listen_address(const char *str) 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); memcpy(&addr->sa_un, res->ai_addr, res->ai_addrlen);
addr->sa_len = 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; ret = true;
@@ -267,10 +362,157 @@ done:
debug_return_bool(ret); debug_return_bool(ret);
} }
/* eventlog callbacks */
static bool 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[] = { 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_user", cb_iolog_user },
{ "iolog_group", cb_iolog_group }, { "iolog_group", cb_iolog_group },
{ "iolog_mode", cb_iolog_mode }, { "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 } { NULL }
}; };
static struct logsrvd_config_section logsrvd_config_sections[] = { static struct logsrvd_config_section logsrvd_config_sections[] = {
{ "server", server_conf_entries }, { "server", server_conf_entries },
{ "iolog", iolog_conf_entries }, { "iolog", iolog_conf_entries },
{ "eventlog", eventlog_conf_entries },
{ "syslog", syslog_conf_entries },
{ "logfile", logfile_conf_entries },
{ NULL } { NULL }
}; };
@@ -300,7 +566,7 @@ static struct logsrvd_config_section logsrvd_config_sections[] = {
* Read .ini style logsrvd.conf file. * Read .ini style logsrvd.conf file.
* Note that we use '#' not ';' for the comment character. * 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 bool
logsrvd_conf_read(const char *path) logsrvd_conf_read(const char *path)
{ {
@@ -318,7 +584,27 @@ logsrvd_conf_read(const char *path)
debug_return_bool(false); debug_return_bool(false);
} }
/* Initialize default values for settings that take int values. */
logsrvd_conf_reset(); 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) { while (sudo_parseln(&line, &linesize, &lineno, fp, 0) != -1) {
struct logsrvd_config_entry *entry; struct logsrvd_config_entry *entry;
@@ -386,23 +672,27 @@ logsrvd_conf_read(const char *path)
} }
} }
/* All the others have default values. */ /* For settings with pointer values we can tell what is unset. */
if (logsrvd_iolog_dir == NULL) { if (logsrvd_config.iolog.iolog_dir == NULL) {
if ((logsrvd_iolog_dir = strdup(_PATH_SUDO_IO_LOGDIR)) == NULL) { if (!cb_iolog_dir(_PATH_SUDO_IO_LOGDIR))
sudo_warn(NULL);
debug_return_bool(false); debug_return_bool(false);
}
} }
if (logsrvd_iolog_file == NULL) { if (logsrvd_config.iolog.iolog_file == NULL) {
if ((logsrvd_iolog_file = strdup("%{seq}")) == NULL) { if (!cb_iolog_file("%{seq}"))
sudo_warn(NULL);
debug_return_bool(false); debug_return_bool(false);
}
} }
if (TAILQ_EMPTY(&addresses)) { if (TAILQ_EMPTY(&logsrvd_config.server.addresses)) {
if (!cb_listen_address("*:30344")) if (!cb_listen_address("*:30344"))
debug_return_bool(false); 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); debug_return_bool(true);
} }

View File

@@ -46,45 +46,6 @@
#include "sudoers.h" #include "sudoers.h"
#include <gram.h> #include <gram.h>
/*
* 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[] = { static struct early_default early_defaults[] = {
{ I_IGNORE_UNKNOWN_DEFAULTS }, { I_IGNORE_UNKNOWN_DEFAULTS },
#ifdef FQDN #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_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 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 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. * Table describing compile-time and run-time options.
@@ -150,14 +109,14 @@ dump_defaults(void)
case T_LOGFAC: case T_LOGFAC:
if (cur->sd_un.ival) { if (cur->sd_un.ival) {
sudo_printf(SUDO_CONV_INFO_MSG, desc, 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"); sudo_printf(SUDO_CONV_INFO_MSG, "\n");
} }
break; break;
case T_LOGPRI: case T_LOGPRI:
if (cur->sd_un.ival) { if (cur->sd_un.ival) {
sudo_printf(SUDO_CONV_INFO_MSG, desc, 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"); sudo_printf(SUDO_CONV_INFO_MSG, "\n");
} }
break; break;
@@ -990,63 +949,25 @@ store_list(const char *str, union sudo_defs_val *sd_un, int op)
static bool static bool
store_syslogfac(const char *str, union sudo_defs_val *sd_un) store_syslogfac(const char *str, union sudo_defs_val *sd_un)
{ {
struct strmap *fac;
debug_decl(store_syslogfac, SUDOERS_DEBUG_DEFAULTS) debug_decl(store_syslogfac, SUDOERS_DEBUG_DEFAULTS)
if (str == NULL) { if (str == NULL) {
sd_un->ival = false; sd_un->ival = false;
debug_return_bool(true); debug_return_bool(true);
} }
for (fac = facilities; fac->name != NULL; fac++) { debug_return_bool(sudo_str2logfac(str, &sd_un->ival));
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);
} }
static bool static bool
store_syslogpri(const char *str, union sudo_defs_val *sd_un) store_syslogpri(const char *str, union sudo_defs_val *sd_un)
{ {
struct strmap *pri;
debug_decl(store_syslogpri, SUDOERS_DEBUG_DEFAULTS) debug_decl(store_syslogpri, SUDOERS_DEBUG_DEFAULTS)
if (str == NULL) { if (str == NULL) {
sd_un->ival = -1; sd_un->ival = -1;
debug_return_bool(true); debug_return_bool(true);
} }
for (pri = priorities; pri->name != NULL; pri++) { debug_return_bool(sudo_str2logpri(str, &sd_un->ival));
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");
} }
static bool static bool