Refactor code in sudoers that creates I/O log files to share with logsrvd.
This commit is contained in:
17
MANIFEST
17
MANIFEST
@@ -71,6 +71,7 @@ include/sudo_dso.h
|
||||
include/sudo_event.h
|
||||
include/sudo_fatal.h
|
||||
include/sudo_gettext.h
|
||||
include/sudo_iolog.h
|
||||
include/sudo_lbuf.h
|
||||
include/sudo_plugin.h
|
||||
include/sudo_queue.h
|
||||
@@ -81,6 +82,13 @@ init.d/aix.sh.in
|
||||
init.d/hpux.sh.in
|
||||
init.d/sudo.conf.in
|
||||
install-sh
|
||||
lib/iolog/Makefile.in
|
||||
lib/iolog/iolog_fileio.c
|
||||
lib/iolog/iolog_path.c
|
||||
lib/iolog/iolog_util.c
|
||||
lib/iolog/regress/iolog_path/check_iolog_path.c
|
||||
lib/iolog/regress/iolog_path/data
|
||||
lib/iolog/regress/iolog_util/check_iolog_util.c
|
||||
lib/util/Makefile.in
|
||||
lib/util/aix.c
|
||||
lib/util/arc4random.c
|
||||
@@ -331,11 +339,7 @@ plugins/sudoers/insults.h
|
||||
plugins/sudoers/interfaces.c
|
||||
plugins/sudoers/interfaces.h
|
||||
plugins/sudoers/iolog.c
|
||||
plugins/sudoers/iolog.h
|
||||
plugins/sudoers/iolog_files.h
|
||||
plugins/sudoers/iolog_path.c
|
||||
plugins/sudoers/iolog_util.c
|
||||
plugins/sudoers/iolog_util.h
|
||||
plugins/sudoers/iolog_path_escapes.c
|
||||
plugins/sudoers/ldap.c
|
||||
plugins/sudoers/ldap_conf.c
|
||||
plugins/sudoers/ldap_util.c
|
||||
@@ -503,10 +507,7 @@ plugins/sudoers/regress/cvtsudoers/test9.out.ok
|
||||
plugins/sudoers/regress/cvtsudoers/test9.sh
|
||||
plugins/sudoers/regress/env_match/check_env_pattern.c
|
||||
plugins/sudoers/regress/env_match/data
|
||||
plugins/sudoers/regress/iolog_path/check_iolog_path.c
|
||||
plugins/sudoers/regress/iolog_path/data
|
||||
plugins/sudoers/regress/iolog_plugin/check_iolog_plugin.c
|
||||
plugins/sudoers/regress/iolog_util/check_iolog_util.c
|
||||
plugins/sudoers/regress/logging/check_wrap.c
|
||||
plugins/sudoers/regress/logging/check_wrap.in
|
||||
plugins/sudoers/regress/logging/check_wrap.out.ok
|
||||
|
13
Makefile.in
13
Makefile.in
@@ -49,8 +49,8 @@ sudoers_gid = @SUDOERS_GID@
|
||||
sudoers_mode = @SUDOERS_MODE@
|
||||
shlib_mode = @SHLIB_MODE@
|
||||
|
||||
SUBDIRS = lib/util @ZLIB_SRC@ logsrvd plugins/group_file plugins/sudoers \
|
||||
plugins/system_group src include doc examples
|
||||
SUBDIRS = lib/util lib/iolog @ZLIB_SRC@ logsrvd plugins/group_file \
|
||||
plugins/sudoers plugins/system_group src include doc examples
|
||||
|
||||
SAMPLES = plugins/sample
|
||||
|
||||
@@ -188,12 +188,13 @@ siglist.c signame.c:
|
||||
|
||||
depend: siglist.c signame.c
|
||||
$(top_srcdir)/mkdep.pl --builddir=`pwd` --srcdir=$(top_srcdir) \
|
||||
lib/util/Makefile.in lib/zlib/Makefile.in logsrvd/Makefile.in \
|
||||
plugins/group_file/Makefile.in plugins/sample/Makefile.in \
|
||||
plugins/sudoers/Makefile.in plugins/system_group/Makefile.in \
|
||||
src/Makefile.in && \
|
||||
lib/util/Makefile.in lib/zlib/Makefile.in lib/iolog/Makefile.in \
|
||||
logsrvd/Makefile.in plugins/group_file/Makefile.in \
|
||||
plugins/sample/Makefile.in plugins/sudoers/Makefile.in \
|
||||
plugins/system_group/Makefile.in src/Makefile.in && \
|
||||
$(top_builddir)/config.status --file $(top_builddir)/lib/util/Makefile \
|
||||
--file $(top_builddir)/lib/zlib/Makefile \
|
||||
--file $(top_builddir)/lib/iolog/Makefile \
|
||||
--file $(top_builddir)/logsrvd/Makefile \
|
||||
--file $(top_builddir)/plugins/sample/Makefile \
|
||||
--file $(top_builddir)/plugins/group_file/Makefile \
|
||||
|
3
configure
vendored
3
configure
vendored
@@ -27067,7 +27067,7 @@ elif test X"$TMPFILES_D" != X""; then
|
||||
ac_config_files="$ac_config_files init.d/sudo.conf"
|
||||
|
||||
fi
|
||||
ac_config_files="$ac_config_files Makefile doc/Makefile examples/Makefile include/Makefile lib/util/Makefile lib/util/util.exp logsrvd/Makefile src/sudo_usage.h src/Makefile plugins/sample/Makefile plugins/group_file/Makefile plugins/system_group/Makefile plugins/sudoers/Makefile plugins/sudoers/sudoers"
|
||||
ac_config_files="$ac_config_files Makefile doc/Makefile examples/Makefile include/Makefile lib/iolog/Makefile lib/util/Makefile lib/util/util.exp logsrvd/Makefile src/sudo_usage.h src/Makefile plugins/sample/Makefile plugins/group_file/Makefile plugins/system_group/Makefile plugins/sudoers/Makefile plugins/sudoers/sudoers"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
@@ -28065,6 +28065,7 @@ do
|
||||
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
|
||||
"examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;;
|
||||
"include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
|
||||
"lib/iolog/Makefile") CONFIG_FILES="$CONFIG_FILES lib/iolog/Makefile" ;;
|
||||
"lib/util/Makefile") CONFIG_FILES="$CONFIG_FILES lib/util/Makefile" ;;
|
||||
"lib/util/util.exp") CONFIG_FILES="$CONFIG_FILES lib/util/util.exp" ;;
|
||||
"logsrvd/Makefile") CONFIG_FILES="$CONFIG_FILES logsrvd/Makefile" ;;
|
||||
|
@@ -4491,7 +4491,7 @@ if test X"$INIT_SCRIPT" != X""; then
|
||||
elif test X"$TMPFILES_D" != X""; then
|
||||
AC_CONFIG_FILES([init.d/sudo.conf])
|
||||
fi
|
||||
AC_CONFIG_FILES([Makefile doc/Makefile examples/Makefile include/Makefile lib/util/Makefile lib/util/util.exp logsrvd/Makefile src/sudo_usage.h src/Makefile plugins/sample/Makefile plugins/group_file/Makefile plugins/system_group/Makefile plugins/sudoers/Makefile plugins/sudoers/sudoers])
|
||||
AC_CONFIG_FILES([Makefile doc/Makefile examples/Makefile include/Makefile lib/iolog/Makefile lib/util/Makefile lib/util/util.exp logsrvd/Makefile src/sudo_usage.h src/Makefile plugins/sample/Makefile plugins/group_file/Makefile plugins/system_group/Makefile plugins/sudoers/Makefile plugins/sudoers/sudoers])
|
||||
AC_OUTPUT
|
||||
|
||||
dnl
|
||||
|
135
include/sudo_iolog.h
Normal file
135
include/sudo_iolog.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2009-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.
|
||||
*/
|
||||
|
||||
#ifndef SUDO_IOLOG_H
|
||||
#define SUDO_IOLOG_H
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
# include <zlib.h> /* for gzFile */
|
||||
#endif
|
||||
|
||||
/* Default maximum session ID */
|
||||
#define SESSID_MAX 2176782336U
|
||||
|
||||
/*
|
||||
* I/O log event types as stored as the first field in the timing file.
|
||||
* Changing existing values will result in incompatible I/O log files.
|
||||
*/
|
||||
#define IO_EVENT_STDIN 0
|
||||
#define IO_EVENT_STDOUT 1
|
||||
#define IO_EVENT_STDERR 2
|
||||
#define IO_EVENT_TTYIN 3
|
||||
#define IO_EVENT_TTYOUT 4
|
||||
#define IO_EVENT_WINSIZE 5
|
||||
#define IO_EVENT_TTYOUT_1_8_7 6
|
||||
#define IO_EVENT_SUSPEND 7
|
||||
#define IO_EVENT_COUNT 8
|
||||
|
||||
/*
|
||||
* Indexes into iolog_files[] array.
|
||||
* These must match the IO_EVENT_ defines above.
|
||||
* TODO: eliminate use of IOFD_* and IO_EVENT_* as indexes in favor of
|
||||
* a struct containing iolog_file *s for each (and names too?).
|
||||
*/
|
||||
#define IOFD_STDIN 0
|
||||
#define IOFD_STDOUT 1
|
||||
#define IOFD_STDERR 2
|
||||
#define IOFD_TTYIN 3
|
||||
#define IOFD_TTYOUT 4
|
||||
#define IOFD_TIMING 5
|
||||
#define IOFD_MAX 6
|
||||
|
||||
/*
|
||||
* Info present in the I/O log file
|
||||
*/
|
||||
struct iolog_info {
|
||||
char *cwd;
|
||||
char *user;
|
||||
char *runas_user;
|
||||
char *runas_group;
|
||||
char *tty;
|
||||
char *cmd;
|
||||
time_t tstamp;
|
||||
int lines;
|
||||
int cols;
|
||||
};
|
||||
|
||||
struct timing_closure {
|
||||
struct timespec delay;
|
||||
const char *decimal;
|
||||
struct iolog_file *iol;
|
||||
int event;
|
||||
union {
|
||||
struct {
|
||||
int lines;
|
||||
int cols;
|
||||
} winsize;
|
||||
size_t nbytes;
|
||||
int signo;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct iolog_file {
|
||||
bool enabled;
|
||||
bool compressed;
|
||||
union {
|
||||
FILE *f;
|
||||
#ifdef HAVE_ZLIB_H
|
||||
gzFile g;
|
||||
#endif
|
||||
void *v;
|
||||
} fd;
|
||||
};
|
||||
|
||||
struct iolog_path_escape {
|
||||
const char *name;
|
||||
size_t (*copy_fn)(char *, size_t, char *);
|
||||
};
|
||||
|
||||
/* iolog_path.c */
|
||||
char *expand_iolog_path(const char *prefix, const char *dir, const char *file, char **slashp, const struct iolog_path_escape *escapes);
|
||||
|
||||
/* iolog_util.c */
|
||||
bool parse_timing(const char *line, struct timing_closure *timing);
|
||||
char *parse_delay(const char *cp, struct timespec *delay, const char *decimal_point);
|
||||
struct iolog_info *parse_logfile(const char *logfile);
|
||||
void free_iolog_info(struct iolog_info *li);
|
||||
void adjust_delay(struct timespec *delay, struct timespec *max_delay, double scale_factor);
|
||||
|
||||
/* iolog_fileio.c */
|
||||
struct passwd;
|
||||
struct group;
|
||||
bool iolog_close(struct iolog_file *iol, const char **errstr);
|
||||
bool iolog_eof(struct iolog_file *iol);
|
||||
bool iolog_nextid(char *iolog_dir, char sessid[7]);
|
||||
bool iolog_open(struct iolog_file *iol, char *pathbuf, const char *mode);
|
||||
bool iolog_set_compress(const char *str);
|
||||
bool iolog_set_flush(const char *str);
|
||||
bool iolog_set_group(const struct group *gr);
|
||||
bool iolog_set_maxseq(const char *maxval);
|
||||
bool iolog_set_mode(mode_t mode);
|
||||
bool iolog_set_user(const struct passwd *pw);
|
||||
bool iolog_write_info_file(const char *parent, struct iolog_info *log_info, char * const argv[]);
|
||||
char *iolog_gets(struct iolog_file *iol, char *buf, size_t nbytes, const char **errsttr);
|
||||
const char *iolog_fd_to_name(int iofd);
|
||||
off_t iolog_seek(struct iolog_file *iol, off_t offset, int whence);
|
||||
size_t mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize);
|
||||
ssize_t iolog_read(struct iolog_file *iol, void *buf, size_t nbytes, const char **errstr);
|
||||
ssize_t iolog_write(struct iolog_file *iol, const void *buf, size_t len, const char **errstr);
|
||||
|
||||
#endif /* SUDO_IOLOG_H */
|
@@ -25,6 +25,13 @@
|
||||
# include "compat/stdbool.h"
|
||||
#endif /* HAVE_STDBOOL_H */
|
||||
|
||||
#ifdef __TANDEM
|
||||
# define ROOT_UID 65535
|
||||
#else
|
||||
# define ROOT_UID 0
|
||||
#endif
|
||||
#define ROOT_GID 0
|
||||
|
||||
#ifndef TIME_T_MAX
|
||||
# if SIZEOF_TIME_T == 8
|
||||
# define TIME_T_MAX LLONG_MAX
|
||||
|
256
lib/iolog/Makefile.in
Normal file
256
lib/iolog/Makefile.in
Normal file
@@ -0,0 +1,256 @@
|
||||
#
|
||||
# SPDX-License-Identifier: ISC
|
||||
#
|
||||
# Copyright (c) 2011-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.
|
||||
#
|
||||
# @configure_input@
|
||||
#
|
||||
|
||||
#### Start of system configuration section. ####
|
||||
|
||||
srcdir = @srcdir@
|
||||
devdir = @devdir@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
incdir = $(top_srcdir)/include
|
||||
cross_compiling = @CROSS_COMPILING@
|
||||
|
||||
# Where to install things...
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
sbindir = @sbindir@
|
||||
sysconfdir = @sysconfdir@
|
||||
libexecdir = @libexecdir@
|
||||
datarootdir = @datarootdir@
|
||||
localstatedir = @localstatedir@
|
||||
|
||||
# Compiler & tools to use
|
||||
CC = @CC@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
SED = @SED@
|
||||
AWK = @AWK@
|
||||
|
||||
# Libraries
|
||||
LT_LIBS = $(top_builddir)/lib/util/libsudo_util.la
|
||||
LIBS = @LIBS@ @ZLIB@ $(LT_LIBS)
|
||||
|
||||
# C preprocessor flags
|
||||
CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(srcdir) -I$(top_srcdir) @CPPFLAGS@
|
||||
|
||||
# Usually -O and/or -g
|
||||
CFLAGS = @CFLAGS@
|
||||
|
||||
# Flags to pass to the link stage
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
# Flags to pass to libtool
|
||||
LTFLAGS = @LT_STATIC@
|
||||
|
||||
# Address sanitizer flags
|
||||
ASAN_CFLAGS = @ASAN_CFLAGS@
|
||||
ASAN_LDFLAGS = @ASAN_LDFLAGS@
|
||||
|
||||
# PIE flags
|
||||
PIE_CFLAGS = @PIE_CFLAGS@
|
||||
PIE_LDFLAGS = @PIE_LDFLAGS@
|
||||
|
||||
# Stack smashing protection flags
|
||||
SSP_CFLAGS = @SSP_CFLAGS@
|
||||
SSP_LDFLAGS = @SSP_LDFLAGS@
|
||||
|
||||
# cppcheck options, usually set in the top-level Makefile
|
||||
CPPCHECK_OPTS = -q --force --enable=warning,performance,portability --suppress=constStatement --error-exitcode=1 --inline-suppr -Dva_copy=va_copy -U__cplusplus -UQUAD_MAX -UQUAD_MIN -UUQUAD_MAX -U_POSIX_HOST_NAME_MAX -U_POSIX_PATH_MAX -U__NBBY -DNSIG=64
|
||||
|
||||
# splint options, usually set in the top-level Makefile
|
||||
SPLINT_OPTS = -D__restrict= -checks
|
||||
|
||||
# PVS-studio options
|
||||
PVS_CFG = $(top_srcdir)/PVS-Studio.cfg
|
||||
PVS_IGNORE = 'V707,V011,V002,V536'
|
||||
PVS_LOG_OPTS = -a 'GA:1,2' -e -t errorfile -d $(PVS_IGNORE)
|
||||
|
||||
# Regression tests
|
||||
TEST_PROGS = check_iolog_path check_iolog_util
|
||||
TEST_LIBS = @LIBS@
|
||||
TEST_LDFLAGS = @LDFLAGS@
|
||||
|
||||
# Set to non-empty for development mode
|
||||
DEVEL = @DEVEL@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
SHELL = @SHELL@
|
||||
|
||||
LIBIOLOG_OBJS = iolog_fileio.lo iolog_path.lo iolog_util.lo
|
||||
|
||||
IOBJS = $(LIBIOLOG_OBJS:.lo=.i)
|
||||
|
||||
POBJS = $(IOBJS:.i=.plog)
|
||||
|
||||
CHECK_IOLOG_PATH_OBJS = check_iolog_path.lo iolog_path.lo
|
||||
|
||||
CHECK_IOLOG_UTIL_OBJS = check_iolog_util.lo iolog_util.lo
|
||||
|
||||
all: libsudo_iolog.la
|
||||
|
||||
pvs-log-files: $(POBJS)
|
||||
|
||||
pvs-studio: $(POBJS)
|
||||
plog-converter $(PVS_LOG_OPTS) $(POBJS)
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in
|
||||
cd $(top_builddir) && ./config.status --file lib/iolog/Makefile
|
||||
|
||||
.SUFFIXES: .c .h .i .lo .plog
|
||||
|
||||
.c.lo:
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $<
|
||||
|
||||
.c.i:
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
|
||||
.i.plog:
|
||||
ifile=$<; rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $${ifile%i}c --i-file $< --output-file $@
|
||||
|
||||
libsudo_iolog.la: $(LIBIOLOG_OBJS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(LIBIOLOG_OBJS) $(LT_LIBS) @ZLIB@
|
||||
|
||||
check_iolog_path: $(CHECK_IOLOG_PATH_OBJS) libsudo_iolog.la
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_PATH_OBJS) libsudo_iolog.la $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS)
|
||||
|
||||
check_iolog_util: $(CHECK_IOLOG_UTIL_OBJS) libsudo_iolog.la
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_UTIL_OBJS) libsudo_iolog.la $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS)
|
||||
|
||||
pre-install:
|
||||
|
||||
install:
|
||||
|
||||
install-binaries:
|
||||
|
||||
install-includes:
|
||||
|
||||
install-doc:
|
||||
|
||||
install-plugin:
|
||||
|
||||
uninstall:
|
||||
|
||||
splint:
|
||||
splint $(SPLINT_OPTS) -I$(incdir) -I$(top_builddir) -I$(top_srcdir) $(srcdir)/*.c
|
||||
|
||||
cppcheck:
|
||||
cppcheck $(CPPCHECK_OPTS) -I$(incdir) -I$(top_builddir) -I$(top_srcdir) $(srcdir)/*.c
|
||||
|
||||
pvs-log-files: $(POBJS)
|
||||
|
||||
check: $(TEST_PROGS)
|
||||
@if test X"$(cross_compiling)" != X"yes"; then \
|
||||
LC_ALL=C; export LC_ALL; \
|
||||
unset LANG || LANG=; \
|
||||
rval=0; \
|
||||
./check_iolog_path $(srcdir)/regress/iolog_path/data || rval=`expr $$rval + $$?`; \
|
||||
./check_iolog_util || rval=`expr $$rval + $$?`; \
|
||||
exit $$rval; \
|
||||
fi
|
||||
|
||||
clean:
|
||||
-$(LIBTOOL) $(LTFLAGS) --mode=clean rm -f $(TEST_PROGS) *.lo *.o \
|
||||
*.la *.a *.i *.plog stamp-* core *.core core.* regress/*/*.out \
|
||||
regress/*/*.err
|
||||
|
||||
mostlyclean: clean
|
||||
|
||||
distclean: clean
|
||||
-rm -rf Makefile .libs
|
||||
|
||||
clobber: distclean
|
||||
|
||||
realclean: distclean
|
||||
rm -f TAGS tags
|
||||
|
||||
cleandir: realclean
|
||||
|
||||
# Autogenerated dependencies, do not modify
|
||||
check_iolog_path.lo: $(srcdir)/regress/iolog_path/check_iolog_path.c \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_iolog.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)/regress/iolog_path/check_iolog_path.c
|
||||
check_iolog_path.i: $(srcdir)/regress/iolog_path/check_iolog_path.c \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_iolog.h \
|
||||
$(incdir)/sudo_util.h $(top_builddir)/config.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
check_iolog_path.plog: check_iolog_path.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/iolog_path/check_iolog_path.c --i-file $< --output-file $@
|
||||
check_iolog_util.lo: $(srcdir)/regress/iolog_util/check_iolog_util.c \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_iolog.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)/regress/iolog_util/check_iolog_util.c
|
||||
check_iolog_util.i: $(srcdir)/regress/iolog_util/check_iolog_util.c \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_iolog.h \
|
||||
$(incdir)/sudo_util.h $(top_builddir)/config.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
check_iolog_util.plog: check_iolog_util.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/iolog_util/check_iolog_util.c --i-file $< --output-file $@
|
||||
iolog_fileio.lo: $(srcdir)/iolog_fileio.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||
$(incdir)/sudo_debug.h $(incdir)/sudo_event.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/iolog_fileio.c
|
||||
iolog_fileio.i: $(srcdir)/iolog_fileio.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||
$(incdir)/sudo_debug.h $(incdir)/sudo_event.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
iolog_fileio.plog: iolog_fileio.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog_fileio.c --i-file $< --output-file $@
|
||||
iolog_path.lo: $(srcdir)/iolog_path.c $(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 $(top_builddir)/config.h
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/iolog_path.c
|
||||
iolog_path.i: $(srcdir)/iolog_path.c $(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 $(top_builddir)/config.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
iolog_path.plog: iolog_path.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog_path.c --i-file $< --output-file $@
|
||||
iolog_util.lo: $(srcdir)/iolog_util.c $(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 $(top_builddir)/config.h
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/iolog_util.c
|
||||
iolog_util.i: $(srcdir)/iolog_util.c $(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 $(top_builddir)/config.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
iolog_util.plog: iolog_util.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog_util.c --i-file $< --output-file $@
|
897
lib/iolog/iolog_fileio.c
Normal file
897
lib/iolog/iolog_fileio.c
Normal file
@@ -0,0 +1,897 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2009-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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
# include <stdbool.h>
|
||||
#else
|
||||
# include "compat/stdbool.h"
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif /* HAVE_STRINGS_H */
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "sudo_gettext.h" /* must be included before sudo_compat.h */
|
||||
#include "sudo_compat.h"
|
||||
#include "sudo_conf.h"
|
||||
#include "sudo_debug.h"
|
||||
#include "sudo_event.h"
|
||||
#include "sudo_queue.h"
|
||||
#include "sudo_util.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "sudo_iolog.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
static unsigned char const gzip_magic[2] = {0x1f, 0x8b};
|
||||
static unsigned int sessid_max = SESSID_MAX;
|
||||
static mode_t iolog_filemode = S_IRUSR|S_IWUSR;
|
||||
static mode_t iolog_dirmode = S_IRWXU;
|
||||
static uid_t iolog_uid = ROOT_UID;
|
||||
static gid_t iolog_gid = ROOT_GID;
|
||||
static bool iolog_gid_set;
|
||||
static bool iolog_compress;
|
||||
static bool iolog_flush;
|
||||
|
||||
/*
|
||||
* Set effective user and group-IDs to iolog_uid and iolog_gid.
|
||||
* If restore flag is set, swap them back.
|
||||
*/
|
||||
static bool
|
||||
io_swapids(bool restore)
|
||||
{
|
||||
#ifdef HAVE_SETEUID
|
||||
static uid_t user_euid = (uid_t)-1;
|
||||
static gid_t user_egid = (gid_t)-1;
|
||||
debug_decl(io_swapids, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (user_euid == (uid_t)-1)
|
||||
user_euid = geteuid();
|
||||
if (user_egid == (gid_t)-1)
|
||||
user_euid = getegid();
|
||||
|
||||
if (restore) {
|
||||
if (seteuid(user_euid) == -1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to restore effective uid to %d", __func__,
|
||||
(int)user_euid);
|
||||
sudo_warn("seteuid() %d -> %d", (int)iolog_uid, (int)user_euid);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
if (setegid(user_egid) == -1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to restore effective gid to %d", __func__,
|
||||
(int)user_egid);
|
||||
sudo_warn("setegid() %d -> %d", (int)iolog_gid, (int)user_egid);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
} else {
|
||||
/* Fail silently if the user has insufficient privileges. */
|
||||
if (setegid(iolog_gid) == -1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to set effective gid to %d", __func__,
|
||||
(int)iolog_gid);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
if (seteuid(iolog_uid) == -1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to set effective uid to %d", __func__,
|
||||
(int)iolog_uid);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
}
|
||||
debug_return_bool(true);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Create directory and any parent directories as needed.
|
||||
*/
|
||||
static bool
|
||||
io_mkdirs(char *path)
|
||||
{
|
||||
mode_t omask;
|
||||
struct stat sb;
|
||||
bool ok, uid_changed = false;
|
||||
debug_decl(io_mkdirs, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* umask must not be more restrictive than the file modes. */
|
||||
omask = umask(ACCESSPERMS & ~(iolog_filemode|iolog_dirmode));
|
||||
|
||||
ok = stat(path, &sb) == 0;
|
||||
if (!ok && errno == EACCES) {
|
||||
/* Try again as the I/O log owner (for NFS). */
|
||||
if (io_swapids(false)) {
|
||||
ok = stat(path, &sb) == 0;
|
||||
if (!io_swapids(true))
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
if (sb.st_uid != iolog_uid || sb.st_gid != iolog_gid) {
|
||||
if (chown(path, iolog_uid, iolog_gid) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to chown %d:%d %s", __func__,
|
||||
(int)iolog_uid, (int)iolog_gid, path);
|
||||
}
|
||||
}
|
||||
if ((sb.st_mode & ALLPERMS) != iolog_dirmode) {
|
||||
if (chmod(path, iolog_dirmode) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to chmod 0%o %s", __func__,
|
||||
(int)iolog_dirmode, path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sudo_warnx(U_("%s exists but is not a directory (0%o)"),
|
||||
path, (unsigned int) sb.st_mode);
|
||||
ok = false;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
ok = sudo_mkdir_parents(path, iolog_uid, iolog_gid, iolog_dirmode, true);
|
||||
if (!ok && errno == EACCES) {
|
||||
/* Try again as the I/O log owner (for NFS). */
|
||||
uid_changed = io_swapids(false);
|
||||
if (uid_changed)
|
||||
ok = sudo_mkdir_parents(path, -1, -1, iolog_dirmode, false);
|
||||
}
|
||||
if (ok) {
|
||||
/* Create final path component. */
|
||||
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
|
||||
"mkdir %s, mode 0%o", path, (unsigned int) iolog_dirmode);
|
||||
ok = mkdir(path, iolog_dirmode) == 0 || errno == EEXIST;
|
||||
if (!ok) {
|
||||
if (errno == EACCES && !uid_changed) {
|
||||
/* Try again as the I/O log owner (for NFS). */
|
||||
uid_changed = io_swapids(false);
|
||||
if (uid_changed)
|
||||
ok = mkdir(path, iolog_dirmode) == 0 || errno == EEXIST;
|
||||
}
|
||||
if (!ok)
|
||||
sudo_warn(U_("unable to mkdir %s"), path);
|
||||
} else {
|
||||
if (chown(path, iolog_uid, iolog_gid) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to chown %d:%d %s", __func__,
|
||||
(int)iolog_uid, (int)iolog_gid, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uid_changed) {
|
||||
if (!io_swapids(true))
|
||||
ok = false;
|
||||
}
|
||||
done:
|
||||
umask(omask);
|
||||
debug_return_bool(ok);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create temporary directory and any parent directories as needed.
|
||||
*/
|
||||
static bool
|
||||
io_mkdtemp(char *path)
|
||||
{
|
||||
bool ok, uid_changed = false;
|
||||
debug_decl(io_mkdtemp, SUDO_DEBUG_UTIL)
|
||||
|
||||
ok = sudo_mkdir_parents(path, iolog_uid, iolog_gid, iolog_dirmode, true);
|
||||
if (!ok && errno == EACCES) {
|
||||
/* Try again as the I/O log owner (for NFS). */
|
||||
uid_changed = io_swapids(false);
|
||||
if (uid_changed)
|
||||
ok = sudo_mkdir_parents(path, -1, -1, iolog_dirmode, false);
|
||||
}
|
||||
if (ok) {
|
||||
/* Create final path component. */
|
||||
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
|
||||
"mkdtemp %s", path);
|
||||
/* We cannot retry mkdtemp() so always open as iolog user */
|
||||
if (!uid_changed)
|
||||
uid_changed = io_swapids(false);
|
||||
if (mkdtemp(path) == NULL) {
|
||||
sudo_warn(U_("unable to mkdir %s"), path);
|
||||
ok = false;
|
||||
} else {
|
||||
if (chmod(path, iolog_dirmode) != 0) {
|
||||
sudo_warn(U_("unable to change mode of %s to 0%o"),
|
||||
path, (unsigned int)iolog_dirmode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uid_changed) {
|
||||
if (!io_swapids(true))
|
||||
ok = false;
|
||||
}
|
||||
debug_return_bool(ok);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set max sequence number (aka session ID)
|
||||
*/
|
||||
bool
|
||||
iolog_set_maxseq(const char *maxval)
|
||||
{
|
||||
const char *errstr;
|
||||
unsigned int value;
|
||||
debug_decl(iolog_set_maxseq, SUDO_DEBUG_UTIL)
|
||||
|
||||
value = sudo_strtonum(maxval, 0, SESSID_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
if (errno != ERANGE) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"bad maxseq: %s: %s", maxval, errstr);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
/* Out of range, clamp to SESSID_MAX as documented. */
|
||||
value = SESSID_MAX;
|
||||
}
|
||||
sessid_max = value;
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set iolog_uid (and iolog_gid if iolog_group not specified).
|
||||
*/
|
||||
bool
|
||||
iolog_set_user(const struct passwd *pw)
|
||||
{
|
||||
debug_decl(iolog_set_user, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (pw != NULL) {
|
||||
iolog_uid = pw->pw_uid;
|
||||
if (!iolog_gid_set)
|
||||
iolog_gid = pw->pw_gid;
|
||||
} else {
|
||||
/* Reset to default. */
|
||||
iolog_uid = ROOT_UID;
|
||||
if (!iolog_gid_set)
|
||||
iolog_gid = ROOT_GID;
|
||||
}
|
||||
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set iolog_gid.
|
||||
*/
|
||||
bool
|
||||
iolog_set_group(const struct group *gr)
|
||||
{
|
||||
debug_decl(iolog_set_group, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (gr != NULL) {
|
||||
iolog_gid = gr->gr_gid;
|
||||
iolog_gid_set = true;
|
||||
} else {
|
||||
/* Reset to default. */
|
||||
iolog_gid = ROOT_GID;
|
||||
iolog_gid_set = false;
|
||||
}
|
||||
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set iolog_filemode and iolog_dirmode.
|
||||
*/
|
||||
bool
|
||||
iolog_set_mode(mode_t mode)
|
||||
{
|
||||
debug_decl(iolog_set_mode, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* I/O log files must be readable and writable by owner. */
|
||||
iolog_filemode = S_IRUSR|S_IWUSR;
|
||||
|
||||
/* Add in group and other read/write if specified. */
|
||||
iolog_filemode |= mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
||||
|
||||
/* For directory mode, add execute bits as needed. */
|
||||
iolog_dirmode = iolog_filemode | S_IXUSR;
|
||||
if (iolog_dirmode & (S_IRGRP|S_IWGRP))
|
||||
iolog_dirmode |= S_IXGRP;
|
||||
if (iolog_dirmode & (S_IROTH|S_IWOTH))
|
||||
iolog_dirmode |= S_IXOTH;
|
||||
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set iolog_compress
|
||||
*/
|
||||
bool
|
||||
iolog_set_compress(const char *str)
|
||||
{
|
||||
int result;
|
||||
debug_decl(iolog_set_compress, SUDO_DEBUG_UTIL)
|
||||
|
||||
if ((result = sudo_strtobool(str)) == -1)
|
||||
debug_return_bool(false);
|
||||
|
||||
iolog_compress = result;
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set iolog_flush
|
||||
*/
|
||||
bool
|
||||
iolog_set_flush(const char *str)
|
||||
{
|
||||
int result;
|
||||
debug_decl(iolog_set_flush, SUDO_DEBUG_UTIL)
|
||||
|
||||
if ((result = sudo_strtobool(str)) == -1)
|
||||
debug_return_bool(false);
|
||||
|
||||
iolog_flush = result;
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for open(2) that sets umask and retries as iolog_uid/iolog_gid
|
||||
* if open(2) returns EACCES.
|
||||
*/
|
||||
static int
|
||||
io_open(const char *path, int flags)
|
||||
{
|
||||
int fd;
|
||||
mode_t omask = S_IRWXG|S_IRWXO;
|
||||
debug_decl(io_open, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (ISSET(flags, O_CREAT)) {
|
||||
/* umask must not be more restrictive than the file modes. */
|
||||
omask = umask(ACCESSPERMS & ~(iolog_filemode|iolog_dirmode));
|
||||
}
|
||||
fd = open(path, flags, iolog_filemode);
|
||||
if (fd == -1 && errno == EACCES) {
|
||||
/* Try again as the I/O log owner (for NFS). */
|
||||
if (io_swapids(false)) {
|
||||
fd = open(path, flags, iolog_filemode);
|
||||
if (!io_swapids(true)) {
|
||||
/* io_swapids() warns on error. */
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ISSET(flags, O_CREAT))
|
||||
umask(omask);
|
||||
debug_return_int(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the on-disk sequence number, set sessid to the next
|
||||
* number, and update the on-disk copy.
|
||||
* Uses file locking to avoid sequence number collisions.
|
||||
*/
|
||||
bool
|
||||
iolog_nextid(char *iolog_dir, char sessid[7])
|
||||
{
|
||||
char buf[32], *ep;
|
||||
int i, len, fd = -1;
|
||||
unsigned long id = 0;
|
||||
ssize_t nread;
|
||||
bool ret = false;
|
||||
char pathbuf[PATH_MAX];
|
||||
static const char b36char[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
debug_decl(iolog_nextid, SUDO_DEBUG_UTIL)
|
||||
|
||||
/*
|
||||
* Create I/O log directory if it doesn't already exist.
|
||||
*/
|
||||
if (!io_mkdirs(iolog_dir))
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Open sequence file
|
||||
*/
|
||||
len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir);
|
||||
if (len < 0 || len >= ssizeof(pathbuf)) {
|
||||
errno = ENAMETOOLONG;
|
||||
goto done;
|
||||
}
|
||||
fd = io_open(pathbuf, O_RDWR|O_CREAT);
|
||||
if (fd == -1) {
|
||||
goto done;
|
||||
}
|
||||
sudo_lock_file(fd, SUDO_LOCK);
|
||||
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to fchown %d:%d %s", __func__,
|
||||
(int)iolog_uid, (int)iolog_gid, pathbuf);
|
||||
}
|
||||
|
||||
/* Read current seq number (base 36). */
|
||||
if (id == 0) {
|
||||
nread = read(fd, buf, sizeof(buf) - 1);
|
||||
if (nread != 0) {
|
||||
if (nread == -1) {
|
||||
goto done;
|
||||
}
|
||||
if (buf[nread - 1] == '\n')
|
||||
nread--;
|
||||
buf[nread] = '\0';
|
||||
id = strtoul(buf, &ep, 36);
|
||||
if (ep == buf || *ep != '\0' || id >= sessid_max) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"%s: bad sequence number: %s", pathbuf, buf);
|
||||
id = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
id++;
|
||||
|
||||
/*
|
||||
* Convert id to a string and stash in sessid.
|
||||
* Note that that least significant digits go at the end of the string.
|
||||
*/
|
||||
for (i = 5; i >= 0; i--) {
|
||||
buf[i] = b36char[id % 36];
|
||||
id /= 36;
|
||||
}
|
||||
buf[6] = '\n';
|
||||
|
||||
/* Stash id for logging purposes. */
|
||||
memcpy(sessid, buf, 6);
|
||||
sessid[6] = '\0';
|
||||
|
||||
/* Rewind and overwrite old seq file, including the NUL byte. */
|
||||
#ifdef HAVE_PWRITE
|
||||
if (pwrite(fd, buf, 7, 0) != 7) {
|
||||
#else
|
||||
if (lseek(fd, 0, SEEK_SET) == -1 || write(fd, buf, 7) != 7) {
|
||||
#endif
|
||||
goto done;
|
||||
}
|
||||
ret = true;
|
||||
|
||||
done:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy iolog_path to pathbuf and create the directory and any intermediate
|
||||
* directories. If iolog_path ends in 'XXXXXX', use mkdtemp().
|
||||
* Returns SIZE_MAX on error.
|
||||
*/
|
||||
size_t
|
||||
mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize)
|
||||
{
|
||||
size_t len;
|
||||
bool ok;
|
||||
debug_decl(mkdir_iopath, SUDO_DEBUG_UTIL)
|
||||
|
||||
len = strlcpy(pathbuf, iolog_path, pathsize);
|
||||
if (len >= pathsize) {
|
||||
errno = ENAMETOOLONG;
|
||||
debug_return_size_t((size_t)-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create path and intermediate subdirs as needed.
|
||||
* If path ends in at least 6 Xs (ala POSIX mktemp), use mkdtemp().
|
||||
* Sets iolog_gid (if it is not already set) as a side effect.
|
||||
*/
|
||||
if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0)
|
||||
ok = io_mkdtemp(pathbuf);
|
||||
else
|
||||
ok = io_mkdirs(pathbuf);
|
||||
|
||||
debug_return_size_t(ok ? len : (size_t)-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append suffix to pathbuf after len chars and open the resulting file.
|
||||
* Note that the size of pathbuf is assumed to be PATH_MAX.
|
||||
* Stores the open file handle which has the close-on-exec flag set.
|
||||
* XXX - move enabled logic into caller?
|
||||
*/
|
||||
bool
|
||||
iolog_open(struct iolog_file *iol, char *path, const char *mode)
|
||||
{
|
||||
int flags;
|
||||
unsigned char magic[2];
|
||||
debug_decl(iolog_open, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (mode[0] == 'r') {
|
||||
flags = mode[1] == '+' ? O_RDWR : O_RDONLY;
|
||||
} else if (mode[0] == 'w') {
|
||||
flags = O_CREAT|O_TRUNC;
|
||||
flags |= mode[1] == '+' ? O_RDWR : O_WRONLY;
|
||||
} else {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR,
|
||||
"%s: invalid I/O mode %s", __func__, mode);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
|
||||
iol->compressed = false;
|
||||
if (iol->enabled) {
|
||||
int fd = io_open(path, flags);
|
||||
if (fd != -1) {
|
||||
if (*mode == 'w') {
|
||||
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to fchown %d:%d %s", __func__,
|
||||
(int)iolog_uid, (int)iolog_gid, path);
|
||||
}
|
||||
iol->compressed = iolog_compress;
|
||||
} else {
|
||||
/* check for gzip magic number */
|
||||
if (read(fd, magic, sizeof(magic)) == ssizeof(magic)) {
|
||||
if (magic[0] == gzip_magic[0] && magic[1] == gzip_magic[1])
|
||||
iol->compressed = true;
|
||||
}
|
||||
(void)lseek(fd, 0, SEEK_SET);
|
||||
}
|
||||
(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (iol->compressed)
|
||||
iol->fd.g = gzdopen(fd, mode);
|
||||
else
|
||||
#endif
|
||||
iol->fd.f = fdopen(fd, mode);
|
||||
if (iol->fd.v == NULL) {
|
||||
int save_errno = errno;
|
||||
close(fd);
|
||||
errno = save_errno;
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
if (fd == -1) {
|
||||
iol->enabled = false;
|
||||
debug_return_bool(false);
|
||||
}
|
||||
} else {
|
||||
if (*mode == 'w') {
|
||||
/* Remove old log file in case we recycled sequence numbers. */
|
||||
(void)unlink(path);
|
||||
}
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
static const char *
|
||||
gzstrerror(gzFile file)
|
||||
{
|
||||
int errnum;
|
||||
|
||||
return gzerror(file, &errnum);
|
||||
}
|
||||
#endif /* HAVE_ZLIB_H */
|
||||
|
||||
/*
|
||||
* Close an I/O log.
|
||||
*/
|
||||
bool
|
||||
iolog_close(struct iolog_file *iol, const char **errstr)
|
||||
{
|
||||
bool ret = true;
|
||||
debug_decl(iolog_close, SUDO_DEBUG_UTIL)
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (iol->compressed) {
|
||||
if (gzclose(iol->fd.g) != Z_OK) {
|
||||
ret = false;
|
||||
if (errstr != NULL)
|
||||
*errstr = gzstrerror(iol->fd.g);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (fclose(iol->fd.f) != 0) {
|
||||
ret = false;
|
||||
if (errstr != NULL)
|
||||
*errstr = strerror(errno);
|
||||
}
|
||||
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O log wrapper for fseek/gzseek.
|
||||
*/
|
||||
off_t
|
||||
iolog_seek(struct iolog_file *iol, off_t offset, int whence)
|
||||
{
|
||||
off_t ret;
|
||||
//debug_decl(iolog_seek, SUDO_DEBUG_UTIL)
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (iol->compressed)
|
||||
ret = gzseek(iol->fd.g, offset, whence);
|
||||
else
|
||||
#endif
|
||||
#ifdef HAVE_FSEEKO
|
||||
ret = fseeko(iol->fd.f, offset, whence);
|
||||
#else
|
||||
ret = fseek(iol->fd.f, offset, whence);
|
||||
#endif
|
||||
|
||||
//debug_return_off_t(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from a (possibly compressed) I/O log file.
|
||||
*/
|
||||
ssize_t
|
||||
iolog_read(struct iolog_file *iol, void *buf, size_t nbytes,
|
||||
const char **errstr)
|
||||
{
|
||||
ssize_t nread;
|
||||
debug_decl(iolog_read, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (nbytes > UINT_MAX) {
|
||||
errno = EINVAL;
|
||||
if (errstr != NULL)
|
||||
*errstr = strerror(errno);
|
||||
debug_return_ssize_t(-1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (iol->compressed) {
|
||||
if ((nread = gzread(iol->fd.g, buf, nbytes)) == -1) {
|
||||
if (errstr != NULL)
|
||||
*errstr = gzstrerror(iol->fd.g);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
nread = (ssize_t)fread(buf, 1, nbytes, iol->fd.f);
|
||||
if (nread == 0 && ferror(iol->fd.f)) {
|
||||
nread = -1;
|
||||
if (errstr != NULL)
|
||||
*errstr = strerror(errno);
|
||||
}
|
||||
}
|
||||
debug_return_ssize_t(nread);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to an I/O log, optionally compressing.
|
||||
*/
|
||||
ssize_t
|
||||
iolog_write(struct iolog_file *iol, const void *buf, size_t len,
|
||||
const char **errstr)
|
||||
{
|
||||
ssize_t ret;
|
||||
debug_decl(iolog_write, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (len > UINT_MAX) {
|
||||
errno = EINVAL;
|
||||
if (errstr != NULL)
|
||||
*errstr = strerror(errno);
|
||||
debug_return_ssize_t(-1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (iol->compressed) {
|
||||
ret = gzwrite(iol->fd.g, (const voidp)buf, len);
|
||||
if (ret == 0) {
|
||||
ret = -1;
|
||||
if (errstr != NULL)
|
||||
*errstr = gzstrerror(iol->fd.g);
|
||||
goto done;
|
||||
}
|
||||
if (iolog_flush) {
|
||||
if (gzflush(iol->fd.g, Z_SYNC_FLUSH) != Z_OK) {
|
||||
ret = -1;
|
||||
if (errstr != NULL)
|
||||
*errstr = gzstrerror(iol->fd.g);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ret = fwrite(buf, 1, len, iol->fd.f);
|
||||
if (ret == 0) {
|
||||
ret = -1;
|
||||
if (errstr != NULL)
|
||||
*errstr = strerror(errno);
|
||||
goto done;
|
||||
}
|
||||
if (iolog_flush) {
|
||||
if (fflush(iol->fd.f) != 0) {
|
||||
ret = -1;
|
||||
if (errstr != NULL)
|
||||
*errstr = strerror(errno);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
debug_return_ssize_t(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if at end of I/O log file, else false.
|
||||
*/
|
||||
bool
|
||||
iolog_eof(struct iolog_file *iol)
|
||||
{
|
||||
bool ret;
|
||||
debug_decl(iolog_eof, SUDO_DEBUG_UTIL)
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (iol->compressed)
|
||||
ret = gzeof(iol->fd.g) == 1;
|
||||
else
|
||||
#endif
|
||||
ret = feof(iol->fd.f) == 1;
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Like gets() but for struct iolog_file.
|
||||
*/
|
||||
char *
|
||||
iolog_gets(struct iolog_file *iol, char *buf, size_t nbytes,
|
||||
const char **errstr)
|
||||
{
|
||||
char *str;
|
||||
debug_decl(iolog_gets, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (nbytes > UINT_MAX) {
|
||||
errno = EINVAL;
|
||||
if (errstr != NULL)
|
||||
*errstr = strerror(errno);
|
||||
debug_return_str(NULL);
|
||||
}
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (iol->compressed) {
|
||||
if ((str = gzgets(iol->fd.g, buf, nbytes)) == NULL) {
|
||||
if (errstr != NULL)
|
||||
*errstr = gzstrerror(iol->fd.g);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if ((str = fgets(buf, nbytes, iol->fd.f)) == NULL) {
|
||||
if (errstr != NULL)
|
||||
*errstr = strerror(errno);
|
||||
}
|
||||
}
|
||||
debug_return_str(str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the I/O log file that contains the user and command info.
|
||||
* This file is not compressed.
|
||||
*/
|
||||
bool
|
||||
iolog_write_info_file(const char *parent, struct iolog_info *log_info,
|
||||
char * const argv[])
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char * const *av;
|
||||
FILE *fp;
|
||||
int error, len, fd;
|
||||
debug_decl(iolog_info_write_log, SUDO_DEBUG_UTIL)
|
||||
|
||||
len = snprintf(path, sizeof(path), "%s/log", parent);
|
||||
if (len < 0 || len >= ssizeof(path)) {
|
||||
errno = ENAMETOOLONG;
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"%s/log", parent);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
fd = io_open(path, O_CREAT|O_TRUNC|O_WRONLY);
|
||||
if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"unable to open %s", path);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to fchown %d:%d %s", __func__,
|
||||
(int)iolog_uid, (int)iolog_gid, path);
|
||||
}
|
||||
|
||||
fprintf(fp, "%lld:%s:%s:%s:%s:%d:%d\n%s\n",
|
||||
(long long)log_info->tstamp,
|
||||
log_info->user ? log_info->user : "unknown",
|
||||
log_info->runas_user ? log_info->runas_user : RUNAS_DEFAULT,
|
||||
log_info->runas_group ? log_info->runas_group : "",
|
||||
log_info->tty ? log_info->tty : "unknown",
|
||||
log_info->lines, log_info->cols,
|
||||
log_info->cwd ? log_info->cwd : "unknown");
|
||||
fputs(log_info->cmd ? log_info->cmd : "unknown", fp);
|
||||
for (av = argv + 1; *av != NULL; av++) {
|
||||
fputc(' ', fp);
|
||||
fputs(*av, fp);
|
||||
}
|
||||
fputc('\n', fp);
|
||||
fflush(fp);
|
||||
if ((error = ferror(fp))) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"unable to write to I/O log file %s", path);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
debug_return_bool(!error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Map IOFD_* -> name.
|
||||
*/
|
||||
const char *
|
||||
iolog_fd_to_name(int iofd)
|
||||
{
|
||||
const char *ret = NULL;
|
||||
debug_decl(iolog_fd_to_name, SUDO_DEBUG_UTIL)
|
||||
|
||||
switch (iofd) {
|
||||
case IOFD_STDIN:
|
||||
ret = "stdin";
|
||||
break;
|
||||
case IOFD_STDOUT:
|
||||
ret = "stdout";
|
||||
break;
|
||||
case IOFD_STDERR:
|
||||
ret = "stderr";
|
||||
break;
|
||||
case IOFD_TTYIN:
|
||||
ret = "ttyin";
|
||||
break;
|
||||
case IOFD_TTYOUT:
|
||||
ret = "ttyout";
|
||||
break;
|
||||
case IOFD_TIMING:
|
||||
ret = "timing";
|
||||
break;
|
||||
default:
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: unexpected iofd %d",
|
||||
__func__, iofd);
|
||||
break;
|
||||
}
|
||||
debug_return_const_str(ret);
|
||||
}
|
@@ -26,6 +26,11 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
# include <stdbool.h>
|
||||
#else
|
||||
# include "compat/stdbool.h"
|
||||
#endif /* HAVE_STDBOOL_H */
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif /* HAVE_STRING_H */
|
||||
@@ -34,137 +39,35 @@
|
||||
#endif /* HAVE_STRINGS_H */
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <limits.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sudoers.h"
|
||||
#include "sudo_gettext.h" /* must be included before sudo_compat.h */
|
||||
|
||||
struct path_escape {
|
||||
const char *name;
|
||||
size_t (*copy_fn)(char *, size_t, char *);
|
||||
};
|
||||
|
||||
static size_t
|
||||
fill_seq(char *str, size_t strsize, char *logdir)
|
||||
{
|
||||
#ifdef SUDOERS_NO_SEQ
|
||||
debug_decl(fill_seq, SUDOERS_DEBUG_UTIL)
|
||||
debug_return_size_t(strlcpy(str, "%{seq}", strsize));
|
||||
#else
|
||||
static char sessid[7];
|
||||
int len;
|
||||
debug_decl(fill_seq, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
if (sessid[0] == '\0') {
|
||||
if (!io_nextid(logdir, def_iolog_dir, sessid))
|
||||
debug_return_size_t((size_t)-1);
|
||||
}
|
||||
|
||||
/* Path is of the form /var/log/sudo-io/00/00/01. */
|
||||
len = snprintf(str, strsize, "%c%c/%c%c/%c%c", sessid[0],
|
||||
sessid[1], sessid[2], sessid[3], sessid[4], sessid[5]);
|
||||
if (len < 0)
|
||||
debug_return_size_t(strsize); /* handle non-standard snprintf() */
|
||||
debug_return_size_t(len);
|
||||
#endif /* SUDOERS_NO_SEQ */
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_user(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
debug_decl(fill_user, SUDOERS_DEBUG_UTIL)
|
||||
debug_return_size_t(strlcpy(str, user_name, strsize));
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_group(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
struct group *grp;
|
||||
size_t len;
|
||||
debug_decl(fill_group, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
if ((grp = sudo_getgrgid(user_gid)) != NULL) {
|
||||
len = strlcpy(str, grp->gr_name, strsize);
|
||||
sudo_gr_delref(grp);
|
||||
} else {
|
||||
len = strlen(str);
|
||||
len = snprintf(str + len, strsize - len, "#%u",
|
||||
(unsigned int) user_gid);
|
||||
}
|
||||
debug_return_size_t(len);
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_runas_user(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
debug_decl(fill_runas_user, SUDOERS_DEBUG_UTIL)
|
||||
debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize));
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_runas_group(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
struct group *grp;
|
||||
size_t len;
|
||||
debug_decl(fill_runas_group, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
if (runas_gr != NULL) {
|
||||
len = strlcpy(str, runas_gr->gr_name, strsize);
|
||||
} else {
|
||||
if ((grp = sudo_getgrgid(runas_pw->pw_gid)) != NULL) {
|
||||
len = strlcpy(str, grp->gr_name, strsize);
|
||||
sudo_gr_delref(grp);
|
||||
} else {
|
||||
len = strlen(str);
|
||||
len = snprintf(str + len, strsize - len, "#%u",
|
||||
(unsigned int) runas_pw->pw_gid);
|
||||
}
|
||||
}
|
||||
debug_return_size_t(len);
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_hostname(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
debug_decl(fill_hostname, SUDOERS_DEBUG_UTIL)
|
||||
debug_return_size_t(strlcpy(str, user_shost, strsize));
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_command(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
debug_decl(fill_command, SUDOERS_DEBUG_UTIL)
|
||||
debug_return_size_t(strlcpy(str, user_base, strsize));
|
||||
}
|
||||
|
||||
/* Note: "seq" must be first in the list. */
|
||||
static struct path_escape io_path_escapes[] = {
|
||||
{ "seq", fill_seq },
|
||||
{ "user", fill_user },
|
||||
{ "group", fill_group },
|
||||
{ "runas_user", fill_runas_user },
|
||||
{ "runas_group", fill_runas_group },
|
||||
{ "hostname", fill_hostname },
|
||||
{ "command", fill_command },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
#include "sudo_compat.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "sudo_debug.h"
|
||||
#include "sudo_util.h"
|
||||
#include "sudo_iolog.h"
|
||||
|
||||
/*
|
||||
* Concatenate dir + file, expanding any escape sequences.
|
||||
* Returns the concatenated path and sets slashp point to
|
||||
* the path separator between the expanded dir and file.
|
||||
* XXX - simplify by only expanding one thing and removing prefix
|
||||
*/
|
||||
char *
|
||||
expand_iolog_path(const char *prefix, const char *dir, const char *file,
|
||||
char **slashp)
|
||||
char **slashp, const struct iolog_path_escape *escapes)
|
||||
{
|
||||
size_t len, prelen = 0;
|
||||
char *dst, *dst0, *path, *pathend, tmpbuf[PATH_MAX];
|
||||
char *slash = NULL;
|
||||
const char *endbrace, *src = dir;
|
||||
struct path_escape *escapes = NULL;
|
||||
int pass, oldlocale;
|
||||
int pass;
|
||||
bool strfit;
|
||||
debug_decl(expand_iolog_path, SUDOERS_DEBUG_UTIL)
|
||||
debug_decl(expand_iolog_path, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Expanded path must be <= PATH_MAX */
|
||||
if (prefix != NULL)
|
||||
@@ -194,7 +97,7 @@ expand_iolog_path(const char *prefix, const char *dir, const char *file,
|
||||
switch (pass) {
|
||||
case 0:
|
||||
src = dir;
|
||||
escapes = io_path_escapes + 1; /* skip "%{seq}" */
|
||||
escapes++; /* skip "%{seq}" */
|
||||
break;
|
||||
case 1:
|
||||
/* Trim trailing slashes from dir component. */
|
||||
@@ -207,7 +110,7 @@ expand_iolog_path(const char *prefix, const char *dir, const char *file,
|
||||
continue;
|
||||
case 2:
|
||||
src = file;
|
||||
escapes = io_path_escapes;
|
||||
escapes--; /* restore "%{seq}" */
|
||||
break;
|
||||
}
|
||||
dst0 = dst;
|
||||
@@ -216,7 +119,7 @@ expand_iolog_path(const char *prefix, const char *dir, const char *file,
|
||||
if (src[1] == '{') {
|
||||
endbrace = strchr(src + 2, '}');
|
||||
if (endbrace != NULL) {
|
||||
struct path_escape *esc;
|
||||
const struct iolog_path_escape *esc;
|
||||
len = (size_t)(endbrace - src - 2);
|
||||
for (esc = escapes; esc->name != NULL; esc++) {
|
||||
if (strncmp(src + 2, esc->name, len) == 0 &&
|
||||
@@ -238,7 +141,7 @@ expand_iolog_path(const char *prefix, const char *dir, const char *file,
|
||||
src++;
|
||||
} else {
|
||||
/* May need strftime() */
|
||||
strfit = 1;
|
||||
strfit = true;
|
||||
}
|
||||
}
|
||||
/* Need at least 2 chars, including the NUL terminator. */
|
||||
@@ -257,16 +160,10 @@ expand_iolog_path(const char *prefix, const char *dir, const char *file,
|
||||
if ((timeptr = localtime(&now)) == NULL)
|
||||
goto bad;
|
||||
|
||||
/* Use sudoers locale for strftime() */
|
||||
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
|
||||
|
||||
/* We only call strftime() on the current part of the buffer. */
|
||||
tmpbuf[sizeof(tmpbuf) - 1] = '\0';
|
||||
len = strftime(tmpbuf, sizeof(tmpbuf), dst0, timeptr);
|
||||
|
||||
/* Restore old locale. */
|
||||
sudoers_setlocale(oldlocale, NULL);
|
||||
|
||||
if (len == 0 || tmpbuf[sizeof(tmpbuf) - 1] != '\0')
|
||||
goto bad; /* strftime() failed, buf too small? */
|
||||
|
@@ -26,6 +26,11 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
# include <stdbool.h>
|
||||
#else
|
||||
# include "compat/stdbool.h"
|
||||
#endif /* HAVE_STDBOOL_H */
|
||||
#if defined(HAVE_STDINT_H)
|
||||
# include <stdint.h>
|
||||
#elif defined(HAVE_INTTYPES_H)
|
||||
@@ -44,11 +49,6 @@
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
# include <stdbool.h>
|
||||
#else
|
||||
# include "compat/stdbool.h"
|
||||
#endif /* HAVE_STDBOOL_H */
|
||||
|
||||
#include "sudo_gettext.h" /* must be included before sudo_compat.h */
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
#include "sudo_fatal.h"
|
||||
#include "sudo_debug.h"
|
||||
#include "sudo_util.h"
|
||||
#include "iolog_util.h"
|
||||
#include "sudo_iolog.h"
|
||||
|
||||
static int timing_event_adj;
|
||||
|
||||
@@ -311,8 +311,8 @@ parse_timing(const char *line, struct timing_closure *timing)
|
||||
char *cp, *ep;
|
||||
debug_decl(parse_timing, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Clear fd. */
|
||||
timing->fd.v = NULL;
|
||||
/* Clear iolog descriptor. */
|
||||
timing->iol = NULL;
|
||||
|
||||
/* Parse event type. */
|
||||
ulval = strtoul(line, &ep, 10);
|
@@ -27,19 +27,25 @@
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif /* HAVE_STRINGS_H */
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define SUDO_ERROR_WRAP 0
|
||||
|
||||
#include "sudoers.h"
|
||||
#include "def_data.c"
|
||||
#include "sudo_compat.h"
|
||||
#include "sudo_util.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "sudo_iolog.h"
|
||||
|
||||
struct sudo_user sudo_user;
|
||||
struct passwd *list_pw;
|
||||
|
||||
static char sessid[7];
|
||||
static struct iolog_escape_data {
|
||||
char sessid[7];
|
||||
char *user;
|
||||
char *group;
|
||||
char *runas_user;
|
||||
char *runas_group;
|
||||
char *host;
|
||||
char *command;
|
||||
} escape_data;
|
||||
|
||||
__dso_public int main(int argc, char *argv[]);
|
||||
|
||||
@@ -50,6 +56,80 @@ usage(void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
reset_escape_data(struct iolog_escape_data *data)
|
||||
{
|
||||
free(data->user);
|
||||
free(data->group);
|
||||
free(data->runas_user);
|
||||
free(data->runas_group);
|
||||
free(data->host);
|
||||
free(data->command);
|
||||
memset(data, 0, sizeof(*data));
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_seq(char *str, size_t strsize, char *logdir)
|
||||
{
|
||||
int len;
|
||||
|
||||
/* Path is of the form /var/log/sudo-io/00/00/01. */
|
||||
len = snprintf(str, strsize, "%c%c/%c%c/%c%c", escape_data.sessid[0],
|
||||
escape_data.sessid[1], escape_data.sessid[2], escape_data.sessid[3],
|
||||
escape_data.sessid[4], escape_data.sessid[5]);
|
||||
if (len < 0)
|
||||
return strsize; /* handle non-standard snprintf() */
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_user(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
return strlcpy(str, escape_data.user, strsize);
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_group(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
return strlcpy(str, escape_data.group, strsize);
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_runas_user(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
return strlcpy(str, escape_data.runas_user, strsize);
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_runas_group(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
return strlcpy(str, escape_data.runas_group, strsize);
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_hostname(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
return strlcpy(str, escape_data.host, strsize);
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_command(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
return strlcpy(str, escape_data.command, strsize);
|
||||
}
|
||||
|
||||
/* Note: "seq" must be first in the list. */
|
||||
static struct iolog_path_escape path_escapes[] = {
|
||||
{ "seq", fill_seq },
|
||||
{ "user", fill_user },
|
||||
{ "group", fill_group },
|
||||
{ "runas_user", fill_runas_user },
|
||||
{ "runas_group", fill_runas_group },
|
||||
{ "hostname", fill_hostname },
|
||||
{ "command", fill_command },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out)
|
||||
{
|
||||
@@ -70,7 +150,7 @@ do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out)
|
||||
strftime(dir_out, sizeof(dir_out), tdir_out, timeptr);
|
||||
strftime(file_out, sizeof(file_out), tfile_out, timeptr);
|
||||
|
||||
path = expand_iolog_path(NULL, dir_in, file_in, &slash);
|
||||
path = expand_iolog_path(NULL, dir_in, file_in, &slash, path_escapes);
|
||||
if (path == NULL)
|
||||
sudo_fatalx("unable to expand I/O log path");
|
||||
*slash = '\0';
|
||||
@@ -92,13 +172,11 @@ do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out)
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct passwd pw, rpw;
|
||||
size_t len;
|
||||
FILE *fp;
|
||||
char line[2048];
|
||||
char *file_in = NULL, *file_out = NULL;
|
||||
char *dir_in = NULL, *dir_out = NULL;
|
||||
const char *errstr;
|
||||
int state = 0;
|
||||
int errors = 0;
|
||||
int tests = 0;
|
||||
@@ -112,11 +190,6 @@ main(int argc, char *argv[])
|
||||
if (fp == NULL)
|
||||
sudo_fatalx("unable to open %s", argv[1]);
|
||||
|
||||
memset(&pw, 0, sizeof(pw));
|
||||
memset(&rpw, 0, sizeof(rpw));
|
||||
sudo_user.pw = &pw;
|
||||
sudo_user._runas_pw = &rpw;
|
||||
|
||||
/*
|
||||
* Input consists of 12 lines:
|
||||
* sequence number
|
||||
@@ -138,37 +211,31 @@ main(int argc, char *argv[])
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
strlcpy(sessid, line, sizeof(sessid));
|
||||
strlcpy(escape_data.sessid, line, sizeof(escape_data.sessid));
|
||||
break;
|
||||
case 1:
|
||||
if (user_name != NULL)
|
||||
free(user_name);
|
||||
user_name = strdup(line);
|
||||
if ((escape_data.user = strdup(line)) == NULL)
|
||||
sudo_fatal(NULL);
|
||||
break;
|
||||
case 2:
|
||||
user_gid = (gid_t)sudo_strtoid(line, &errstr);
|
||||
if (errstr != NULL)
|
||||
sudo_fatalx("group ID %s: %s", line, errstr);
|
||||
if ((escape_data.group = strdup(line)) == NULL)
|
||||
sudo_fatal(NULL);
|
||||
break;
|
||||
case 3:
|
||||
if (runas_pw->pw_name != NULL)
|
||||
free(runas_pw->pw_name);
|
||||
runas_pw->pw_name = strdup(line);
|
||||
if ((escape_data.runas_user = strdup(line)) == NULL)
|
||||
sudo_fatal(NULL);
|
||||
break;
|
||||
case 4:
|
||||
runas_pw->pw_gid = (gid_t)sudo_strtoid(line, &errstr);
|
||||
if (errstr != NULL)
|
||||
sudo_fatalx("group ID %s: %s", line, errstr);
|
||||
if ((escape_data.runas_group = strdup(line)) == NULL)
|
||||
sudo_fatal(NULL);
|
||||
break;
|
||||
case 5:
|
||||
if (user_shost != NULL)
|
||||
free(user_shost);
|
||||
user_shost = strdup(line);
|
||||
if ((escape_data.host = strdup(line)) == NULL)
|
||||
sudo_fatal(NULL);
|
||||
break;
|
||||
case 6:
|
||||
if (user_base != NULL)
|
||||
free(user_base);
|
||||
user_base = strdup(line);
|
||||
if ((escape_data.command = strdup(line)) == NULL)
|
||||
sudo_fatal(NULL);
|
||||
break;
|
||||
case 7:
|
||||
if (dir_in != NULL)
|
||||
@@ -193,6 +260,7 @@ main(int argc, char *argv[])
|
||||
case 11:
|
||||
errors += do_check(dir_in, file_in, dir_out, file_out);
|
||||
tests++;
|
||||
reset_escape_data(&escape_data);
|
||||
break;
|
||||
default:
|
||||
sudo_fatalx("internal error, invalid state %d", state);
|
||||
@@ -208,10 +276,3 @@ main(int argc, char *argv[])
|
||||
|
||||
exit(errors);
|
||||
}
|
||||
|
||||
bool
|
||||
io_nextid(char *iolog_dir, char *fallback, char id[7])
|
||||
{
|
||||
memcpy(id, sessid, sizeof(sessid));
|
||||
return true;
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
000001
|
||||
nobody
|
||||
1
|
||||
nogroup
|
||||
root
|
||||
root
|
||||
0
|
||||
somehost
|
||||
id
|
||||
/var/log/sudo-io
|
||||
@@ -12,9 +12,9 @@ id
|
||||
|
||||
000001
|
||||
nobody
|
||||
1
|
||||
nogroup
|
||||
root
|
||||
0
|
||||
wheel
|
||||
somehost
|
||||
id
|
||||
/var/log/sudo-io
|
||||
@@ -24,9 +24,9 @@ id
|
||||
|
||||
000001
|
||||
nobody
|
||||
1
|
||||
nogroup
|
||||
root
|
||||
0
|
||||
wheel
|
||||
somehost
|
||||
id
|
||||
/var/log/sudo-io
|
||||
@@ -36,9 +36,9 @@ id
|
||||
|
||||
000001
|
||||
nobody
|
||||
1
|
||||
nogroup
|
||||
root
|
||||
0
|
||||
wheel
|
||||
somehost
|
||||
id
|
||||
/var/log/sudo-io/%{user}
|
||||
@@ -48,9 +48,9 @@ id
|
||||
|
||||
000001
|
||||
nobody
|
||||
1
|
||||
nogroup
|
||||
root
|
||||
0
|
||||
wheel
|
||||
somehost
|
||||
su
|
||||
/var/log/sudo-io/%{user}/%{runas_user}
|
||||
@@ -60,9 +60,9 @@ su_%Y%m%s_%H%M
|
||||
|
||||
000001
|
||||
nobody
|
||||
1
|
||||
nogroup
|
||||
root
|
||||
0
|
||||
wheel
|
||||
somehost
|
||||
su
|
||||
/var/log/sudo-io/
|
||||
@@ -72,9 +72,9 @@ nobody/root/su_%Y%m%s_%H%M
|
||||
|
||||
000001
|
||||
nobody
|
||||
1
|
||||
nogroup
|
||||
root
|
||||
0
|
||||
wheel
|
||||
somehost
|
||||
su
|
||||
/var/log/sudo-io/%d%m%Y
|
||||
@@ -84,9 +84,9 @@ nobody/root/su
|
||||
|
||||
000001
|
||||
nobody
|
||||
1
|
||||
nogroup
|
||||
root
|
||||
0
|
||||
wheel
|
||||
somehost
|
||||
su
|
||||
////////
|
@@ -35,7 +35,7 @@
|
||||
#include "sudo_compat.h"
|
||||
#include "sudo_util.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "iolog_util.h"
|
||||
#include "sudo_iolog.h"
|
||||
|
||||
__dso_public int main(int argc, char *argv[]);
|
||||
|
||||
@@ -137,14 +137,14 @@ main(int argc, char *argv[])
|
||||
{
|
||||
int tests = 0, errors = 0;
|
||||
|
||||
initprogname(argc > 0 ? argv[0] : "check_iolog_reader");
|
||||
initprogname(argc > 0 ? argv[0] : "check_iolog_util");
|
||||
|
||||
test_parse_delay(&tests, &errors);
|
||||
|
||||
test_adjust_delay(&tests, &errors);
|
||||
|
||||
if (tests != 0) {
|
||||
printf("check_iolog_reader: %d test%s run, %d errors, %d%% success rate\n",
|
||||
printf("iolog_util: %d test%s run, %d errors, %d%% success rate\n",
|
||||
tests, tests == 1 ? "" : "s", errors,
|
||||
(tests - errors) * 100 / tests);
|
||||
}
|
@@ -56,12 +56,6 @@
|
||||
#include "sudo_debug.h"
|
||||
#include "sudo_util.h"
|
||||
|
||||
#ifdef __TANDEM
|
||||
# define ROOT_UID 65535
|
||||
#else
|
||||
# define ROOT_UID 0
|
||||
#endif
|
||||
|
||||
struct sudo_conf_table {
|
||||
const char *name;
|
||||
unsigned int namelen;
|
||||
|
@@ -24,7 +24,6 @@ srcdir = @srcdir@
|
||||
devdir = @devdir@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
sudoers_srcdir = @top_srcdir@/plugins/sudoers
|
||||
incdir = $(top_srcdir)/include
|
||||
rundir = @rundir@
|
||||
cross_compiling = @CROSS_COMPILING@
|
||||
@@ -40,7 +39,7 @@ INSTALL_OWNER = -o $(install_uid) -g $(install_gid)
|
||||
INSTALL_BACKUP = @INSTALL_BACKUP@
|
||||
|
||||
# Libraries
|
||||
LT_LIBS = $(top_builddir)/lib/util/libsudo_util.la
|
||||
LT_LIBS = $(top_builddir)/lib/iolog/libsudo_iolog.la
|
||||
LIBS = $(LT_LIBS)
|
||||
|
||||
# C preprocessor defines
|
||||
@@ -49,7 +48,7 @@ CPPDEFS = -D_PATH_SUDO_LOGSRVD_CONF=\"$(sysconfdir)/sudo_logsrvd.conf\" \
|
||||
|
||||
# C preprocessor flags
|
||||
CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(devdir) -I$(srcdir) \
|
||||
-I$(sudoers_srcdir) -I$(top_srcdir) $(CPPDEFS) @CPPFLAGS@
|
||||
-I$(top_srcdir) $(CPPDEFS) @CPPFLAGS@
|
||||
|
||||
# Usually -O and/or -g
|
||||
CFLAGS = @CFLAGS@
|
||||
@@ -108,10 +107,10 @@ SHELL = @SHELL@
|
||||
|
||||
PROGS = logsrvd sendlog
|
||||
|
||||
LOGSRVD_OBJS = iolog_util.o iolog_writer.o logsrvd.o logsrvd_conf.o \
|
||||
log_server.pb-c.o protobuf-c.o
|
||||
LOGSRVD_OBJS = iolog_writer.o logsrvd.o \
|
||||
logsrvd_conf.o log_server.pb-c.o protobuf-c.o
|
||||
|
||||
SENDLOG_OBJS = sendlog.o iolog_util.o log_server.pb-c.o protobuf-c.o
|
||||
SENDLOG_OBJS = sendlog.o log_server.pb-c.o protobuf-c.o
|
||||
|
||||
IOBJS = $(LOGSRVD_OBJS:.o=.i) $(SENDLOG_OBJS:.o=.i)
|
||||
|
||||
@@ -144,7 +143,7 @@ logsrvd: $(LOGSRVD_OBJS) $(LT_LIBS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(LOGSRVD_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
sendlog: $(SENDLOG_OBJS) $(LT_LIBS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(SENDLOG_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) -lz
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(SENDLOG_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
GENERATED = log_server.pb-c.h log_server.pb-c.c
|
||||
|
||||
@@ -212,37 +211,19 @@ realclean: distclean
|
||||
cleandir: realclean
|
||||
|
||||
# Autogenerated dependencies, do not modify
|
||||
iolog_util.o: plugins/sudoers/iolog_util.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(sudoers_srcdir)/iolog.h $(sudoers_srcdir)/iolog_util.h \
|
||||
$(top_builddir)/config.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) plugins/sudoers/iolog_util.c
|
||||
iolog_util.i: plugins/sudoers/iolog_util.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(sudoers_srcdir)/iolog.h $(sudoers_srcdir)/iolog_util.h \
|
||||
$(top_builddir)/config.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
iolog_util.plog: iolog_util.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file plugins/sudoers/iolog_util.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_fatal.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/logsrvd.h $(srcdir)/protobuf-c/protobuf-c.h \
|
||||
$(sudoers_srcdir)/iolog.h $(sudoers_srcdir)/iolog_util.h \
|
||||
$(top_builddir)/config.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)/iolog_writer.c
|
||||
iolog_writer.i: $(srcdir)/iolog_writer.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_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/logsrvd.h $(srcdir)/protobuf-c/protobuf-c.h \
|
||||
$(sudoers_srcdir)/iolog.h $(sudoers_srcdir)/iolog_util.h \
|
||||
$(top_builddir)/config.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) $<
|
||||
iolog_writer.plog: iolog_writer.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog_writer.c --i-file $< --output-file $@
|
||||
@@ -258,34 +239,36 @@ logsrvd.o: $(srcdir)/logsrvd.c $(devdir)/log_server.pb-c.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h $(incdir)/sudo_event.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_rand.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/logsrvd.h $(srcdir)/protobuf-c/protobuf-c.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_queue.h $(incdir)/sudo_rand.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/logsrvd.h \
|
||||
$(srcdir)/protobuf-c/protobuf-c.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/logsrvd.c
|
||||
logsrvd.i: $(srcdir)/logsrvd.c $(devdir)/log_server.pb-c.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h $(incdir)/sudo_event.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_rand.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/logsrvd.h $(srcdir)/protobuf-c/protobuf-c.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_queue.h $(incdir)/sudo_rand.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/logsrvd.h \
|
||||
$(srcdir)/protobuf-c/protobuf-c.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
logsrvd.plog: logsrvd.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/logsrvd.c --i-file $< --output-file $@
|
||||
logsrvd_conf.o: $(srcdir)/logsrvd_conf.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_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/logsrvd.h \
|
||||
$(srcdir)/protobuf-c/protobuf-c.h $(sudoers_srcdir)/iolog.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 $(top_builddir)/pathnames.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/logsrvd_conf.c
|
||||
logsrvd_conf.i: $(srcdir)/logsrvd_conf.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_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/logsrvd.h \
|
||||
$(srcdir)/protobuf-c/protobuf-c.h $(sudoers_srcdir)/iolog.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 $(top_builddir)/pathnames.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
logsrvd_conf.plog: logsrvd_conf.i
|
||||
@@ -301,9 +284,8 @@ sendlog.o: $(srcdir)/sendlog.c $(devdir)/log_server.pb-c.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||
$(incdir)/sudo_debug.h $(incdir)/sudo_event.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/protobuf-c/protobuf-c.h $(srcdir)/sendlog.h \
|
||||
$(sudoers_srcdir)/iolog.h $(sudoers_srcdir)/iolog_util.h \
|
||||
$(top_builddir)/config.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/sendlog.c
|
||||
sendlog.i: $(srcdir)/sendlog.c $(devdir)/log_server.pb-c.h \
|
||||
@@ -311,9 +293,8 @@ sendlog.i: $(srcdir)/sendlog.c $(devdir)/log_server.pb-c.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||
$(incdir)/sudo_debug.h $(incdir)/sudo_event.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/protobuf-c/protobuf-c.h $(srcdir)/sendlog.h \
|
||||
$(sudoers_srcdir)/iolog.h $(sudoers_srcdir)/iolog_util.h \
|
||||
$(top_builddir)/config.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
sendlog.plog: sendlog.i
|
||||
|
@@ -42,20 +42,9 @@
|
||||
#include "sudo_debug.h"
|
||||
#include "sudo_util.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "iolog_util.h"
|
||||
#include "sudo_iolog.h"
|
||||
#include "logsrvd.h"
|
||||
|
||||
/* I/O log file names relative to iolog_dir. */
|
||||
static const char *iolog_names[] = {
|
||||
"stdin", /* IOFD_STDIN */
|
||||
"stdout", /* IOFD_STDOUT */
|
||||
"stderr", /* IOFD_STDERR */
|
||||
"ttyin", /* IOFD_TTYIN */
|
||||
"ttyout", /* IOFD_TTYOUT */
|
||||
"timing", /* IOFD_TIMING */
|
||||
NULL /* IOFD_MAX */
|
||||
};
|
||||
|
||||
static inline bool
|
||||
has_numval(InfoMessage *info)
|
||||
{
|
||||
@@ -284,13 +273,13 @@ create_iolog_dir(struct iolog_details *details, struct connection_closure *closu
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Make a copy of iolog_dir for error messages. */
|
||||
if ((closure->iolog_dir = strdup(path)) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"strdup");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* We use iolog_dir_fd in calls to openat(2) */
|
||||
closure->iolog_dir_fd = open(closure->iolog_dir, O_RDONLY);
|
||||
if (closure->iolog_dir_fd == -1) {
|
||||
@@ -298,6 +287,7 @@ create_iolog_dir(struct iolog_details *details, struct connection_closure *closu
|
||||
"%s", closure->iolog_dir);
|
||||
goto bad;
|
||||
}
|
||||
#endif
|
||||
|
||||
debug_return_bool(true);
|
||||
bad:
|
||||
@@ -349,9 +339,11 @@ iolog_details_write(struct iolog_details *details, struct connection_closure *cl
|
||||
}
|
||||
|
||||
static bool
|
||||
iolog_open(int iofd, struct connection_closure *closure)
|
||||
iolog_create(int iofd, struct connection_closure *closure)
|
||||
{
|
||||
debug_decl(iolog_open, SUDO_DEBUG_UTIL)
|
||||
char path[PATH_MAX];
|
||||
int len;
|
||||
debug_decl(iolog_create, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (iofd < 0 || iofd >= IOFD_MAX) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
@@ -359,24 +351,34 @@ iolog_open(int iofd, struct connection_closure *closure)
|
||||
debug_return_bool(false);
|
||||
}
|
||||
|
||||
closure->io_fds[iofd] = openat(closure->iolog_dir_fd,
|
||||
iolog_names[iofd], O_CREAT|O_EXCL|O_WRONLY, 0600);
|
||||
debug_return_bool(closure->io_fds[iofd] != -1);
|
||||
len = snprintf(path, sizeof(path), "%s/%s", closure->iolog_dir,
|
||||
iolog_fd_to_name(iofd));
|
||||
if (len < 0 || len >= ssizeof(path)) {
|
||||
errno = ENAMETOOLONG;
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"%s/%s", closure->iolog_dir, iolog_fd_to_name(iofd));
|
||||
debug_return_bool(false);
|
||||
}
|
||||
|
||||
closure->iolog_files[iofd].enabled = true;
|
||||
debug_return_bool(iolog_open(&closure->iolog_files[iofd], path, "w"));
|
||||
}
|
||||
|
||||
void
|
||||
iolog_close(struct connection_closure *closure)
|
||||
iolog_close_all(struct connection_closure *closure)
|
||||
{
|
||||
const char *errstr;
|
||||
int i;
|
||||
debug_decl(iolog_close, SUDO_DEBUG_UTIL)
|
||||
|
||||
for (i = 0; i < IOFD_MAX; i++) {
|
||||
if (closure->io_fds[i] == -1)
|
||||
if (!closure->iolog_files[i].enabled)
|
||||
continue;
|
||||
close(closure->io_fds[i]);
|
||||
if (!iolog_close(&closure->iolog_files[i], &errstr)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"error closing iofd %d: %s", i, errstr);
|
||||
}
|
||||
}
|
||||
if (closure->iolog_dir_fd != -1)
|
||||
close(closure->iolog_dir_fd);
|
||||
|
||||
debug_return;
|
||||
}
|
||||
@@ -385,13 +387,8 @@ bool
|
||||
iolog_init(ExecMessage *msg, struct connection_closure *closure)
|
||||
{
|
||||
struct iolog_details details;
|
||||
int i;
|
||||
debug_decl(iolog_init, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Init io_fds in closure. */
|
||||
for (i = 0; i < IOFD_MAX; i++)
|
||||
closure->io_fds[i] = -1;
|
||||
|
||||
/* Fill in iolog_details */
|
||||
if (!iolog_details_fill(&details, msg))
|
||||
debug_return_bool(false);
|
||||
@@ -404,11 +401,14 @@ iolog_init(ExecMessage *msg, struct connection_closure *closure)
|
||||
if (!iolog_details_write(&details, closure))
|
||||
debug_return_bool(false);
|
||||
|
||||
/* Create timing, stdout, stderr and ttyout files for sudoreplay. */
|
||||
if (!iolog_open(IOFD_TIMING, closure) ||
|
||||
!iolog_open(IOFD_STDOUT, closure) ||
|
||||
!iolog_open(IOFD_STDERR, closure) ||
|
||||
!iolog_open(IOFD_TTYOUT, closure))
|
||||
/*
|
||||
* Create timing, stdout, stderr and ttyout files for sudoreplay.
|
||||
* Others will be created on demand.
|
||||
*/
|
||||
if (!iolog_create(IOFD_TIMING, closure) ||
|
||||
!iolog_create(IOFD_STDOUT, closure) ||
|
||||
!iolog_create(IOFD_STDERR, closure) ||
|
||||
!iolog_create(IOFD_TTYOUT, closure))
|
||||
debug_return_bool(false);
|
||||
|
||||
/* Ready to log I/O buffers. */
|
||||
@@ -420,18 +420,19 @@ iolog_init(ExecMessage *msg, struct connection_closure *closure)
|
||||
* Return 0 on success, 1 on EOF and -1 on error.
|
||||
*/
|
||||
static int
|
||||
read_timing_record(FILE *fp, struct timing_closure *timing)
|
||||
read_timing_record(struct iolog_file *iol, struct timing_closure *timing)
|
||||
{
|
||||
char line[LINE_MAX];
|
||||
const char *errstr;
|
||||
debug_decl(read_timing_record, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Read next record from timing file. */
|
||||
if (fgets(line, sizeof(line), fp) == NULL) {
|
||||
if (iolog_gets(iol, line, sizeof(line), &errstr) == NULL) {
|
||||
/* EOF or error reading timing file, we are done. */
|
||||
if (feof(fp))
|
||||
if (iolog_eof(iol))
|
||||
debug_return_int(1); /* EOF */
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"error reading timing file");
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"error reading timing file: %s", errstr);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
@@ -446,80 +447,65 @@ read_timing_record(FILE *fp, struct timing_closure *timing)
|
||||
debug_return_int(0);
|
||||
}
|
||||
|
||||
/* XXX - compressed I/O logs cannot be restarted, must re-write them */
|
||||
bool
|
||||
iolog_restart(RestartMessage *msg, struct connection_closure *closure)
|
||||
{
|
||||
struct timespec target;
|
||||
struct timing_closure timing;
|
||||
FILE *fp = NULL;
|
||||
int i, fd;
|
||||
off_t length;
|
||||
off_t pos;
|
||||
int i;
|
||||
debug_decl(iolog_init, SUDO_DEBUG_UTIL)
|
||||
|
||||
target.tv_sec = msg->resume_point->tv_sec;
|
||||
target.tv_nsec = msg->resume_point->tv_nsec;
|
||||
|
||||
/* We use iolog_dir_fd in calls to openat(2) */
|
||||
if ((closure->iolog_dir = strdup(msg->log_id)) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"strdup");
|
||||
goto bad;
|
||||
}
|
||||
closure->iolog_dir_fd = open(closure->iolog_dir, O_RDONLY);
|
||||
if (closure->iolog_dir_fd == -1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"%s", closure->iolog_dir);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Open existing I/O log files. */
|
||||
for (i = 0; i < IOFD_MAX; i++) {
|
||||
closure->io_fds[i] = openat(closure->iolog_dir_fd, iolog_names[i],
|
||||
O_RDWR, 0600);
|
||||
char path[PATH_MAX];
|
||||
int len = snprintf(path, sizeof(path), "%s/%s", closure->iolog_dir,
|
||||
iolog_fd_to_name(i));
|
||||
if (len < 0 || len >= ssizeof(path)) {
|
||||
errno = ENAMETOOLONG;
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: %s/%s", __func__, closure->iolog_dir, iolog_fd_to_name(i));
|
||||
goto bad;
|
||||
}
|
||||
closure->iolog_files[i].enabled = true;
|
||||
(void)iolog_open(&closure->iolog_files[i], path, "r+");
|
||||
}
|
||||
|
||||
/* Dup IOFD_TIMING to a stream for easier processing. */
|
||||
if (closure->io_fds[IOFD_TIMING] == -1)
|
||||
if (!closure->iolog_files[IOFD_TIMING].enabled)
|
||||
goto bad;
|
||||
if ((fd = dup(closure->io_fds[IOFD_TIMING])) == -1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"dup");
|
||||
goto bad;
|
||||
}
|
||||
if ((fp = fdopen(fd, "r")) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"fdopen");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Parse timing file until we reach the target point. */
|
||||
/* XXX - split up */
|
||||
for (;;) {
|
||||
if (read_timing_record(fp, &timing) != 0)
|
||||
if (read_timing_record(&closure->iolog_files[IOFD_TIMING], &timing) != 0)
|
||||
goto bad;
|
||||
sudo_timespecadd(&timing.delay, &closure->elapsed_time,
|
||||
&closure->elapsed_time);
|
||||
if (timing.event < IOFD_TIMING) {
|
||||
if (closure->io_fds[timing.event] == -1) {
|
||||
if (!closure->iolog_files[timing.event].enabled) {
|
||||
/* Missing log file. */
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"iofd %d referenced but not open", timing.event);
|
||||
goto bad;
|
||||
}
|
||||
length = lseek(closure->io_fds[timing.event], timing.u.nbytes,
|
||||
SEEK_CUR);
|
||||
if (length == -1) {
|
||||
pos = iolog_seek(&closure->iolog_files[timing.event],
|
||||
timing.u.nbytes, SEEK_CUR);
|
||||
if (pos == -1) {
|
||||
sudo_debug_printf(
|
||||
SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"lseek(%d, %lld, SEEK_CUR", closure->io_fds[timing.event],
|
||||
"seek(%d, %lld, SEEK_CUR", timing.event,
|
||||
(long long)timing.u.nbytes);
|
||||
goto bad;
|
||||
}
|
||||
if (ftruncate(closure->io_fds[timing.event], length) == -1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"ftruncate(%d, %lld)", closure->io_fds[IOFD_TIMING], length);
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
if (sudo_timespeccmp(&closure->elapsed_time, &target, >=)) {
|
||||
if (sudo_timespeccmp(&closure->elapsed_time, &target, ==))
|
||||
@@ -534,47 +520,19 @@ iolog_restart(RestartMessage *msg, struct connection_closure *closure)
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
/* Update timing file position after determining resume point. */
|
||||
#ifdef HAVE_FSEEKO
|
||||
length = ftello(fp);
|
||||
#else
|
||||
length = ftell(fp);
|
||||
#endif
|
||||
fclose(fp);
|
||||
if (lseek(closure->io_fds[IOFD_TIMING], length, SEEK_SET) == -1) {
|
||||
/* Must seek or flush before switching from read -> write. */
|
||||
if (iolog_seek(&closure->iolog_files[IOFD_TIMING], 0, SEEK_CUR) == -1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"lseek(%d, %lld, SEEK_SET", closure->io_fds[IOFD_TIMING], length);
|
||||
goto bad;
|
||||
}
|
||||
if (ftruncate(closure->io_fds[IOFD_TIMING], length) == -1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"ftruncate(%d, %lld)", closure->io_fds[IOFD_TIMING], length);
|
||||
"lseek(IOFD_TIMING, 0, SEEK_CUR)");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Ready to log I/O buffers. */
|
||||
debug_return_bool(true);
|
||||
bad:
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
|
||||
static bool
|
||||
iolog_write(int iofd, void *buf, size_t len, struct connection_closure *closure)
|
||||
{
|
||||
debug_decl(iolog_write, SUDO_DEBUG_UTIL)
|
||||
size_t nread;
|
||||
|
||||
if (iofd < 0 || iofd >= IOFD_MAX) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"invalid iofd %d", iofd);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
nread = write(closure->io_fds[iofd], buf, len);
|
||||
debug_return_bool(nread == len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add given delta to elapsed time.
|
||||
* We cannot use timespecadd here since delta is not struct timespec.
|
||||
@@ -598,13 +556,14 @@ update_elapsed_time(TimeSpec *delta, struct timespec *elapsed)
|
||||
int
|
||||
store_iobuf(int iofd, IoBuffer *msg, struct connection_closure *closure)
|
||||
{
|
||||
const char *errstr;
|
||||
char tbuf[1024];
|
||||
int len;
|
||||
debug_decl(store_iobuf, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Open log file as needed. */
|
||||
if (closure->io_fds[iofd] == -1) {
|
||||
if (!iolog_open(iofd, closure))
|
||||
if (!closure->iolog_files[iofd].enabled) {
|
||||
if (!iolog_create(iofd, closure))
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
@@ -620,12 +579,22 @@ store_iobuf(int iofd, IoBuffer *msg, struct connection_closure *closure)
|
||||
}
|
||||
|
||||
/* Write to specified I/O log file. */
|
||||
if (!iolog_write(iofd, msg->data.data, msg->data.len, 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,
|
||||
iolog_fd_to_name(iofd), errstr);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
/* Write timing data. */
|
||||
if (!iolog_write(IOFD_TIMING, tbuf, len, 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,
|
||||
iolog_fd_to_name(IOFD_TIMING), errstr);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
update_elapsed_time(msg->delay, &closure->elapsed_time);
|
||||
|
||||
@@ -635,6 +604,7 @@ store_iobuf(int iofd, IoBuffer *msg, struct connection_closure *closure)
|
||||
int
|
||||
store_suspend(CommandSuspend *msg, struct connection_closure *closure)
|
||||
{
|
||||
const char *errstr;
|
||||
char tbuf[1024];
|
||||
int len;
|
||||
debug_decl(store_suspend, SUDO_DEBUG_UTIL)
|
||||
@@ -650,8 +620,13 @@ store_suspend(CommandSuspend *msg, struct connection_closure *closure)
|
||||
}
|
||||
|
||||
/* Write timing data. */
|
||||
if (!iolog_write(IOFD_TIMING, tbuf, len, 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,
|
||||
iolog_fd_to_name(IOFD_TIMING), errstr);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
update_elapsed_time(msg->delay, &closure->elapsed_time);
|
||||
|
||||
@@ -661,6 +636,7 @@ store_suspend(CommandSuspend *msg, struct connection_closure *closure)
|
||||
int
|
||||
store_winsize(ChangeWindowSize *msg, struct connection_closure *closure)
|
||||
{
|
||||
const char *errstr;
|
||||
char tbuf[1024];
|
||||
int len;
|
||||
debug_decl(store_winsize, SUDO_DEBUG_UTIL)
|
||||
@@ -676,8 +652,13 @@ store_winsize(ChangeWindowSize *msg, struct connection_closure *closure)
|
||||
}
|
||||
|
||||
/* Write timing data. */
|
||||
if (!iolog_write(IOFD_TIMING, tbuf, len, 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,
|
||||
iolog_fd_to_name(IOFD_TIMING), errstr);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
update_elapsed_time(msg->delay, &closure->elapsed_time);
|
||||
|
||||
|
@@ -50,6 +50,7 @@
|
||||
#include "sudo_util.h"
|
||||
#include "sudo_rand.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "sudo_iolog.h"
|
||||
#include "pathnames.h"
|
||||
#include "logsrvd.h"
|
||||
|
||||
@@ -84,7 +85,7 @@ connection_closure_free(struct connection_closure *closure)
|
||||
|
||||
TAILQ_REMOVE(&connections, closure, entries);
|
||||
close(closure->sock);
|
||||
iolog_close(closure);
|
||||
iolog_close_all(closure);
|
||||
sudo_ev_free(closure->commit_ev);
|
||||
sudo_ev_free(closure->read_ev);
|
||||
sudo_ev_free(closure->write_ev);
|
||||
|
@@ -14,6 +14,9 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SUDO_LOGSRVD_H
|
||||
#define SUDO_LOGSRVD_H
|
||||
|
||||
#if PROTOBUF_C_VERSION_NUMBER < 1003000
|
||||
# error protobuf-c version 1.30 or higher required
|
||||
#endif
|
||||
@@ -28,18 +31,6 @@
|
||||
/* Shutdown timeout (in seconds) in case client connections time out. */
|
||||
#define SHUTDOWN_TIMEO 10
|
||||
|
||||
/*
|
||||
* Indexes into io_fds[] and iolog_names[]
|
||||
* The first five must match the IO_EVENT_ defines in iolog.h.
|
||||
*/
|
||||
#define IOFD_STDIN 0
|
||||
#define IOFD_STDOUT 1
|
||||
#define IOFD_STDERR 2
|
||||
#define IOFD_TTYIN 3
|
||||
#define IOFD_TTYOUT 4
|
||||
#define IOFD_TIMING 5
|
||||
#define IOFD_MAX 6
|
||||
|
||||
/*
|
||||
* I/O log details from the ExecMessage
|
||||
*/
|
||||
@@ -93,19 +84,19 @@ struct connection_closure {
|
||||
struct sudo_event *read_ev;
|
||||
struct sudo_event *write_ev;
|
||||
char *iolog_dir;
|
||||
struct iolog_file iolog_files[IOFD_MAX];
|
||||
int iolog_dir_fd;
|
||||
int io_fds[IOFD_MAX];
|
||||
int sock;
|
||||
enum connection_status state;
|
||||
};
|
||||
|
||||
/* iolog.c */
|
||||
/* iolog_writer.c */
|
||||
bool iolog_init(ExecMessage *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(struct connection_closure *closure);
|
||||
void iolog_close_all(struct connection_closure *closure);
|
||||
|
||||
/* logsrvd_conf.c */
|
||||
bool logsrvd_conf_iolog_compress(void);
|
||||
@@ -117,3 +108,5 @@ const char *logsrvd_conf_iolog_user(void);
|
||||
mode_t logsrvd_conf_iolog_mode(void);
|
||||
unsigned int logsrvd_conf_maxseq(void);
|
||||
void logsrvd_conf_read(const char *path);
|
||||
|
||||
#endif /* SUDO_LOGSRVD_H */
|
||||
|
@@ -39,9 +39,9 @@
|
||||
#include "sudo_debug.h"
|
||||
#include "sudo_util.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "sudo_iolog.h"
|
||||
#include "pathnames.h"
|
||||
#include "logsrvd.h"
|
||||
#include "iolog.h"
|
||||
|
||||
enum config_type {
|
||||
CONF_BOOL,
|
||||
|
@@ -54,22 +54,11 @@
|
||||
#include "sudo_util.h"
|
||||
#include "sudo_event.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "iolog_util.h"
|
||||
#include "sudo_iolog.h"
|
||||
#include "sendlog.h"
|
||||
|
||||
static gzFile io_fds[IOFD_MAX];
|
||||
|
||||
/* I/O log file names relative to the iolog dir. */
|
||||
/* XXX - duplicated with server */
|
||||
static const char *iolog_names[] = {
|
||||
"stdin", /* IOFD_STDIN */
|
||||
"stdout", /* IOFD_STDOUT */
|
||||
"stderr", /* IOFD_STDERR */
|
||||
"ttyin", /* IOFD_TTYIN */
|
||||
"ttyout", /* IOFD_TTYOUT */
|
||||
"timing", /* IOFD_TIMING */
|
||||
NULL /* IOFD_MAX */
|
||||
};
|
||||
static struct iolog_file iolog_files[IOFD_MAX];
|
||||
static char *iolog_path;
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
@@ -151,8 +140,6 @@ client_closure_free(struct client_closure *closure)
|
||||
free(closure->read_buf.data);
|
||||
free(closure->write_buf.data);
|
||||
free(closure->buf);
|
||||
// XXX - avoid use after free
|
||||
//free(closure);
|
||||
}
|
||||
|
||||
debug_return;
|
||||
@@ -165,26 +152,23 @@ client_closure_free(struct client_closure *closure)
|
||||
int
|
||||
read_timing_record(struct timing_closure *timing)
|
||||
{
|
||||
const char *errstr;
|
||||
char line[LINE_MAX];
|
||||
int errnum;
|
||||
const char *errstr;
|
||||
debug_decl(read_timing_record, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Read next record from timing file. */
|
||||
if (gzgets(io_fds[IOFD_TIMING], line, sizeof(line)) == NULL) {
|
||||
if (iolog_gets(&iolog_files[IOFD_TIMING], line, sizeof(line), &errstr) == NULL) {
|
||||
/* EOF or error reading timing file, we are done. */
|
||||
if (gzeof(io_fds[IOFD_TIMING]))
|
||||
debug_return_int(1); /* EOF */
|
||||
if ((errstr = gzerror(io_fds[IOFD_TIMING], &errnum)) == NULL)
|
||||
errstr = strerror(errno);
|
||||
sudo_warnx("error reading timing file: %s", errstr);
|
||||
if (iolog_eof(&iolog_files[IOFD_TIMING]))
|
||||
debug_return_int(1);
|
||||
sudo_warnx(U_("error reading timing file: %s"), errstr);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
/* Parse timing file record. */
|
||||
line[strcspn(line, "\n")] = '\0';
|
||||
if (!parse_timing(line, timing)) {
|
||||
sudo_warnx("invalid timing file line: %s", line);
|
||||
sudo_warnx(U_("invalid timing file line: %s"), line);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
@@ -198,11 +182,13 @@ static bool
|
||||
read_io_buf(struct client_closure *closure)
|
||||
{
|
||||
struct timing_closure *timing = &closure->timing;
|
||||
const char *errstr = NULL;
|
||||
size_t nread;
|
||||
debug_decl(read_io_buf, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (io_fds[timing->event] == NULL) {
|
||||
sudo_warnx("%s file not open", iolog_names[timing->event]);
|
||||
if (!iolog_files[timing->event].enabled) {
|
||||
errno = ENOENT;
|
||||
sudo_warn("%s/%s", iolog_path, iolog_fd_to_name(timing->event));
|
||||
debug_return_bool(false);
|
||||
}
|
||||
|
||||
@@ -219,15 +205,11 @@ read_io_buf(struct client_closure *closure)
|
||||
}
|
||||
}
|
||||
|
||||
nread = gzread(io_fds[timing->event], closure->buf, timing->u.nbytes);
|
||||
nread = iolog_read(&iolog_files[timing->event], closure->buf,
|
||||
timing->u.nbytes, &errstr);
|
||||
if (nread != timing->u.nbytes) {
|
||||
int errnum;
|
||||
const char *errstr;
|
||||
|
||||
if ((errstr = gzerror(io_fds[timing->event], &errnum)) == NULL)
|
||||
errstr = strerror(errno);
|
||||
sudo_warnx("unable to read %s file: %s", iolog_names[timing->event],
|
||||
errstr);
|
||||
sudo_warnx(U_("unable to read %s/%s: %s"), iolog_path,
|
||||
iolog_fd_to_name(timing->event), errstr);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
debug_return_bool(true);
|
||||
@@ -742,7 +724,7 @@ handle_server_hello(ServerHello *msg, struct client_closure *closure)
|
||||
|
||||
/* Sanity check ServerHello message. */
|
||||
if (msg->server_id == NULL || msg->server_id[0] == '\0') {
|
||||
sudo_warnx("invalid ServerHello");
|
||||
sudo_warnx("%s", U_("invalid ServerHello"));
|
||||
debug_return_bool(false);
|
||||
}
|
||||
|
||||
@@ -1034,23 +1016,25 @@ bad:
|
||||
* The timing file must always exist.
|
||||
*/
|
||||
bool
|
||||
iolog_open_all(const char *iolog_path)
|
||||
iolog_open_all(char *path, size_t dir_len)
|
||||
{
|
||||
char fname[PATH_MAX];
|
||||
int i, len;
|
||||
size_t file_len;
|
||||
int i;
|
||||
debug_decl(iolog_open_all, SUDO_DEBUG_UTIL)
|
||||
|
||||
for (i = 0; iolog_names[i] != NULL; i++) {
|
||||
len = snprintf(fname, sizeof(fname), "%s/%s", iolog_path,
|
||||
iolog_names[i]);
|
||||
if (len < 0 || len >= ssizeof(fname)) {
|
||||
errno = ENAMETOOLONG;
|
||||
sudo_warn("%s/%s", iolog_path, iolog_names[i]);
|
||||
for (i = 0; i < IOFD_MAX; i++) {
|
||||
path[dir_len] = '\0';
|
||||
file_len = strlen(iolog_fd_to_name(i));
|
||||
if (dir_len + 1 + file_len + 1 >= PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
sudo_warn("%s/%s", path, iolog_fd_to_name(i));
|
||||
debug_return_bool(false);
|
||||
}
|
||||
io_fds[i] = gzopen(fname, "r");
|
||||
if (io_fds[i] == NULL && i == IOFD_TIMING) {
|
||||
/* The timing file is not optional. */
|
||||
sudo_warn("unable to open %s/%s", iolog_path, iolog_names[i]);
|
||||
path[dir_len++] = '/';
|
||||
memcpy(path + dir_len, iolog_fd_to_name(i), file_len + 1);
|
||||
iolog_files[i].enabled = true;
|
||||
if (!iolog_open(&iolog_files[i], path, "r")) {
|
||||
sudo_warn(U_("unable to open %s"), path);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
}
|
||||
@@ -1104,9 +1088,9 @@ main(int argc, char *argv[])
|
||||
const char *host = "localhost";
|
||||
const char *port = DEFAULT_PORT_STR;
|
||||
struct timespec restart = { 0, 0 };
|
||||
char fname[PATH_MAX], *iolog_path;
|
||||
char pathbuf[PATH_MAX];
|
||||
const char *iolog_id = NULL;
|
||||
int ch, sock;
|
||||
int ch, len, sock;
|
||||
debug_decl_vars(main, SUDO_DEBUG_MAIN)
|
||||
|
||||
initprogname(argc > 0 ? argv[0] : "sendlog");
|
||||
@@ -1158,12 +1142,18 @@ main(int argc, char *argv[])
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* Parse I/O info log file. */
|
||||
snprintf(fname, sizeof(fname), "%s/log", iolog_path);
|
||||
if ((log_info = parse_logfile(fname)) == NULL)
|
||||
len = snprintf(pathbuf, sizeof(pathbuf), "%s/log", iolog_path);
|
||||
if (len < 0 || len >= ssizeof(pathbuf)) {
|
||||
errno = ENAMETOOLONG;
|
||||
sudo_warn("%s/log", iolog_path);
|
||||
goto bad;
|
||||
}
|
||||
len -= 4;
|
||||
if ((log_info = parse_logfile(pathbuf)) == NULL)
|
||||
goto bad;
|
||||
|
||||
/* Open the I/O log files. */
|
||||
if (!iolog_open_all(iolog_path))
|
||||
if (!iolog_open_all(pathbuf, len))
|
||||
goto bad;
|
||||
|
||||
/* Connect to server, setup events. */
|
||||
|
@@ -14,25 +14,15 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SUDO_SENDLOG_H
|
||||
#define SUDO_SENDLOG_H
|
||||
|
||||
#if PROTOBUF_C_VERSION_NUMBER < 1003000
|
||||
# error protobuf-c version 1.30 or higher required
|
||||
#endif
|
||||
|
||||
#define DEFAULT_PORT_STR "30344"
|
||||
|
||||
/*
|
||||
* Indexes into io_fds[] and iolog_names[]
|
||||
* The first five must match the IO_EVENT_ defines in iolog.h.
|
||||
* XXX - needed?
|
||||
*/
|
||||
#define IOFD_STDIN 0
|
||||
#define IOFD_STDOUT 1
|
||||
#define IOFD_STDERR 2
|
||||
#define IOFD_TTYIN 3
|
||||
#define IOFD_TTYOUT 4
|
||||
#define IOFD_TIMING 5
|
||||
#define IOFD_MAX 6
|
||||
|
||||
enum client_state {
|
||||
ERROR,
|
||||
RECV_HELLO,
|
||||
@@ -67,3 +57,5 @@ struct client_closure {
|
||||
size_t bufsize; /* XXX */
|
||||
enum client_state state;
|
||||
};
|
||||
|
||||
#endif /* SUDO_SENDLOG_H */
|
||||
|
@@ -59,12 +59,6 @@
|
||||
* caching the validate and invalidate functions are NULL.
|
||||
*/
|
||||
|
||||
#ifdef __TANDEM
|
||||
# define ROOT_UID 65535
|
||||
#else
|
||||
# define ROOT_UID 0
|
||||
#endif
|
||||
|
||||
static struct plugin_state {
|
||||
char **envp;
|
||||
char * const *settings;
|
||||
|
@@ -52,11 +52,12 @@ INSTALL_OWNER = -o $(install_uid) -g $(install_gid)
|
||||
INSTALL_BACKUP = @INSTALL_BACKUP@
|
||||
|
||||
# Libraries
|
||||
LT_LIBS = $(top_builddir)/lib/util/libsudo_util.la
|
||||
LIBS = $(LT_LIBS)
|
||||
LIBUTIL = $(top_builddir)/lib/util/libsudo_util.la
|
||||
LIBIOLOG = $(top_builddir)/lib/iolog/libsudo_iolog.la
|
||||
LIBS = $(LIBUTIL)
|
||||
NET_LIBS = @NET_LIBS@
|
||||
SUDOERS_LIBS = @SUDOERS_LIBS@ @AFS_LIBS@ @GETGROUPS_LIB@ $(LIBS) $(NET_LIBS) @ZLIB@
|
||||
REPLAY_LIBS = @REPLAY_LIBS@ @ZLIB@
|
||||
SUDOERS_LIBS = @SUDOERS_LIBS@ @AFS_LIBS@ @GETGROUPS_LIB@ $(NET_LIBS) $(LIBIOLOG)
|
||||
REPLAY_LIBS = @REPLAY_LIBS@ $(LIBIOLOG)
|
||||
VISUDO_LIBS = $(NET_LIBS)
|
||||
CVTSUDOERS_LIBS = $(NET_LIBS)
|
||||
TESTSUDOERS_LIBS = $(NET_LIBS)
|
||||
@@ -148,8 +149,8 @@ SHELL = @SHELL@
|
||||
PROGS = sudoers.la visudo sudoreplay cvtsudoers testsudoers
|
||||
|
||||
TEST_PROGS = check_addr check_base64 check_digest check_env_pattern check_fill \
|
||||
check_gentime check_hexchar check_iolog_path check_iolog_plugin \
|
||||
check_iolog_util check_wrap check_starttime @SUDOERS_TEST_PROGS@
|
||||
check_gentime check_hexchar check_iolog_plugin check_wrap \
|
||||
check_starttime @SUDOERS_TEST_PROGS@
|
||||
|
||||
AUTH_OBJS = sudo_auth.lo @AUTH_OBJS@
|
||||
|
||||
@@ -165,7 +166,7 @@ LIBPARSESUDOERS_IOBJS = $(LIBPARSESUDOERS_OBJS:.lo=.i) passwd.i
|
||||
SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo \
|
||||
env_pattern.lo file.lo find_path.lo fmtsudoers.lo gc.lo \
|
||||
goodpath.lo group_plugin.lo interfaces.lo iolog.lo \
|
||||
iolog_path.lo locale.lo logging.lo logwrap.lo \
|
||||
iolog_path_escapes.lo locale.lo logging.lo logwrap.lo \
|
||||
parse.lo policy.lo prompt.lo set_perms.lo starttime.lo \
|
||||
sudo_nss.lo sudoers.lo timestamp.lo @SUDOERS_OBJS@
|
||||
|
||||
@@ -183,7 +184,7 @@ CVTSUDOERS_OBJS = cvtsudoers.o cvtsudoers_json.o cvtsudoers_ldif.o \
|
||||
CVTSUDOERS_IOBJS = cvtsudoers.i cvtsudoers_json.i cvtsudoers_ldif.i \
|
||||
cvtsudoers_pwutil.i strlist.i
|
||||
|
||||
REPLAY_OBJS = getdate.o sudoreplay.o iolog_util.o
|
||||
REPLAY_OBJS = getdate.o sudoreplay.o
|
||||
|
||||
REPLAY_IOBJS = $(REPLAY_OBJS:.o=.i)
|
||||
|
||||
@@ -213,16 +214,9 @@ CHECK_GENTIME_OBJS = check_gentime.o gentime.lo gmtoff.lo sudoers_debug.lo
|
||||
|
||||
CHECK_HEXCHAR_OBJS = check_hexchar.o hexchar.lo sudoers_debug.lo
|
||||
|
||||
CHECK_IOLOG_PATH_OBJS = check_iolog_path.o iolog_path.lo locale.lo \
|
||||
pwutil.lo pwutil_impl.lo redblack.lo sudoers_debug.lo
|
||||
|
||||
CHECK_IOLOG_PLUGIN_OBJS = check_iolog_plugin.o iolog.lo iolog_path.lo \
|
||||
iolog_util.o locale.lo pwutil.lo \
|
||||
CHECK_IOLOG_PLUGIN_OBJS = check_iolog_plugin.o iolog.lo locale.lo pwutil.lo \
|
||||
pwutil_impl.lo redblack.lo sudoers_debug.lo
|
||||
|
||||
CHECK_IOLOG_UTIL_OBJS = check_iolog_util.o iolog_util.o locale.lo \
|
||||
sudoers_debug.lo
|
||||
|
||||
CHECK_SYMBOLS_OBJS = check_symbols.o
|
||||
|
||||
CHECK_STARTTIME_OBJS = check_starttime.o starttime.lo sudoers_debug.lo
|
||||
@@ -272,7 +266,7 @@ Makefile: $(srcdir)/Makefile.in
|
||||
libparsesudoers.la: $(LIBPARSESUDOERS_OBJS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(LIBPARSESUDOERS_OBJS) -no-install
|
||||
|
||||
sudoers.la: $(SUDOERS_OBJS) $(LT_LIBS) libparsesudoers.la @LT_LDDEP@
|
||||
sudoers.la: $(SUDOERS_OBJS) $(LIBUTIL) $(LIBIOLOG) libparsesudoers.la @LT_LDDEP@
|
||||
case "$(LT_LDFLAGS)" in \
|
||||
*-no-install*) \
|
||||
$(LIBTOOL) $(LTFLAGS) @LT_STATIC@ --mode=link $(CC) $(LDFLAGS) $(LT_LDFLAGS) -o $@ $(SUDOERS_OBJS) libparsesudoers.la $(SUDOERS_LIBS) -module;; \
|
||||
@@ -280,59 +274,53 @@ sudoers.la: $(SUDOERS_OBJS) $(LT_LIBS) libparsesudoers.la @LT_LDDEP@
|
||||
$(LIBTOOL) $(LTFLAGS) @LT_STATIC@ --mode=link $(CC) $(LDFLAGS) $(ASAN_LDFLAGS) $(SSP_LDFLAGS) $(LT_LDFLAGS) -o $@ $(SUDOERS_OBJS) libparsesudoers.la $(SUDOERS_LIBS) -module -avoid-version -rpath $(plugindir) -shrext .so;; \
|
||||
esac
|
||||
|
||||
visudo: libparsesudoers.la $(VISUDO_OBJS) $(LT_LIBS)
|
||||
visudo: libparsesudoers.la $(VISUDO_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(VISUDO_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) libparsesudoers.la $(LIBS) $(VISUDO_LIBS)
|
||||
|
||||
cvtsudoers: libparsesudoers.la $(CVTSUDOERS_OBJS) $(LT_LIBS)
|
||||
cvtsudoers: libparsesudoers.la $(CVTSUDOERS_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CVTSUDOERS_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) libparsesudoers.la $(LIBS) $(CVTSUDOERS_LIBS)
|
||||
|
||||
sudoreplay: timestr.lo $(REPLAY_OBJS) $(LT_LIBS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(REPLAY_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) timestr.lo $(LIBS) $(REPLAY_LIBS)
|
||||
sudoreplay: timestr.lo $(REPLAY_OBJS) $(LIBUTIL) $(LIBIOLOG)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(REPLAY_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) timestr.lo $(REPLAY_LIBS)
|
||||
|
||||
testsudoers: libparsesudoers.la $(TEST_OBJS) $(LT_LIBS)
|
||||
testsudoers: libparsesudoers.la $(TEST_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(TEST_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) libparsesudoers.la $(LIBS) $(TESTSUDOERS_LIBS)
|
||||
|
||||
tsdump: $(TSDUMP_OBJS) $(LT_LIBS)
|
||||
tsdump: $(TSDUMP_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(TSDUMP_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
check_addr: $(CHECK_ADDR_OBJS) $(LT_LIBS)
|
||||
check_addr: $(CHECK_ADDR_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_ADDR_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) $(NET_LIBS)
|
||||
|
||||
check_base64: $(CHECK_BASE64_OBJS) $(LT_LIBS)
|
||||
check_base64: $(CHECK_BASE64_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_BASE64_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
check_digest: $(CHECK_DIGEST_OBJS) $(LT_LIBS)
|
||||
check_digest: $(CHECK_DIGEST_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_DIGEST_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
check_env_pattern: $(CHECK_ENV_MATCH_OBJS) $(LT_LIBS)
|
||||
check_env_pattern: $(CHECK_ENV_MATCH_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_ENV_MATCH_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
check_fill: $(CHECK_FILL_OBJS) $(LT_LIBS)
|
||||
check_fill: $(CHECK_FILL_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_FILL_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
check_gentime: $(CHECK_GENTIME_OBJS) $(LT_LIBS)
|
||||
check_gentime: $(CHECK_GENTIME_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_GENTIME_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
check_hexchar: $(CHECK_HEXCHAR_OBJS) $(LT_LIBS)
|
||||
check_hexchar: $(CHECK_HEXCHAR_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_HEXCHAR_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
check_iolog_path: $(CHECK_IOLOG_PATH_OBJS) $(LT_LIBS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_PATH_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
check_iolog_plugin: $(CHECK_IOLOG_PLUGIN_OBJS) $(LIBUTIL) $(LIBIOLOG)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_PLUGIN_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBIOLOG)
|
||||
|
||||
check_iolog_plugin: $(CHECK_IOLOG_PLUGIN_OBJS) $(LT_LIBS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_PLUGIN_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) @ZLIB@
|
||||
|
||||
check_iolog_util: $(CHECK_IOLOG_UTIL_OBJS) $(LT_LIBS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_UTIL_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) @ZLIB@
|
||||
|
||||
check_starttime: $(CHECK_STARTTIME_OBJS) $(LT_LIBS)
|
||||
check_starttime: $(CHECK_STARTTIME_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_STARTTIME_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
# We need to link check_symbols with -lpthread on HP-UX since LDAP uses threads
|
||||
check_symbols: $(CHECK_SYMBOLS_OBJS) $(LT_LIBS)
|
||||
check_symbols: $(CHECK_SYMBOLS_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_SYMBOLS_OBJS) $(CHECK_SYMBOLS_LDFLAGS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) @SUDO_LIBS@
|
||||
|
||||
check_wrap: $(CHECK_WRAP_OBJS) $(LT_LIBS)
|
||||
check_wrap: $(CHECK_WRAP_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_WRAP_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
|
||||
GENERATED = gram.h gram.c toke.c def_data.c def_data.h getdate.c
|
||||
@@ -472,9 +460,7 @@ check: $(TEST_PROGS) visudo testsudoers cvtsudoers
|
||||
./check_fill || rval=`expr $$rval + $$?`; \
|
||||
./check_gentime || rval=`expr $$rval + $$?`; \
|
||||
./check_hexchar || rval=`expr $$rval + $$?`; \
|
||||
./check_iolog_path $(srcdir)/regress/iolog_path/data || rval=`expr $$rval + $$?`; \
|
||||
./check_iolog_plugin $(srcdir)/regress/iolog_plugin/iolog || rval=`expr $$rval + $$?`; \
|
||||
./check_iolog_util || rval=`expr $$rval + $$?`; \
|
||||
./check_starttime || rval=`expr $$rval + $$?`; \
|
||||
if test -f check_symbols; then \
|
||||
./check_symbols .libs/sudoers.so $(shlib_exp) || rval=`expr $$rval + $$?`; \
|
||||
@@ -933,72 +919,32 @@ check_hexchar.i: $(srcdir)/regress/parser/check_hexchar.c \
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
check_hexchar.plog: check_hexchar.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/parser/check_hexchar.c --i-file $< --output-file $@
|
||||
check_iolog_path.o: $(srcdir)/regress/iolog_path/check_iolog_path.c \
|
||||
$(devdir)/def_data.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/defaults.h \
|
||||
$(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/sudo_nss.h \
|
||||
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/iolog_path/check_iolog_path.c
|
||||
check_iolog_path.i: $(srcdir)/regress/iolog_path/check_iolog_path.c \
|
||||
$(devdir)/def_data.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/defaults.h \
|
||||
$(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/sudo_nss.h \
|
||||
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
check_iolog_path.plog: check_iolog_path.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/iolog_path/check_iolog_path.c --i-file $< --output-file $@
|
||||
check_iolog_plugin.o: $(srcdir)/regress/iolog_plugin/check_iolog_plugin.c \
|
||||
$(devdir)/def_data.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/defaults.h \
|
||||
$(srcdir)/iolog.h $(srcdir)/iolog_util.h \
|
||||
$(srcdir)/logging.h $(srcdir)/parse.h \
|
||||
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
|
||||
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/defaults.h $(srcdir)/logging.h \
|
||||
$(srcdir)/parse.h $(srcdir)/sudo_nss.h \
|
||||
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/iolog_plugin/check_iolog_plugin.c
|
||||
check_iolog_plugin.i: $(srcdir)/regress/iolog_plugin/check_iolog_plugin.c \
|
||||
$(devdir)/def_data.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/defaults.h \
|
||||
$(srcdir)/iolog.h $(srcdir)/iolog_util.h \
|
||||
$(srcdir)/logging.h $(srcdir)/parse.h \
|
||||
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
|
||||
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/defaults.h $(srcdir)/logging.h \
|
||||
$(srcdir)/parse.h $(srcdir)/sudo_nss.h \
|
||||
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
check_iolog_plugin.plog: check_iolog_plugin.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/iolog_plugin/check_iolog_plugin.c --i-file $< --output-file $@
|
||||
check_iolog_util.o: $(srcdir)/regress/iolog_util/check_iolog_util.c \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/iolog.h $(srcdir)/iolog_util.h \
|
||||
$(top_builddir)/config.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/iolog_util/check_iolog_util.c
|
||||
check_iolog_util.i: $(srcdir)/regress/iolog_util/check_iolog_util.c \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/iolog.h $(srcdir)/iolog_util.h \
|
||||
$(top_builddir)/config.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
check_iolog_util.plog: check_iolog_util.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/iolog_util/check_iolog_util.c --i-file $< --output-file $@
|
||||
check_starttime.o: $(srcdir)/regress/starttime/check_starttime.c \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_util.h \
|
||||
@@ -1550,8 +1496,8 @@ interfaces.plog: interfaces.i
|
||||
iolog.lo: $(srcdir)/iolog.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/defaults.h $(srcdir)/iolog.h $(srcdir)/iolog_files.h \
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/defaults.h \
|
||||
$(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/sudo_nss.h \
|
||||
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
@@ -1559,50 +1505,38 @@ iolog.lo: $(srcdir)/iolog.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
||||
iolog.i: $(srcdir)/iolog.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/defaults.h $(srcdir)/iolog.h $(srcdir)/iolog_files.h \
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/defaults.h \
|
||||
$(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/sudo_nss.h \
|
||||
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
iolog.plog: iolog.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog.c --i-file $< --output-file $@
|
||||
iolog_path.lo: $(srcdir)/iolog_path.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/defaults.h $(srcdir)/logging.h \
|
||||
$(srcdir)/parse.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
|
||||
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/iolog_path.c
|
||||
iolog_path.i: $(srcdir)/iolog_path.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/defaults.h $(srcdir)/logging.h \
|
||||
$(srcdir)/parse.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
|
||||
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
iolog_path_escapes.lo: $(srcdir)/iolog_path_escapes.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/defaults.h $(srcdir)/logging.h \
|
||||
$(srcdir)/parse.h $(srcdir)/sudo_nss.h \
|
||||
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/iolog_path_escapes.c
|
||||
iolog_path_escapes.i: $(srcdir)/iolog_path_escapes.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/defaults.h $(srcdir)/logging.h \
|
||||
$(srcdir)/parse.h $(srcdir)/sudo_nss.h \
|
||||
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
iolog_path.plog: iolog_path.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog_path.c --i-file $< --output-file $@
|
||||
iolog_util.o: $(srcdir)/iolog_util.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/iolog.h \
|
||||
$(srcdir)/iolog_util.h $(top_builddir)/config.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/iolog_util.c
|
||||
iolog_util.i: $(srcdir)/iolog_util.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/iolog.h \
|
||||
$(srcdir)/iolog_util.h $(top_builddir)/config.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
iolog_util.plog: iolog_util.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog_util.c --i-file $< --output-file $@
|
||||
iolog_path_escapes.plog: iolog_path_escapes.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog_path_escapes.c --i-file $< --output-file $@
|
||||
kerb5.lo: $(authdir)/kerb5.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
@@ -2365,22 +2299,22 @@ sudoers.lo: $(srcdir)/sudoers.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/getaddrinfo.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||
$(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \
|
||||
$(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/auth/sudo_auth.h $(srcdir)/defaults.h \
|
||||
$(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/sudo_nss.h \
|
||||
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/auth/sudo_auth.h \
|
||||
$(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
|
||||
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/sudoers.c
|
||||
sudoers.i: $(srcdir)/sudoers.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/getaddrinfo.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
|
||||
$(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \
|
||||
$(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/auth/sudo_auth.h $(srcdir)/defaults.h \
|
||||
$(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/sudo_nss.h \
|
||||
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/auth/sudo_auth.h \
|
||||
$(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
|
||||
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
sudoers.plog: sudoers.i
|
||||
@@ -2411,21 +2345,19 @@ sudoreplay.o: $(srcdir)/sudoreplay.c $(incdir)/compat/getopt.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_event.h $(incdir)/sudo_fatal.h \
|
||||
$(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/iolog.h \
|
||||
$(srcdir)/iolog_files.h $(srcdir)/iolog_util.h \
|
||||
$(srcdir)/logging.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/logging.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/sudoreplay.c
|
||||
sudoreplay.i: $(srcdir)/sudoreplay.c $(incdir)/compat/getopt.h \
|
||||
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
|
||||
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_event.h $(incdir)/sudo_fatal.h \
|
||||
$(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/iolog.h \
|
||||
$(srcdir)/iolog_files.h $(srcdir)/iolog_util.h \
|
||||
$(srcdir)/logging.h $(top_builddir)/config.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \
|
||||
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/logging.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
sudoreplay.plog: sudoreplay.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/sudoreplay.c --i-file $< --output-file $@
|
||||
|
@@ -402,8 +402,8 @@ struct sudo_defs_types sudo_defs_table[] = {
|
||||
N_("Perform PAM account validation management"),
|
||||
NULL,
|
||||
}, {
|
||||
"maxseq", T_UINT,
|
||||
N_("Maximum I/O log sequence number: %u"),
|
||||
"maxseq", T_STR,
|
||||
N_("Maximum I/O log sequence number: %s"),
|
||||
NULL,
|
||||
}, {
|
||||
"use_netgroups", T_FLAG,
|
||||
|
@@ -181,7 +181,7 @@
|
||||
#define I_PAM_ACCT_MGMT 90
|
||||
#define def_pam_acct_mgmt (sudo_defs_table[I_PAM_ACCT_MGMT].sd_un.flag)
|
||||
#define I_MAXSEQ 91
|
||||
#define def_maxseq (sudo_defs_table[I_MAXSEQ].sd_un.uival)
|
||||
#define def_maxseq (sudo_defs_table[I_MAXSEQ].sd_un.str)
|
||||
#define I_USE_NETGROUPS 92
|
||||
#define def_use_netgroups (sudo_defs_table[I_USE_NETGROUPS].sd_un.flag)
|
||||
#define I_SUDOEDIT_CHECKDIR 93
|
||||
|
@@ -287,8 +287,8 @@ pam_acct_mgmt
|
||||
T_FLAG
|
||||
"Perform PAM account validation management"
|
||||
maxseq
|
||||
T_UINT
|
||||
"Maximum I/O log sequence number: %u"
|
||||
T_STR
|
||||
"Maximum I/O log sequence number: %s"
|
||||
use_netgroups
|
||||
T_FLAG
|
||||
"Enable sudoers netgroup support"
|
||||
|
@@ -42,8 +42,7 @@
|
||||
#include <grp.h>
|
||||
|
||||
#include "sudoers.h"
|
||||
#include "iolog.h"
|
||||
#include "iolog_files.h"
|
||||
#include "sudo_iolog.h"
|
||||
|
||||
/* XXX - separate sudoers.h and iolog.h? */
|
||||
#undef runas_pw
|
||||
@@ -62,206 +61,29 @@ struct iolog_details {
|
||||
bool ignore_iolog_errors;
|
||||
};
|
||||
|
||||
static struct iolog_file iolog_files[] = {
|
||||
{ false }, /* IOFD_STDIN */
|
||||
{ false }, /* IOFD_STDOUT */
|
||||
{ false }, /* IOFD_STDERR */
|
||||
{ false }, /* IOFD_TTYIN */
|
||||
{ false }, /* IOFD_TTYOUT */
|
||||
{ true, }, /* IOFD_TIMING */
|
||||
};
|
||||
|
||||
static struct iolog_details iolog_details;
|
||||
static bool iolog_compress = false;
|
||||
static bool warned = false;
|
||||
static struct timespec last_time;
|
||||
static unsigned int sessid_max = SESSID_MAX;
|
||||
static mode_t iolog_filemode = S_IRUSR|S_IWUSR;
|
||||
static mode_t iolog_dirmode = S_IRWXU;
|
||||
static bool iolog_gid_set;
|
||||
|
||||
/* shared with set_perms.c */
|
||||
uid_t iolog_uid = ROOT_UID;
|
||||
gid_t iolog_gid = ROOT_GID;
|
||||
|
||||
/* sudoers_io is declared at the end of this file. */
|
||||
extern __dso_public struct io_plugin sudoers_io;
|
||||
|
||||
/*
|
||||
* Create directory and any parent directories as needed.
|
||||
*/
|
||||
static bool
|
||||
io_mkdirs(char *path)
|
||||
{
|
||||
struct stat sb;
|
||||
bool ok, uid_changed = false;
|
||||
debug_decl(io_mkdirs, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
ok = stat(path, &sb) == 0;
|
||||
if (!ok && errno == EACCES) {
|
||||
/* Try again as the I/O log owner (for NFS). */
|
||||
if (set_perms(PERM_IOLOG)) {
|
||||
ok = stat(path, &sb) == 0;
|
||||
if (!restore_perms())
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
if (sb.st_uid != iolog_uid || sb.st_gid != iolog_gid) {
|
||||
if (chown(path, iolog_uid, iolog_gid) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to chown %d:%d %s", __func__,
|
||||
(int)iolog_uid, (int)iolog_gid, path);
|
||||
}
|
||||
}
|
||||
if ((sb.st_mode & ALLPERMS) != iolog_dirmode) {
|
||||
if (chmod(path, iolog_dirmode) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to chmod 0%o %s", __func__,
|
||||
(int)iolog_dirmode, path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sudo_warnx(U_("%s exists but is not a directory (0%o)"),
|
||||
path, (unsigned int) sb.st_mode);
|
||||
ok = false;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
ok = sudo_mkdir_parents(path, iolog_uid, iolog_gid, iolog_dirmode, true);
|
||||
if (!ok && errno == EACCES) {
|
||||
/* Try again as the I/O log owner (for NFS). */
|
||||
uid_changed = set_perms(PERM_IOLOG);
|
||||
ok = sudo_mkdir_parents(path, -1, -1, iolog_dirmode, false);
|
||||
}
|
||||
if (ok) {
|
||||
/* Create final path component. */
|
||||
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
|
||||
"mkdir %s, mode 0%o", path, (unsigned int) iolog_dirmode);
|
||||
ok = mkdir(path, iolog_dirmode) == 0 || errno == EEXIST;
|
||||
if (!ok) {
|
||||
if (errno == EACCES && !uid_changed) {
|
||||
/* Try again as the I/O log owner (for NFS). */
|
||||
uid_changed = set_perms(PERM_IOLOG);
|
||||
ok = mkdir(path, iolog_dirmode) == 0 || errno == EEXIST;
|
||||
}
|
||||
if (!ok)
|
||||
sudo_warn(U_("unable to mkdir %s"), path);
|
||||
} else {
|
||||
if (chown(path, iolog_uid, iolog_gid) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to chown %d:%d %s", __func__,
|
||||
(int)iolog_uid, (int)iolog_gid, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uid_changed) {
|
||||
if (!restore_perms())
|
||||
ok = false;
|
||||
}
|
||||
done:
|
||||
debug_return_bool(ok);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create temporary directory and any parent directories as needed.
|
||||
*/
|
||||
static bool
|
||||
io_mkdtemp(char *path)
|
||||
{
|
||||
bool ok, uid_changed = false;
|
||||
debug_decl(io_mkdtemp, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
ok = sudo_mkdir_parents(path, iolog_uid, iolog_gid, iolog_dirmode, true);
|
||||
if (!ok && errno == EACCES) {
|
||||
/* Try again as the I/O log owner (for NFS). */
|
||||
uid_changed = set_perms(PERM_IOLOG);
|
||||
ok = sudo_mkdir_parents(path, -1, -1, iolog_dirmode, false);
|
||||
}
|
||||
if (ok) {
|
||||
/* Create final path component. */
|
||||
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
|
||||
"mkdtemp %s", path);
|
||||
/* We cannot retry mkdtemp() so always use PERM_IOLOG */
|
||||
if (!uid_changed)
|
||||
uid_changed = set_perms(PERM_IOLOG);
|
||||
if (mkdtemp(path) == NULL) {
|
||||
sudo_warn(U_("unable to mkdir %s"), path);
|
||||
ok = false;
|
||||
} else {
|
||||
if (chmod(path, iolog_dirmode) != 0) {
|
||||
sudo_warn(U_("unable to change mode of %s to 0%o"),
|
||||
path, (unsigned int)iolog_dirmode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uid_changed) {
|
||||
if (!restore_perms())
|
||||
ok = false;
|
||||
}
|
||||
debug_return_bool(ok);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set max session ID (aka sequence number)
|
||||
*/
|
||||
static bool
|
||||
io_set_max_sessid(const char *maxval)
|
||||
{
|
||||
const char *errstr;
|
||||
unsigned int value;
|
||||
debug_decl(io_set_max_sessid, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
value = sudo_strtonum(maxval, 0, SESSID_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
if (errno != ERANGE) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"bad maxseq: %s: %s", maxval, errstr);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
/* Out of range, clamp to SESSID_MAX as documented. */
|
||||
value = SESSID_MAX;
|
||||
}
|
||||
sessid_max = value;
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sudoers callback for maxseq Defaults setting.
|
||||
*/
|
||||
bool
|
||||
cb_maxseq(const union sudo_defs_val *sd_un)
|
||||
{
|
||||
debug_decl(cb_maxseq, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
/* Clamp value to SESSID_MAX as documented. */
|
||||
sessid_max = sd_un->uival < SESSID_MAX ? sd_un->uival : SESSID_MAX;
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up I/O log user-ID from user name. Sets iolog_uid.
|
||||
* Also sets iolog_gid if iolog_group not specified.
|
||||
*/
|
||||
static bool
|
||||
iolog_set_user(const char *name)
|
||||
{
|
||||
struct passwd *pw;
|
||||
debug_decl(iolog_set_user, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
if (name != NULL) {
|
||||
pw = sudo_getpwnam(name);
|
||||
if (pw != NULL) {
|
||||
iolog_uid = pw->pw_uid;
|
||||
if (!iolog_gid_set)
|
||||
iolog_gid = pw->pw_gid;
|
||||
sudo_pw_delref(pw);
|
||||
} else {
|
||||
log_warningx(SLOG_SEND_MAIL,
|
||||
N_("unknown user: %s"), name);
|
||||
}
|
||||
} else {
|
||||
/* Reset to default. */
|
||||
iolog_uid = ROOT_UID;
|
||||
if (!iolog_gid_set)
|
||||
iolog_gid = ROOT_GID;
|
||||
}
|
||||
|
||||
debug_return_bool(true);
|
||||
return iolog_set_maxseq(sd_un->str);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -270,36 +92,23 @@ iolog_set_user(const char *name)
|
||||
bool
|
||||
cb_iolog_user(const union sudo_defs_val *sd_un)
|
||||
{
|
||||
return iolog_set_user(sd_un->str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up I/O log group-ID from group name.
|
||||
* Sets iolog_gid.
|
||||
*/
|
||||
static bool
|
||||
iolog_set_group(const char *name)
|
||||
{
|
||||
struct group *gr;
|
||||
debug_decl(iolog_set_group, SUDOERS_DEBUG_UTIL)
|
||||
const char *name = sd_un->str;
|
||||
struct passwd *pw = NULL;
|
||||
bool ret;
|
||||
debug_decl(cb_iolog_user, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
/* NULL name means reset to default. */
|
||||
if (name != NULL) {
|
||||
gr = sudo_getgrnam(name);
|
||||
if (gr != NULL) {
|
||||
iolog_gid = gr->gr_gid;
|
||||
iolog_gid_set = true;
|
||||
sudo_gr_delref(gr);
|
||||
} else {
|
||||
log_warningx(SLOG_SEND_MAIL,
|
||||
N_("unknown group: %s"), name);
|
||||
if ((pw = sudo_getpwnam(name)) == NULL) {
|
||||
log_warningx(SLOG_SEND_MAIL, N_("unknown user: %s"), name);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
} else {
|
||||
/* Reset to default. */
|
||||
iolog_gid = ROOT_GID;
|
||||
iolog_gid_set = false;
|
||||
}
|
||||
ret = iolog_set_user(pw);
|
||||
if (pw != NULL)
|
||||
sudo_pw_delref(pw);
|
||||
|
||||
debug_return_bool(true);
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -308,31 +117,23 @@ iolog_set_group(const char *name)
|
||||
bool
|
||||
cb_iolog_group(const union sudo_defs_val *sd_un)
|
||||
{
|
||||
return iolog_set_group(sd_un->str);
|
||||
}
|
||||
const char *name = sd_un->str;
|
||||
struct group *gr = NULL;
|
||||
bool ret;
|
||||
debug_decl(cb_iolog_group, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
/*
|
||||
* Set iolog_filemode and iolog_dirmode.
|
||||
*/
|
||||
static bool
|
||||
iolog_set_mode(mode_t mode)
|
||||
{
|
||||
debug_decl(iolog_set_mode, SUDOERS_DEBUG_UTIL)
|
||||
/* NULL name means reset to default. */
|
||||
if (name != NULL) {
|
||||
if ((gr = sudo_getgrnam(name)) == NULL) {
|
||||
log_warningx(SLOG_SEND_MAIL, N_("unknown group: %s"), name);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
}
|
||||
ret = iolog_set_group(gr);
|
||||
if (gr != NULL)
|
||||
sudo_gr_delref(gr);
|
||||
|
||||
/* I/O log files must be readable and writable by owner. */
|
||||
iolog_filemode = S_IRUSR|S_IWUSR;
|
||||
|
||||
/* Add in group and other read/write if specified. */
|
||||
iolog_filemode |= mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
||||
|
||||
/* For directory mode, add execute bits as needed. */
|
||||
iolog_dirmode = iolog_filemode | S_IXUSR;
|
||||
if (iolog_dirmode & (S_IRGRP|S_IWGRP))
|
||||
iolog_dirmode |= S_IXGRP;
|
||||
if (iolog_dirmode & (S_IROTH|S_IWOTH))
|
||||
iolog_dirmode |= S_IXOTH;
|
||||
|
||||
debug_return_bool(true);
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -344,248 +145,6 @@ cb_iolog_mode(const union sudo_defs_val *sd_un)
|
||||
return iolog_set_mode(sd_un->mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for open(2) that retries with PERM_IOLOG if open(2)
|
||||
* returns EACCES.
|
||||
*/
|
||||
static int
|
||||
io_open(const char *path, int flags, mode_t perm)
|
||||
{
|
||||
int fd;
|
||||
debug_decl(io_open, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
fd = open(path, flags, perm);
|
||||
if (fd == -1 && errno == EACCES) {
|
||||
/* Try again as the I/O log owner (for NFS). */
|
||||
if (set_perms(PERM_IOLOG)) {
|
||||
fd = open(path, flags, perm);
|
||||
if (!restore_perms()) {
|
||||
/* restore_perms() warns on error. */
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
debug_return_int(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the on-disk sequence number, set sessid to the next
|
||||
* number, and update the on-disk copy.
|
||||
* Uses file locking to avoid sequence number collisions.
|
||||
*/
|
||||
bool
|
||||
io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7])
|
||||
{
|
||||
struct stat sb;
|
||||
char buf[32], *ep;
|
||||
int i, len, fd = -1;
|
||||
unsigned long id = 0;
|
||||
mode_t omask;
|
||||
ssize_t nread;
|
||||
bool ret = false;
|
||||
char pathbuf[PATH_MAX];
|
||||
static const char b36char[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
debug_decl(io_nextid, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
/* umask must not be more restrictive than the file modes. */
|
||||
omask = umask(ACCESSPERMS & ~(iolog_filemode|iolog_dirmode));
|
||||
|
||||
/*
|
||||
* Create I/O log directory if it doesn't already exist.
|
||||
*/
|
||||
if (!io_mkdirs(iolog_dir))
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Open sequence file
|
||||
*/
|
||||
len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir);
|
||||
if (len < 0 || len >= ssizeof(pathbuf)) {
|
||||
errno = ENAMETOOLONG;
|
||||
log_warning(SLOG_SEND_MAIL, "%s/seq", pathbuf);
|
||||
goto done;
|
||||
}
|
||||
fd = io_open(pathbuf, O_RDWR|O_CREAT, iolog_filemode);
|
||||
if (fd == -1) {
|
||||
log_warning(SLOG_SEND_MAIL, N_("unable to open %s"), pathbuf);
|
||||
goto done;
|
||||
}
|
||||
sudo_lock_file(fd, SUDO_LOCK);
|
||||
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to fchown %d:%d %s", __func__,
|
||||
(int)iolog_uid, (int)iolog_gid, pathbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no seq file in iolog_dir and a fallback dir was
|
||||
* specified, look for seq in the fallback dir. This is to work
|
||||
* around a bug in sudo 1.8.5 and older where iolog_dir was not
|
||||
* expanded before the sequence number was updated.
|
||||
*/
|
||||
if (iolog_dir_fallback != NULL && fstat(fd, &sb) == 0 && sb.st_size == 0) {
|
||||
char fallback[PATH_MAX];
|
||||
|
||||
len = snprintf(fallback, sizeof(fallback), "%s/seq",
|
||||
iolog_dir_fallback);
|
||||
if (len > 0 && len < ssizeof(fallback)) {
|
||||
int fd2 = io_open(fallback, O_RDWR|O_CREAT, iolog_filemode);
|
||||
if (fd2 != -1) {
|
||||
if (fchown(fd2, iolog_uid, iolog_gid) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to fchown %d:%d %s", __func__,
|
||||
(int)iolog_uid, (int)iolog_gid, fallback);
|
||||
}
|
||||
nread = read(fd2, buf, sizeof(buf) - 1);
|
||||
if (nread > 0) {
|
||||
if (buf[nread - 1] == '\n')
|
||||
nread--;
|
||||
buf[nread] = '\0';
|
||||
id = strtoul(buf, &ep, 36);
|
||||
if (ep == buf || *ep != '\0' || id >= sessid_max) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"%s: bad sequence number: %s", fallback, buf);
|
||||
id = 0;
|
||||
}
|
||||
}
|
||||
close(fd2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Read current seq number (base 36). */
|
||||
if (id == 0) {
|
||||
nread = read(fd, buf, sizeof(buf) - 1);
|
||||
if (nread != 0) {
|
||||
if (nread == -1) {
|
||||
log_warning(SLOG_SEND_MAIL, N_("unable to read %s"), pathbuf);
|
||||
goto done;
|
||||
}
|
||||
if (buf[nread - 1] == '\n')
|
||||
nread--;
|
||||
buf[nread] = '\0';
|
||||
id = strtoul(buf, &ep, 36);
|
||||
if (ep == buf || *ep != '\0' || id >= sessid_max) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"%s: bad sequence number: %s", pathbuf, buf);
|
||||
id = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
id++;
|
||||
|
||||
/*
|
||||
* Convert id to a string and stash in sessid.
|
||||
* Note that that least significant digits go at the end of the string.
|
||||
*/
|
||||
for (i = 5; i >= 0; i--) {
|
||||
buf[i] = b36char[id % 36];
|
||||
id /= 36;
|
||||
}
|
||||
buf[6] = '\n';
|
||||
|
||||
/* Stash id for logging purposes. */
|
||||
memcpy(sessid, buf, 6);
|
||||
sessid[6] = '\0';
|
||||
|
||||
/* Rewind and overwrite old seq file, including the NUL byte. */
|
||||
#ifdef HAVE_PWRITE
|
||||
if (pwrite(fd, buf, 7, 0) != 7) {
|
||||
#else
|
||||
if (lseek(fd, 0, SEEK_SET) == -1 || write(fd, buf, 7) != 7) {
|
||||
#endif
|
||||
log_warning(SLOG_SEND_MAIL, N_("unable to write to %s"), pathbuf);
|
||||
warned = true;
|
||||
goto done;
|
||||
}
|
||||
ret = true;
|
||||
|
||||
done:
|
||||
umask(omask);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy iolog_path to pathbuf and create the directory and any intermediate
|
||||
* directories. If iolog_path ends in 'XXXXXX', use mkdtemp().
|
||||
* Returns SIZE_MAX on error.
|
||||
*/
|
||||
static size_t
|
||||
mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize)
|
||||
{
|
||||
size_t len;
|
||||
bool ok;
|
||||
debug_decl(mkdir_iopath, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
len = strlcpy(pathbuf, iolog_path, pathsize);
|
||||
if (len >= pathsize) {
|
||||
errno = ENAMETOOLONG;
|
||||
log_warning(SLOG_SEND_MAIL, "%s", iolog_path);
|
||||
debug_return_size_t((size_t)-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create path and intermediate subdirs as needed.
|
||||
* If path ends in at least 6 Xs (ala POSIX mktemp), use mkdtemp().
|
||||
* Sets iolog_gid (if it is not already set) as a side effect.
|
||||
*/
|
||||
if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0)
|
||||
ok = io_mkdtemp(pathbuf);
|
||||
else
|
||||
ok = io_mkdirs(pathbuf);
|
||||
|
||||
debug_return_size_t(ok ? len : (size_t)-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append suffix to pathbuf after len chars and open the resulting file.
|
||||
* Note that the size of pathbuf is assumed to be PATH_MAX.
|
||||
* Uses zlib if docompress is true.
|
||||
* Stores the open file handle which has the close-on-exec flag set.
|
||||
*/
|
||||
static bool
|
||||
open_io_fd(char *pathbuf, size_t len, struct io_log_file *iol, bool docompress)
|
||||
{
|
||||
debug_decl(open_io_fd, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
pathbuf[len] = '\0';
|
||||
strlcat(pathbuf, iol->suffix, PATH_MAX);
|
||||
if (iol->enabled) {
|
||||
int fd = io_open(pathbuf, O_CREAT|O_TRUNC|O_WRONLY, iolog_filemode);
|
||||
if (fd != -1) {
|
||||
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to fchown %d:%d %s", __func__,
|
||||
(int)iolog_uid, (int)iolog_gid, pathbuf);
|
||||
}
|
||||
(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (docompress)
|
||||
iol->fd.g = gzdopen(fd, "w");
|
||||
else
|
||||
#endif
|
||||
iol->fd.f = fdopen(fd, "w");
|
||||
if (iol->fd.v == NULL) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
if (fd == -1) {
|
||||
log_warning(SLOG_SEND_MAIL, N_("unable to create %s"), pathbuf);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
} else {
|
||||
/* Remove old log file if we recycled sequence numbers. */
|
||||
unlink(pathbuf);
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pull out I/O log related data from user_info and command_info arrays.
|
||||
* Returns true if I/O logging is enabled, else false.
|
||||
@@ -666,52 +225,81 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
|
||||
}
|
||||
if (strncmp(*cur, "iolog_stdin=", sizeof("iolog_stdin=") - 1) == 0) {
|
||||
if (sudo_strtobool(*cur + sizeof("iolog_stdin=") - 1) == true)
|
||||
io_log_files[IOFD_STDIN].enabled = true;
|
||||
iolog_files[IOFD_STDIN].enabled = true;
|
||||
continue;
|
||||
}
|
||||
if (strncmp(*cur, "iolog_stdout=", sizeof("iolog_stdout=") - 1) == 0) {
|
||||
if (sudo_strtobool(*cur + sizeof("iolog_stdout=") - 1) == true)
|
||||
io_log_files[IOFD_STDOUT].enabled = true;
|
||||
iolog_files[IOFD_STDOUT].enabled = true;
|
||||
continue;
|
||||
}
|
||||
if (strncmp(*cur, "iolog_stderr=", sizeof("iolog_stderr=") - 1) == 0) {
|
||||
if (sudo_strtobool(*cur + sizeof("iolog_stderr=") - 1) == true)
|
||||
io_log_files[IOFD_STDERR].enabled = true;
|
||||
iolog_files[IOFD_STDERR].enabled = true;
|
||||
continue;
|
||||
}
|
||||
if (strncmp(*cur, "iolog_ttyin=", sizeof("iolog_ttyin=") - 1) == 0) {
|
||||
if (sudo_strtobool(*cur + sizeof("iolog_ttyin=") - 1) == true)
|
||||
io_log_files[IOFD_TTYIN].enabled = true;
|
||||
iolog_files[IOFD_TTYIN].enabled = true;
|
||||
continue;
|
||||
}
|
||||
if (strncmp(*cur, "iolog_ttyout=", sizeof("iolog_ttyout=") - 1) == 0) {
|
||||
if (sudo_strtobool(*cur + sizeof("iolog_ttyout=") - 1) == true)
|
||||
io_log_files[IOFD_TTYOUT].enabled = true;
|
||||
iolog_files[IOFD_TTYOUT].enabled = true;
|
||||
continue;
|
||||
}
|
||||
if (strncmp(*cur, "iolog_compress=", sizeof("iolog_compress=") - 1) == 0) {
|
||||
if (sudo_strtobool(*cur + sizeof("iolog_compress=") - 1) == true)
|
||||
iolog_compress = true; /* must be global */
|
||||
if (!iolog_set_compress(*cur + sizeof("iolog_compress=") - 1)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_WARN,
|
||||
"%s: unable to parse %s", __func__, *cur);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strncmp(*cur, "iolog_flush=", sizeof("iolog_flush=") - 1) == 0) {
|
||||
if (!iolog_set_flush(*cur + sizeof("iolog_flush=") - 1)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_WARN,
|
||||
"%s: unable to parse %s", __func__, *cur);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strncmp(*cur, "iolog_mode=", sizeof("iolog_mode=") - 1) == 0) {
|
||||
mode_t mode = sudo_strtomode(*cur + sizeof("iolog_mode=") - 1, &errstr);
|
||||
if (errstr == NULL)
|
||||
if (errstr == NULL) {
|
||||
iolog_set_mode(mode);
|
||||
} else {
|
||||
sudo_debug_printf(SUDO_DEBUG_WARN,
|
||||
"%s: unable to parse %s", __func__, *cur);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strncmp(*cur, "iolog_group=", sizeof("iolog_group=") - 1) == 0) {
|
||||
iolog_set_group(*cur + sizeof("iolog_group=") - 1);
|
||||
struct group *gr =
|
||||
sudo_getgrnam(*cur + sizeof("iolog_group=") - 1);
|
||||
if (gr == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_WARN, "%s: unknown group %s",
|
||||
__func__, *cur + sizeof("iolog_group=") - 1);
|
||||
} else {
|
||||
iolog_set_group(gr);
|
||||
sudo_gr_delref(gr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strncmp(*cur, "iolog_user=", sizeof("iolog_user=") - 1) == 0) {
|
||||
iolog_set_user(*cur + sizeof("iolog_user=") - 1);
|
||||
struct passwd *pw =
|
||||
sudo_getpwnam(*cur + sizeof("iolog_user=") - 1);
|
||||
if (pw == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_WARN, "%s: unknown user %s",
|
||||
__func__, *cur + sizeof("iolog_user=") - 1);
|
||||
} else {
|
||||
iolog_set_user(pw);
|
||||
sudo_pw_delref(pw);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
if (strncmp(*cur, "maxseq=", sizeof("maxseq=") - 1) == 0) {
|
||||
io_set_max_sessid(*cur + sizeof("maxseq=") - 1);
|
||||
iolog_set_maxseq(*cur + sizeof("maxseq=") - 1);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -774,9 +362,9 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
|
||||
}
|
||||
}
|
||||
debug_return_bool(
|
||||
io_log_files[IOFD_STDIN].enabled || io_log_files[IOFD_STDOUT].enabled ||
|
||||
io_log_files[IOFD_STDERR].enabled || io_log_files[IOFD_TTYIN].enabled ||
|
||||
io_log_files[IOFD_TTYOUT].enabled);
|
||||
iolog_files[IOFD_STDIN].enabled || iolog_files[IOFD_STDOUT].enabled ||
|
||||
iolog_files[IOFD_STDERR].enabled || iolog_files[IOFD_TTYIN].enabled ||
|
||||
iolog_files[IOFD_TTYOUT].enabled);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -787,97 +375,28 @@ static bool
|
||||
write_info_log(char *pathbuf, size_t len, struct iolog_details *details,
|
||||
char * const argv[])
|
||||
{
|
||||
time_t now;
|
||||
char * const *av;
|
||||
FILE *fp;
|
||||
int fd;
|
||||
bool ret = true;
|
||||
struct iolog_info iolog_info;
|
||||
debug_decl(write_info_log, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
/* XXX - just use iolog_info in the first place? */
|
||||
time(&iolog_info.tstamp);
|
||||
iolog_info.user = (char *)details->user;
|
||||
iolog_info.runas_user = details->runas_pw->pw_name;
|
||||
iolog_info.runas_group = details->runas_gr ? details->runas_gr->gr_name: NULL;
|
||||
iolog_info.tty = (char *)details->tty;
|
||||
iolog_info.cwd = (char *)details->cwd;
|
||||
iolog_info.cmd = (char *)details->command;
|
||||
iolog_info.lines = details->lines;
|
||||
iolog_info.cols = details->cols;
|
||||
pathbuf[len] = '\0';
|
||||
strlcat(pathbuf, "/log", PATH_MAX);
|
||||
fd = io_open(pathbuf, O_CREAT|O_TRUNC|O_WRONLY, iolog_filemode);
|
||||
if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) {
|
||||
log_warning(SLOG_SEND_MAIL, N_("unable to create %s"), pathbuf);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to fchown %d:%d %s", __func__,
|
||||
(int)iolog_uid, (int)iolog_gid, pathbuf);
|
||||
}
|
||||
|
||||
fprintf(fp, "%lld:%s:%s:%s:%s:%d:%d\n%s\n%s", (long long)time(&now),
|
||||
details->user ? details->user : "unknown", details->runas_pw->pw_name,
|
||||
details->runas_gr ? details->runas_gr->gr_name : "",
|
||||
details->tty ? details->tty : "unknown", details->lines, details->cols,
|
||||
details->cwd ? details->cwd : "unknown",
|
||||
details->command ? details->command : "unknown");
|
||||
for (av = argv + 1; *av != NULL; av++) {
|
||||
fputc(' ', fp);
|
||||
fputs(*av, fp);
|
||||
}
|
||||
fputc('\n', fp);
|
||||
fflush(fp);
|
||||
if (ferror(fp)) {
|
||||
if (!iolog_write_info_file(pathbuf, &iolog_info, argv)) {
|
||||
log_warning(SLOG_SEND_MAIL,
|
||||
N_("unable to write to I/O log file: %s"), strerror(errno));
|
||||
warned = true;
|
||||
ret = false;
|
||||
debug_return_bool(false);
|
||||
}
|
||||
fclose(fp);
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
static const char *
|
||||
gzstrerror(gzFile file)
|
||||
{
|
||||
int errnum;
|
||||
|
||||
return gzerror(file, &errnum);
|
||||
}
|
||||
#endif /* HAVE_ZLIB_H */
|
||||
|
||||
/*
|
||||
* Write to an I/O log, compressing if iolog_compress is enabled.
|
||||
* If def_iolog_flush is true, flush the buffer immediately.
|
||||
*/
|
||||
static const char *
|
||||
iolog_write(union io_fd ifd, const void *buf, unsigned int len)
|
||||
{
|
||||
const char *errstr = NULL;
|
||||
debug_decl(iolog_write, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (iolog_compress) {
|
||||
if (gzwrite(ifd.g, (const voidp)buf, len) != (int)len) {
|
||||
errstr = gzstrerror(ifd.g);
|
||||
goto done;
|
||||
}
|
||||
if (def_iolog_flush) {
|
||||
if (gzflush(ifd.g, Z_SYNC_FLUSH) != Z_OK) {
|
||||
errstr = gzstrerror(ifd.g);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (fwrite(buf, 1, len, ifd.f) != len) {
|
||||
errstr = strerror(errno);
|
||||
goto done;
|
||||
}
|
||||
if (def_iolog_flush) {
|
||||
if (fflush(ifd.f) != 0) {
|
||||
errstr = strerror(errno);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
debug_return_const_str(errstr);
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -892,7 +411,6 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
||||
char * const *cur;
|
||||
const char *cp, *plugin_path = NULL;
|
||||
size_t len;
|
||||
mode_t omask;
|
||||
int i, ret = -1;
|
||||
debug_decl(sudoers_io_open, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
@@ -919,9 +437,6 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
||||
}
|
||||
}
|
||||
|
||||
/* umask must not be more restrictive than the file modes. */
|
||||
omask = umask(ACCESSPERMS & ~(iolog_filemode|iolog_dirmode));
|
||||
|
||||
if (!sudoers_debug_register(plugin_path, &debug_files)) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
@@ -944,7 +459,8 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
||||
goto done;
|
||||
}
|
||||
memcpy(tofree, _PATH_SUDO_IO_LOGDIR, sizeof(_PATH_SUDO_IO_LOGDIR));
|
||||
if (!io_nextid(tofree, NULL, sessid)) {
|
||||
if (!iolog_nextid(tofree, sessid)) {
|
||||
log_warning(SLOG_SEND_MAIL, N_("unable to update sequence file"));
|
||||
ret = false;
|
||||
goto done;
|
||||
}
|
||||
@@ -959,8 +475,10 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
||||
* intermediate subdirs. Calls mkdtemp() if iolog_path ends in XXXXXX.
|
||||
*/
|
||||
len = mkdir_iopath(iolog_details.iolog_path, pathbuf, sizeof(pathbuf));
|
||||
if (len >= sizeof(pathbuf))
|
||||
if (len >= sizeof(pathbuf)) {
|
||||
log_warning(SLOG_SEND_MAIL, "%s", iolog_details.iolog_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Write log file with user and command details. */
|
||||
if (!write_info_log(pathbuf, len, &iolog_details, argv))
|
||||
@@ -968,22 +486,31 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
||||
|
||||
/* Create the timing and I/O log files. */
|
||||
for (i = 0; i < IOFD_MAX; i++) {
|
||||
if (!open_io_fd(pathbuf, len, &io_log_files[i], iolog_compress))
|
||||
pathbuf[len] = '/';
|
||||
pathbuf[len + 1] = '\0';
|
||||
if (strlcat(pathbuf, iolog_fd_to_name(i), sizeof(pathbuf)) >= sizeof(pathbuf)) {
|
||||
errno = ENAMETOOLONG;
|
||||
log_warning(SLOG_SEND_MAIL, N_("unable to create %s"), pathbuf);
|
||||
goto done;
|
||||
}
|
||||
if (!iolog_open(&iolog_files[i], pathbuf, "w")) {
|
||||
log_warning(SLOG_SEND_MAIL, N_("unable to create %s"), pathbuf);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear I/O log function pointers for disabled log functions.
|
||||
*/
|
||||
if (!io_log_files[IOFD_STDIN].enabled)
|
||||
if (!iolog_files[IOFD_STDIN].enabled)
|
||||
sudoers_io.log_stdin = NULL;
|
||||
if (!io_log_files[IOFD_STDOUT].enabled)
|
||||
if (!iolog_files[IOFD_STDOUT].enabled)
|
||||
sudoers_io.log_stdout = NULL;
|
||||
if (!io_log_files[IOFD_STDERR].enabled)
|
||||
if (!iolog_files[IOFD_STDERR].enabled)
|
||||
sudoers_io.log_stderr = NULL;
|
||||
if (!io_log_files[IOFD_TTYIN].enabled)
|
||||
if (!iolog_files[IOFD_TTYIN].enabled)
|
||||
sudoers_io.log_ttyin = NULL;
|
||||
if (!io_log_files[IOFD_TTYOUT].enabled)
|
||||
if (!iolog_files[IOFD_TTYOUT].enabled)
|
||||
sudoers_io.log_ttyout = NULL;
|
||||
|
||||
if (sudo_gettime_awake(&last_time) == -1) {
|
||||
@@ -995,7 +522,6 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
||||
ret = true;
|
||||
|
||||
done:
|
||||
umask(omask);
|
||||
free(tofree);
|
||||
if (iolog_details.runas_pw)
|
||||
sudo_pw_delref(iolog_details.runas_pw);
|
||||
@@ -1019,18 +545,9 @@ sudoers_io_close(int exit_status, int error)
|
||||
debug_decl(sudoers_io_close, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
for (i = 0; i < IOFD_MAX; i++) {
|
||||
if (io_log_files[i].fd.v == NULL)
|
||||
if (iolog_files[i].fd.v == NULL)
|
||||
continue;
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (iolog_compress) {
|
||||
int errnum;
|
||||
|
||||
if (gzclose(io_log_files[i].fd.g) != Z_OK)
|
||||
errstr = gzerror(io_log_files[i].fd.g, &errnum);
|
||||
} else
|
||||
#endif
|
||||
if (fclose(io_log_files[i].fd.f) != 0)
|
||||
errstr = strerror(errno);
|
||||
iolog_close(&iolog_files[i], &errstr);
|
||||
}
|
||||
|
||||
if (errstr != NULL && !warned) {
|
||||
@@ -1061,7 +578,8 @@ sudoers_io_version(int verbose)
|
||||
* Returns 1 on success and -1 on error.
|
||||
*/
|
||||
static int
|
||||
sudoers_io_log(union io_fd ifd, const char *buf, unsigned int len, int event)
|
||||
sudoers_io_log(struct iolog_file *iol, const char *buf, unsigned int len,
|
||||
int event)
|
||||
{
|
||||
struct timespec now, delay;
|
||||
char tbuf[1024];
|
||||
@@ -1069,7 +587,7 @@ sudoers_io_log(union io_fd ifd, const char *buf, unsigned int len, int event)
|
||||
int ret = -1;
|
||||
debug_decl(sudoers_io_log, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
if (ifd.v == NULL) {
|
||||
if (!iol->enabled) {
|
||||
sudo_warnx(U_("%s: internal error, I/O log file for event %d not open"),
|
||||
__func__, event);
|
||||
debug_return_int(-1);
|
||||
@@ -1083,8 +601,7 @@ sudoers_io_log(union io_fd ifd, const char *buf, unsigned int len, int event)
|
||||
}
|
||||
|
||||
/* Write I/O log file entry. */
|
||||
errstr = iolog_write(ifd, buf, len);
|
||||
if (errstr != NULL)
|
||||
if (iolog_write(iol, buf, len, &errstr) == -1)
|
||||
goto done;
|
||||
|
||||
/* Write timing file entry. */
|
||||
@@ -1096,8 +613,7 @@ sudoers_io_log(union io_fd ifd, const char *buf, unsigned int len, int event)
|
||||
errstr = strerror(EOVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
errstr = iolog_write(io_log_files[IOFD_TIMING].fd, tbuf, len);
|
||||
if (errstr != NULL)
|
||||
if (iolog_write(&iolog_files[IOFD_TIMING], tbuf, len, &errstr) == -1)
|
||||
goto done;
|
||||
|
||||
/* Success. */
|
||||
@@ -1127,41 +643,31 @@ bad:
|
||||
static int
|
||||
sudoers_io_log_stdin(const char *buf, unsigned int len)
|
||||
{
|
||||
const union io_fd ifd = io_log_files[IOFD_STDIN].fd;
|
||||
|
||||
return sudoers_io_log(ifd, buf, len, IO_EVENT_STDIN);
|
||||
return sudoers_io_log(&iolog_files[IOFD_STDIN], buf, len, IO_EVENT_STDIN);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_log_stdout(const char *buf, unsigned int len)
|
||||
{
|
||||
const union io_fd ifd = io_log_files[IOFD_STDOUT].fd;
|
||||
|
||||
return sudoers_io_log(ifd, buf, len, IO_EVENT_STDOUT);
|
||||
return sudoers_io_log(&iolog_files[IOFD_STDOUT], buf, len, IO_EVENT_STDOUT);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_log_stderr(const char *buf, unsigned int len)
|
||||
{
|
||||
const union io_fd ifd = io_log_files[IOFD_STDERR].fd;
|
||||
|
||||
return sudoers_io_log(ifd, buf, len, IO_EVENT_STDERR);
|
||||
return sudoers_io_log(&iolog_files[IOFD_STDERR], buf, len, IO_EVENT_STDERR);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_log_ttyin(const char *buf, unsigned int len)
|
||||
{
|
||||
const union io_fd ifd = io_log_files[IOFD_TTYIN].fd;
|
||||
|
||||
return sudoers_io_log(ifd, buf, len, IO_EVENT_TTYIN);
|
||||
return sudoers_io_log(&iolog_files[IOFD_TTYIN], buf, len, IO_EVENT_TTYIN);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_log_ttyout(const char *buf, unsigned int len)
|
||||
{
|
||||
const union io_fd ifd = io_log_files[IOFD_TTYOUT].fd;
|
||||
|
||||
return sudoers_io_log(ifd, buf, len, IO_EVENT_TTYOUT);
|
||||
return sudoers_io_log(&iolog_files[IOFD_TTYOUT], buf, len, IO_EVENT_TTYOUT);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1190,8 +696,7 @@ sudoers_io_change_winsize(unsigned int lines, unsigned int cols)
|
||||
errstr = strerror(EOVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
errstr = iolog_write(io_log_files[IOFD_TIMING].fd, tbuf, len);
|
||||
if (errstr != NULL)
|
||||
if (iolog_write(&iolog_files[IOFD_TIMING], tbuf, len, &errstr) == -1)
|
||||
goto done;
|
||||
|
||||
/* Success. */
|
||||
@@ -1251,8 +756,7 @@ sudoers_io_suspend(int signo)
|
||||
errstr = strerror(EOVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
errstr = iolog_write(io_log_files[IOFD_TIMING].fd, tbuf, len);
|
||||
if (errstr != NULL)
|
||||
if (iolog_write(&iolog_files[IOFD_TIMING], tbuf, len, &errstr) == -1)
|
||||
goto done;
|
||||
|
||||
/* Success. */
|
||||
|
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2009-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.
|
||||
*/
|
||||
|
||||
#ifndef SUDOERS_IOLOG_H
|
||||
#define SUDOERS_IOLOG_H
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
# include <zlib.h> /* for gzFile */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* I/O log event types as stored as the first field in the timing file.
|
||||
* Changing existing values will result in incompatible I/O log files.
|
||||
*/
|
||||
#define IO_EVENT_STDIN 0
|
||||
#define IO_EVENT_STDOUT 1
|
||||
#define IO_EVENT_STDERR 2
|
||||
#define IO_EVENT_TTYIN 3
|
||||
#define IO_EVENT_TTYOUT 4
|
||||
#define IO_EVENT_WINSIZE 5
|
||||
#define IO_EVENT_TTYOUT_1_8_7 6
|
||||
#define IO_EVENT_SUSPEND 7
|
||||
#define IO_EVENT_COUNT 8
|
||||
|
||||
/* Default maximum session ID */
|
||||
#define SESSID_MAX 2176782336U
|
||||
|
||||
union io_fd {
|
||||
FILE *f;
|
||||
#ifdef HAVE_ZLIB_H
|
||||
gzFile g;
|
||||
#endif
|
||||
void *v;
|
||||
};
|
||||
|
||||
#endif /* SUDOERS_IOLOG_H */
|
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2013 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.
|
||||
*/
|
||||
|
||||
#ifndef SUDOERS_IOLOG_FILES_H
|
||||
#define SUDOERS_IOLOG_FILES_H
|
||||
|
||||
/*
|
||||
* Indexes into io_log_files[]
|
||||
*/
|
||||
#define IOFD_STDIN 0
|
||||
#define IOFD_STDOUT 1
|
||||
#define IOFD_STDERR 2
|
||||
#define IOFD_TTYIN 3
|
||||
#define IOFD_TTYOUT 4
|
||||
#define IOFD_TIMING 5
|
||||
#define IOFD_MAX 6
|
||||
|
||||
struct io_log_file {
|
||||
bool enabled;
|
||||
const char *suffix;
|
||||
union io_fd fd;
|
||||
};
|
||||
|
||||
static struct io_log_file io_log_files[] = {
|
||||
{ false, "/stdin" }, /* IOFD_STDIN */
|
||||
{ false, "/stdout" }, /* IOFD_STDOUT */
|
||||
{ false, "/stderr" }, /* IOFD_STDERR */
|
||||
{ false, "/ttyin" }, /* IOFD_TTYIN */
|
||||
{ false, "/ttyout" }, /* IOFD_TTYOUT */
|
||||
{ true, "/timing" }, /* IOFD_TIMING */
|
||||
{ false, NULL } /* IOFD_MAX */
|
||||
};
|
||||
|
||||
#endif /* SUDOERS_IOLOG_H */
|
148
plugins/sudoers/iolog_path_escapes.c
Normal file
148
plugins/sudoers/iolog_path_escapes.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2011-2015 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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>
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif /* HAVE_STRINGS_H */
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <limits.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sudoers.h"
|
||||
#include "sudo_iolog.h"
|
||||
|
||||
static size_t
|
||||
fill_seq(char *str, size_t strsize, char *logdir)
|
||||
{
|
||||
#ifdef SUDOERS_NO_SEQ
|
||||
debug_decl(fill_seq, SUDO_DEBUG_UTIL)
|
||||
debug_return_size_t(strlcpy(str, "%{seq}", strsize));
|
||||
#else
|
||||
static char sessid[7];
|
||||
int len;
|
||||
debug_decl(fill_seq, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (sessid[0] == '\0') {
|
||||
if (!iolog_nextid(logdir, sessid))
|
||||
debug_return_size_t((size_t)-1);
|
||||
}
|
||||
|
||||
/* Path is of the form /var/log/sudo-io/00/00/01. */
|
||||
len = snprintf(str, strsize, "%c%c/%c%c/%c%c", sessid[0],
|
||||
sessid[1], sessid[2], sessid[3], sessid[4], sessid[5]);
|
||||
if (len < 0)
|
||||
debug_return_size_t(strsize); /* handle non-standard snprintf() */
|
||||
debug_return_size_t(len);
|
||||
#endif /* SUDOERS_NO_SEQ */
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_user(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
debug_decl(fill_user, SUDO_DEBUG_UTIL)
|
||||
debug_return_size_t(strlcpy(str, user_name, strsize));
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_group(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
struct group *grp;
|
||||
size_t len;
|
||||
debug_decl(fill_group, SUDO_DEBUG_UTIL)
|
||||
|
||||
if ((grp = sudo_getgrgid(user_gid)) != NULL) {
|
||||
len = strlcpy(str, grp->gr_name, strsize);
|
||||
sudo_gr_delref(grp);
|
||||
} else {
|
||||
len = strlen(str);
|
||||
len = snprintf(str + len, strsize - len, "#%u",
|
||||
(unsigned int) user_gid);
|
||||
}
|
||||
debug_return_size_t(len);
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_runas_user(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
debug_decl(fill_runas_user, SUDO_DEBUG_UTIL)
|
||||
debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize));
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_runas_group(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
struct group *grp;
|
||||
size_t len;
|
||||
debug_decl(fill_runas_group, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (runas_gr != NULL) {
|
||||
len = strlcpy(str, runas_gr->gr_name, strsize);
|
||||
} else {
|
||||
if ((grp = sudo_getgrgid(runas_pw->pw_gid)) != NULL) {
|
||||
len = strlcpy(str, grp->gr_name, strsize);
|
||||
sudo_gr_delref(grp);
|
||||
} else {
|
||||
len = strlen(str);
|
||||
len = snprintf(str + len, strsize - len, "#%u",
|
||||
(unsigned int) runas_pw->pw_gid);
|
||||
}
|
||||
}
|
||||
debug_return_size_t(len);
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_hostname(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
debug_decl(fill_hostname, SUDO_DEBUG_UTIL)
|
||||
debug_return_size_t(strlcpy(str, user_shost, strsize));
|
||||
}
|
||||
|
||||
static size_t
|
||||
fill_command(char *str, size_t strsize, char *unused)
|
||||
{
|
||||
debug_decl(fill_command, SUDO_DEBUG_UTIL)
|
||||
debug_return_size_t(strlcpy(str, user_base, strsize));
|
||||
}
|
||||
|
||||
/* Note: "seq" must be first in the list. */
|
||||
static const struct iolog_path_escape path_escapes[] = {
|
||||
{ "seq", fill_seq },
|
||||
{ "user", fill_user },
|
||||
{ "group", fill_group },
|
||||
{ "runas_user", fill_runas_user },
|
||||
{ "runas_group", fill_runas_group },
|
||||
{ "hostname", fill_hostname },
|
||||
{ "command", fill_command },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
const struct iolog_path_escape *sudoers_iolog_path_escapes = path_escapes;
|
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2009-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.
|
||||
*/
|
||||
|
||||
#ifndef SUDOERS_IOLOG_READER_H
|
||||
#define SUDOERS_IOLOG_READER_H
|
||||
|
||||
#include "iolog.h"
|
||||
|
||||
/*
|
||||
* Info present in the I/O log file
|
||||
*/
|
||||
struct iolog_info {
|
||||
char *cwd;
|
||||
char *user;
|
||||
char *runas_user;
|
||||
char *runas_group;
|
||||
char *tty;
|
||||
char *cmd;
|
||||
time_t tstamp;
|
||||
int lines;
|
||||
int cols;
|
||||
};
|
||||
|
||||
struct timing_closure {
|
||||
struct timespec delay;
|
||||
const char *decimal;
|
||||
union io_fd fd;
|
||||
int event;
|
||||
union {
|
||||
struct {
|
||||
int lines;
|
||||
int cols;
|
||||
} winsize;
|
||||
size_t nbytes; // XXX
|
||||
int signo;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* iolog_reader.c */
|
||||
bool parse_timing(const char *line, struct timing_closure *timing);
|
||||
char *parse_delay(const char *cp, struct timespec *delay, const char *decimal_point);
|
||||
struct iolog_info *parse_logfile(const char *logfile);
|
||||
void free_iolog_info(struct iolog_info *li);
|
||||
void adjust_delay(struct timespec *delay, struct timespec *max_delay, double scale_factor);
|
||||
|
||||
#endif /* SUDOERS_IOLOG_READER_H */
|
@@ -550,8 +550,12 @@ sudoers_policy_exec_setup(char *argv[], char *envp[], mode_t cmnd_umask,
|
||||
if ((command_info[info_len++] = strdup("iolog_compress=true")) == NULL)
|
||||
goto oom;
|
||||
}
|
||||
if (def_maxseq) {
|
||||
if (asprintf(&command_info[info_len++], "maxseq=%u", def_maxseq) == -1)
|
||||
if (def_iolog_flush) {
|
||||
if ((command_info[info_len++] = strdup("iolog_flush=true")) == NULL)
|
||||
goto oom;
|
||||
}
|
||||
if (def_maxseq != NULL) {
|
||||
if (asprintf(&command_info[info_len++], "maxseq=%s", def_maxseq) == -1)
|
||||
goto oom;
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2018 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
* Copyright (c) 2018-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
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "sudoers.h"
|
||||
#include "def_data.c" /* for iolog_path.c */
|
||||
#include "sudo_plugin.h"
|
||||
#include "iolog_util.h"
|
||||
#include "sudo_iolog.h"
|
||||
|
||||
extern struct io_plugin sudoers_io;
|
||||
|
||||
@@ -337,7 +337,7 @@ test_endpoints(int *ntests, int *nerrors, const char *iolog_dir, char *envp[])
|
||||
int
|
||||
main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
struct passwd pw, rpw, *tpw;
|
||||
struct passwd *tpw;
|
||||
int tests = 0, errors = 0;
|
||||
const char *iolog_dir;
|
||||
|
||||
@@ -347,21 +347,20 @@ main(int argc, char *argv[], char *envp[])
|
||||
usage();
|
||||
iolog_dir = argv[1];
|
||||
|
||||
/* Bare minimum to link. */
|
||||
memset(&pw, 0, sizeof(pw));
|
||||
memset(&rpw, 0, sizeof(rpw));
|
||||
/* Set runas user. */
|
||||
if ((tpw = getpwuid(0)) == NULL) {
|
||||
if ((tpw = getpwnam("root")) == NULL)
|
||||
sudo_fatalx("unable to look up uid 0 or root");
|
||||
}
|
||||
rpw.pw_uid = tpw->pw_uid;
|
||||
rpw.pw_gid = tpw->pw_gid;
|
||||
sudo_user.pw = &pw;
|
||||
sudo_user._runas_pw = &rpw;
|
||||
sudo_user._runas_pw = pw_dup(tpw);
|
||||
|
||||
/* Set invoking user. */
|
||||
if ((tpw = getpwuid(geteuid())) == NULL)
|
||||
sudo_fatalx("unable to look up invoking user's uid");
|
||||
sudo_user.pw = pw_dup(tpw);
|
||||
|
||||
/* Set iolog uid/gid to invoking user. */
|
||||
iolog_uid = geteuid();
|
||||
iolog_gid = getegid();
|
||||
iolog_set_user(sudo_user.pw);
|
||||
|
||||
test_endpoints(&tests, &errors, iolog_dir, envp);
|
||||
|
||||
|
@@ -356,37 +356,6 @@ set_perms(int perm)
|
||||
goto bad;
|
||||
}
|
||||
break;
|
||||
|
||||
case PERM_IOLOG:
|
||||
state->gidlist = ostate->gidlist;
|
||||
sudo_gidlist_addref(state->gidlist);
|
||||
state->rgid = ostate->rgid;
|
||||
state->egid = iolog_gid;
|
||||
state->sgid = ostate->sgid;
|
||||
state->ruid = ROOT_UID;
|
||||
state->euid = iolog_uid;
|
||||
state->suid = ROOT_UID;
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: gid: "
|
||||
"[%d, %d, %d] -> [%d, %d, %d]", __func__,
|
||||
(int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
|
||||
(int)state->rgid, (int)state->egid, (int)state->sgid);
|
||||
if (GID_CHANGED && setresgid(ID(rgid), ID(egid), ID(sgid))) {
|
||||
(void)snprintf(errbuf, sizeof(errbuf),
|
||||
"PERM_IOLOG: setresgid(%d, %d, %d)",
|
||||
(int)ID(rgid), (int)ID(egid), (int)ID(sgid));
|
||||
goto bad;
|
||||
}
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: uid: "
|
||||
"[%d, %d, %d] -> [%d, %d, %d]", __func__,
|
||||
(int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
|
||||
(int)state->ruid, (int)state->euid, (int)state->suid);
|
||||
if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) {
|
||||
(void)snprintf(errbuf, sizeof(errbuf),
|
||||
"PERM_IOLOG: setresuid(%d, %d, %d)",
|
||||
(int)ID(ruid), (int)ID(euid), (int)ID(suid));
|
||||
goto bad;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
perm_stack_depth++;
|
||||
@@ -726,46 +695,6 @@ set_perms(int perm)
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PERM_IOLOG:
|
||||
state->gidlist = ostate->gidlist;
|
||||
sudo_gidlist_addref(state->gidlist);
|
||||
state->rgid = ostate->rgid;
|
||||
state->egid = iolog_gid;
|
||||
state->sgid = ostate->sgid;
|
||||
state->ruid = ROOT_UID;
|
||||
state->euid = iolog_uid;
|
||||
state->suid = ROOT_UID;
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: gid: "
|
||||
"[%d, %d, %d] -> [%d, %d, %d]", __func__,
|
||||
(int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid,
|
||||
(int)state->rgid, (int)state->egid, (int)state->sgid);
|
||||
if (GID_CHANGED && setgidx(ID_EFFECTIVE, iolog_gid)) {
|
||||
(void)snprintf(errbuf, sizeof(errbuf),
|
||||
"PERM_IOLOG: setgidx(ID_EFFECTIVE, %d)", (int)iolog_gid);
|
||||
goto bad;
|
||||
}
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: uid: "
|
||||
"[%d, %d, %d] -> [%d, %d, %d]", __func__,
|
||||
(int)ostate->ruid, (int)ostate->euid, (int)ostate->suid,
|
||||
(int)state->ruid, (int)state->euid, (int)state->suid);
|
||||
if (UID_CHANGED) {
|
||||
if (ostate->ruid != ROOT_UID || ostate->suid != ROOT_UID) {
|
||||
if (setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID)) {
|
||||
(void)snprintf(errbuf, sizeof(errbuf),
|
||||
"PERM_IOLOG: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)",
|
||||
ROOT_UID);
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
if (setuidx(ID_EFFECTIVE, timestamp_uid)) {
|
||||
(void)snprintf(errbuf, sizeof(errbuf),
|
||||
"PERM_IOLOG: setuidx(ID_EFFECTIVE, %d)",
|
||||
(int)timestamp_uid);
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
perm_stack_depth++;
|
||||
@@ -1129,33 +1058,6 @@ set_perms(int perm)
|
||||
goto bad;
|
||||
}
|
||||
break;
|
||||
|
||||
case PERM_IOLOG:
|
||||
state->gidlist = ostate->gidlist;
|
||||
sudo_gidlist_addref(state->gidlist);
|
||||
state->rgid = ostate->rgid;
|
||||
state->egid = iolog_gid;
|
||||
state->ruid = ROOT_UID;
|
||||
state->euid = iolog_uid;
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: gid: "
|
||||
"[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
|
||||
(int)ostate->egid, (int)state->rgid, (int)state->egid);
|
||||
if (GID_CHANGED && setregid(ID(rgid), ID(egid))) {
|
||||
(void)snprintf(errbuf, sizeof(errbuf),
|
||||
"PERM_IOLOG: setregid(%d, %d)",
|
||||
(int)ID(rgid), (int)ID(egid));
|
||||
goto bad;
|
||||
}
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: uid: "
|
||||
"[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
|
||||
(int)ostate->euid, (int)state->ruid, (int)state->euid);
|
||||
if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) {
|
||||
(void)snprintf(errbuf, sizeof(errbuf),
|
||||
"PERM_IOLOG: setreuid(%d, %d)",
|
||||
(int)ID(ruid), (int)ID(euid));
|
||||
goto bad;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
perm_stack_depth++;
|
||||
@@ -1459,31 +1361,6 @@ set_perms(int perm)
|
||||
goto bad;
|
||||
}
|
||||
break;
|
||||
|
||||
case PERM_IOLOG:
|
||||
state->gidlist = ostate->gidlist;
|
||||
sudo_gidlist_addref(state->gidlist);
|
||||
state->rgid = ostate->rgid;
|
||||
state->egid = iolog_gid;
|
||||
state->ruid = ROOT_UID;
|
||||
state->euid = iolog_uid;
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: gid: "
|
||||
"[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid,
|
||||
(int)ostate->egid, (int)state->rgid, (int)state->egid);
|
||||
if (GID_CHANGED && setegid(iolog_gid)) {
|
||||
(void)snprintf(errbuf, sizeof(errbuf),
|
||||
"PERM_IOLOG: setegid(%d)", (int)iolog_gid);
|
||||
goto bad;
|
||||
}
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_IOLOG: uid: "
|
||||
"[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid,
|
||||
(int)ostate->euid, (int)state->ruid, (int)state->euid);
|
||||
if (seteuid(timestamp_uid)) {
|
||||
(void)snprintf(errbuf, sizeof(errbuf),
|
||||
"PERM_IOLOG: seteuid(%d)", (int)timestamp_uid);
|
||||
goto bad;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
perm_stack_depth++;
|
||||
@@ -1524,11 +1401,11 @@ restore_perms(void)
|
||||
* real and effective uids to ROOT_UID initially to be safe.
|
||||
*/
|
||||
if (seteuid(ROOT_UID)) {
|
||||
sudo_warnx("seteuid() [%d] -> [%d]", (int)state->euid, ROOT_UID);
|
||||
sudo_warn("seteuid() [%d] -> [%d]", (int)state->euid, ROOT_UID);
|
||||
goto bad;
|
||||
}
|
||||
if (setuid(ROOT_UID)) {
|
||||
sudo_warnx("setuid() [%d, %d] -> [%d, %d]", (int)state->ruid, ROOT_UID,
|
||||
sudo_warn("setuid() [%d, %d] -> [%d, %d]", (int)state->ruid, ROOT_UID,
|
||||
ROOT_UID, ROOT_UID);
|
||||
goto bad;
|
||||
}
|
||||
@@ -1643,7 +1520,6 @@ set_perms(int perm)
|
||||
case PERM_SUDOERS:
|
||||
case PERM_RUNAS:
|
||||
case PERM_TIMESTAMP:
|
||||
case PERM_IOLOG:
|
||||
/* Unsupported since we can't set euid. */
|
||||
state->ruid = ostate->ruid;
|
||||
state->rgid = ostate->rgid;
|
||||
|
@@ -68,6 +68,7 @@
|
||||
#include "sudoers.h"
|
||||
#include "parse.h"
|
||||
#include "auth/sudo_auth.h"
|
||||
#include "sudo_iolog.h"
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
# include "compat/getaddrinfo.h"
|
||||
@@ -472,8 +473,12 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
|
||||
if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT))) {
|
||||
if ((def_log_input || def_log_output) && def_iolog_file && def_iolog_dir) {
|
||||
const char prefix[] = "iolog_path=";
|
||||
/* Use sudoers locale for strftime() */
|
||||
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
|
||||
iolog_path = expand_iolog_path(prefix, def_iolog_dir,
|
||||
def_iolog_file, &sudo_user.iolog_file);
|
||||
def_iolog_file, &sudo_user.iolog_file,
|
||||
sudoers_iolog_path_escapes);
|
||||
sudoers_setlocale(oldlocale, NULL);
|
||||
if (iolog_path == NULL) {
|
||||
if (!def_ignore_iolog_errors)
|
||||
goto done;
|
||||
|
@@ -237,13 +237,6 @@ struct sudo_user {
|
||||
# define SUDOERS_MODE 0600
|
||||
#endif
|
||||
|
||||
#ifdef __TANDEM
|
||||
# define ROOT_UID 65535
|
||||
#else
|
||||
# define ROOT_UID 0
|
||||
#endif
|
||||
#define ROOT_GID 0
|
||||
|
||||
struct sudo_lbuf;
|
||||
struct passwd;
|
||||
struct stat;
|
||||
@@ -350,17 +343,14 @@ char *get_timestr(time_t, int);
|
||||
bool get_boottime(struct timespec *);
|
||||
|
||||
/* iolog.c */
|
||||
bool io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7]);
|
||||
bool cb_maxseq(const union sudo_defs_val *sd_un);
|
||||
bool cb_iolog_user(const union sudo_defs_val *sd_un);
|
||||
bool cb_iolog_group(const union sudo_defs_val *sd_un);
|
||||
bool cb_iolog_mode(const union sudo_defs_val *sd_un);
|
||||
extern uid_t iolog_uid;
|
||||
extern gid_t iolog_gid;
|
||||
|
||||
/* iolog_path.c */
|
||||
char *expand_iolog_path(const char *prefix, const char *dir, const char *file,
|
||||
char **slashp);
|
||||
/* iolog_path_escapes.c */
|
||||
struct iolog_path_escape;
|
||||
extern const struct iolog_path_escape *sudoers_iolog_path_escapes;
|
||||
|
||||
/* env.c */
|
||||
char **env_get(void);
|
||||
|
@@ -64,8 +64,7 @@
|
||||
#include "sudo_compat.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "logging.h"
|
||||
#include "iolog_util.h"
|
||||
#include "iolog_files.h"
|
||||
#include "sudo_iolog.h"
|
||||
#include "sudo_queue.h"
|
||||
#include "sudo_plugin.h"
|
||||
#include "sudo_conf.h"
|
||||
@@ -80,6 +79,7 @@
|
||||
#endif /* HAVE_GETOPT_LONG */
|
||||
|
||||
struct replay_closure {
|
||||
const char *iolog_dir;
|
||||
struct sudo_event_base *evbase;
|
||||
struct sudo_event *delay_ev;
|
||||
struct sudo_event *keyboard_ev;
|
||||
@@ -146,6 +146,15 @@ static int terminal_lines, terminal_cols;
|
||||
|
||||
static int ttyfd = -1;
|
||||
|
||||
static struct iolog_file iolog_files[] = {
|
||||
{ false }, /* IOFD_STDIN */
|
||||
{ false }, /* IOFD_STDOUT */
|
||||
{ false }, /* IOFD_STDERR */
|
||||
{ false }, /* IOFD_TTYIN */
|
||||
{ false }, /* IOFD_TTYOUT */
|
||||
{ true, }, /* IOFD_TIMING */
|
||||
};
|
||||
|
||||
static const char short_opts[] = "d:f:hlm:nRSs:V";
|
||||
static struct option long_opts[] = {
|
||||
{ "directory", required_argument, NULL, 'd' },
|
||||
@@ -166,11 +175,11 @@ extern char *get_timestr(time_t, int);
|
||||
extern time_t get_date(char *);
|
||||
|
||||
static int list_sessions(int, char **, const char *, const char *, const char *);
|
||||
static int open_io_fd(char *path, int len, struct io_log_file *iol);
|
||||
static int parse_expr(struct search_node_list *, char **, bool);
|
||||
static void read_keyboard(int fd, int what, void *v);
|
||||
static void help(void) __attribute__((__noreturn__));
|
||||
static int replay_session(struct timespec *max_wait, const char *decimal, bool interactive, bool suspend_wait);
|
||||
static int replay_session(const char *iolog_dir, struct timespec *max_wait,
|
||||
const char *decimal, bool interactive, bool suspend_wait);
|
||||
static void sudoreplay_cleanup(void);
|
||||
static void usage(int);
|
||||
static void write_output(int fd, int what, void *v);
|
||||
@@ -238,15 +247,15 @@ main(int argc, char *argv[])
|
||||
def_filter = false;
|
||||
for (cp = strtok_r(optarg, ",", &ep); cp; cp = strtok_r(NULL, ",", &ep)) {
|
||||
if (strcmp(cp, "stdin") == 0)
|
||||
io_log_files[IOFD_STDIN].enabled = true;
|
||||
iolog_files[IOFD_STDIN].enabled = true;
|
||||
else if (strcmp(cp, "stdout") == 0)
|
||||
io_log_files[IOFD_STDOUT].enabled = true;
|
||||
iolog_files[IOFD_STDOUT].enabled = true;
|
||||
else if (strcmp(cp, "stderr") == 0)
|
||||
io_log_files[IOFD_STDERR].enabled = true;
|
||||
iolog_files[IOFD_STDERR].enabled = true;
|
||||
else if (strcmp(cp, "ttyin") == 0)
|
||||
io_log_files[IOFD_TTYIN].enabled = true;
|
||||
iolog_files[IOFD_TTYIN].enabled = true;
|
||||
else if (strcmp(cp, "ttyout") == 0)
|
||||
io_log_files[IOFD_TTYOUT].enabled = true;
|
||||
iolog_files[IOFD_TTYOUT].enabled = true;
|
||||
else
|
||||
sudo_fatalx(U_("invalid filter option: %s"), optarg);
|
||||
}
|
||||
@@ -308,9 +317,9 @@ main(int argc, char *argv[])
|
||||
|
||||
/* By default we replay stdout, stderr and ttyout. */
|
||||
if (def_filter) {
|
||||
io_log_files[IOFD_STDOUT].enabled = true;
|
||||
io_log_files[IOFD_STDERR].enabled = true;
|
||||
io_log_files[IOFD_TTYOUT].enabled = true;
|
||||
iolog_files[IOFD_STDOUT].enabled = true;
|
||||
iolog_files[IOFD_STDERR].enabled = true;
|
||||
iolog_files[IOFD_TTYOUT].enabled = true;
|
||||
}
|
||||
|
||||
/* 6 digit ID in base 36, e.g. 01G712AB or free-form name */
|
||||
@@ -327,15 +336,22 @@ main(int argc, char *argv[])
|
||||
sudo_fatalx(U_("%s/timing: %s"), id, strerror(ENAMETOOLONG));
|
||||
} else {
|
||||
plen = snprintf(path, sizeof(path), "%s/%s/timing", session_dir, id);
|
||||
if (plen < 0 || plen >= ssizeof(path))
|
||||
if (plen < 0 || plen >= ssizeof(path)) {
|
||||
sudo_fatalx(U_("%s/%s/timing: %s"), session_dir, id,
|
||||
strerror(ENAMETOOLONG));
|
||||
}
|
||||
}
|
||||
plen -= 7;
|
||||
|
||||
/* Open files for replay, applying replay filter for the -f flag. */
|
||||
for (i = 0; i < IOFD_MAX; i++) {
|
||||
if (open_io_fd(path, plen, &io_log_files[i]) == -1)
|
||||
path[plen] = '/';
|
||||
path[plen + 1] = '\0';
|
||||
if (strlcat(path, iolog_fd_to_name(i), sizeof(path)) >= sizeof(path)) {
|
||||
errno = ENAMETOOLONG;
|
||||
sudo_fatal("%s%s", path, iolog_fd_to_name(i));
|
||||
}
|
||||
if (!iolog_open(&iolog_files[i], path, "r"))
|
||||
sudo_fatal(U_("unable to open %s"), path);
|
||||
}
|
||||
|
||||
@@ -357,8 +373,10 @@ main(int argc, char *argv[])
|
||||
free_iolog_info(li);
|
||||
li = NULL;
|
||||
|
||||
/* Replay session corresponding to io_log_files[]. */
|
||||
exitcode = replay_session(max_delay, decimal, interactive, suspend_wait);
|
||||
/* Replay session corresponding to iolog_files[]. */
|
||||
path[plen] = '\0';
|
||||
exitcode = replay_session(path, max_delay, decimal, interactive,
|
||||
suspend_wait);
|
||||
|
||||
restore_terminal_size();
|
||||
sudo_term_restore(ttyfd, true);
|
||||
@@ -367,58 +385,6 @@ done:
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call gzread() or fread() for the I/O log file in question.
|
||||
* Return 0 for EOF or -1 on error.
|
||||
*/
|
||||
static ssize_t
|
||||
io_log_read(union io_fd ifd, char *buf, size_t nbytes)
|
||||
{
|
||||
ssize_t nread;
|
||||
debug_decl(io_log_read, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (nbytes > INT_MAX) {
|
||||
errno = EINVAL;
|
||||
debug_return_ssize_t(-1);
|
||||
}
|
||||
#ifdef HAVE_ZLIB_H
|
||||
nread = gzread(ifd.g, buf, nbytes);
|
||||
#else
|
||||
nread = (ssize_t)fread(buf, 1, nbytes, ifd.f);
|
||||
if (nread == 0 && ferror(ifd.f))
|
||||
nread = -1;
|
||||
#endif
|
||||
debug_return_ssize_t(nread);
|
||||
}
|
||||
|
||||
static int
|
||||
io_log_eof(union io_fd ifd)
|
||||
{
|
||||
int ret;
|
||||
debug_decl(io_log_eof, SUDO_DEBUG_UTIL)
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
ret = gzeof(ifd.g);
|
||||
#else
|
||||
ret = feof(ifd.f);
|
||||
#endif
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
static char *
|
||||
io_log_gets(union io_fd ifd, char *buf, size_t nbytes)
|
||||
{
|
||||
char *str;
|
||||
debug_decl(io_log_gets, SUDO_DEBUG_UTIL)
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
str = gzgets(ifd.g, buf, nbytes);
|
||||
#else
|
||||
str = fgets(buf, nbytes, ifd.f);
|
||||
#endif
|
||||
debug_return_str(str);
|
||||
}
|
||||
|
||||
/*
|
||||
* List of terminals that support xterm-like resizing.
|
||||
* This is not an exhaustive list.
|
||||
@@ -753,18 +719,23 @@ restore_terminal_size(void)
|
||||
* Read the next record from the timing file and schedule a delay
|
||||
* event with the specified timeout.
|
||||
* Return 0 on success, 1 on EOF and -1 on error.
|
||||
* XXX - duplicated in sendlog
|
||||
*/
|
||||
static int
|
||||
read_timing_record(struct replay_closure *closure)
|
||||
{
|
||||
struct timing_closure *timing = &closure->timing;
|
||||
char line[LINE_MAX];
|
||||
const char *errstr;
|
||||
debug_decl(read_timing_record, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Read next record from timing file. */
|
||||
if (io_log_gets(io_log_files[IOFD_TIMING].fd, line, sizeof(line)) == NULL) {
|
||||
if (iolog_gets(&iolog_files[IOFD_TIMING], line, sizeof(line), &errstr) == NULL) {
|
||||
/* EOF or error reading timing file, we are done. */
|
||||
debug_return_int(io_log_eof(io_log_files[IOFD_TIMING].fd) ? 1 : -1);
|
||||
if (iolog_eof(&iolog_files[IOFD_TIMING]))
|
||||
debug_return_int(1);
|
||||
sudo_fatalx(U_("error reading timing file: %s"), errstr);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
/* Parse timing file record. */
|
||||
@@ -773,7 +744,6 @@ read_timing_record(struct replay_closure *closure)
|
||||
sudo_fatalx(U_("invalid timing file line: %s"), line);
|
||||
|
||||
/* Record number bytes to read. */
|
||||
/* XXX - remove timing->nbytes? */
|
||||
if (timing->event != IO_EVENT_WINSIZE &&
|
||||
timing->event != IO_EVENT_SUSPEND) {
|
||||
closure->iobuf.len = 0;
|
||||
@@ -828,24 +798,27 @@ fill_iobuf(struct replay_closure *closure)
|
||||
{
|
||||
const size_t space = sizeof(closure->iobuf.buf) - closure->iobuf.len;
|
||||
const struct timing_closure *timing = &closure->timing;
|
||||
const char *errstr;
|
||||
debug_decl(fill_iobuf, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (closure->iobuf.toread != 0 && space != 0) {
|
||||
const size_t len =
|
||||
closure->iobuf.toread < space ? closure->iobuf.toread : space;
|
||||
ssize_t nread = io_log_read(timing->fd,
|
||||
closure->iobuf.buf + closure->iobuf.off, len);
|
||||
ssize_t nread = iolog_read(timing->iol,
|
||||
closure->iobuf.buf + closure->iobuf.off, len, &errstr);
|
||||
if (nread <= 0) {
|
||||
if (nread == 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"%s: premature EOF, expected %u bytes",
|
||||
io_log_files[timing->event].suffix, closure->iobuf.toread);
|
||||
"%s/%s: premature EOF, expected %u bytes",
|
||||
closure->iolog_dir, iolog_fd_to_name(timing->event),
|
||||
closure->iobuf.toread);
|
||||
} else {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
|
||||
"%s: read error", io_log_files[timing->event].suffix);
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"%s/%s: read error: %s", closure->iolog_dir,
|
||||
iolog_fd_to_name(timing->event), errstr);
|
||||
}
|
||||
sudo_warnx(U_("unable to read %s"),
|
||||
io_log_files[timing->event].suffix);
|
||||
sudo_warnx(U_("unable to read %s/%s: %s"),
|
||||
closure->iolog_dir, iolog_fd_to_name(timing->event), errstr);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
closure->iobuf.toread -= nread;
|
||||
@@ -872,28 +845,28 @@ delay_cb(int fd, int what, void *v)
|
||||
resize_terminal(timing->u.winsize.lines, timing->u.winsize.cols);
|
||||
break;
|
||||
case IO_EVENT_STDIN:
|
||||
if (io_log_files[IOFD_STDIN].enabled)
|
||||
timing->fd = io_log_files[IOFD_STDIN].fd;
|
||||
if (iolog_files[IOFD_STDIN].enabled)
|
||||
timing->iol = &iolog_files[IOFD_STDIN];
|
||||
break;
|
||||
case IO_EVENT_STDOUT:
|
||||
if (io_log_files[IOFD_STDOUT].enabled)
|
||||
timing->fd = io_log_files[IOFD_STDOUT].fd;
|
||||
if (iolog_files[IOFD_STDOUT].enabled)
|
||||
timing->iol = &iolog_files[IOFD_STDOUT];
|
||||
break;
|
||||
case IO_EVENT_STDERR:
|
||||
if (io_log_files[IOFD_STDERR].enabled)
|
||||
timing->fd = io_log_files[IOFD_STDERR].fd;
|
||||
if (iolog_files[IOFD_STDERR].enabled)
|
||||
timing->iol = &iolog_files[IOFD_STDERR];
|
||||
break;
|
||||
case IO_EVENT_TTYIN:
|
||||
if (io_log_files[IOFD_TTYIN].enabled)
|
||||
timing->fd = io_log_files[IOFD_TTYIN].fd;
|
||||
if (iolog_files[IOFD_TTYIN].enabled)
|
||||
timing->iol = &iolog_files[IOFD_TTYIN];
|
||||
break;
|
||||
case IO_EVENT_TTYOUT:
|
||||
if (io_log_files[IOFD_TTYOUT].enabled)
|
||||
timing->fd = io_log_files[IOFD_TTYOUT].fd;
|
||||
if (iolog_files[IOFD_TTYOUT].enabled)
|
||||
timing->iol = &iolog_files[IOFD_TTYOUT];
|
||||
break;
|
||||
}
|
||||
|
||||
if (timing->fd.v != NULL) {
|
||||
if (timing->iol != NULL) {
|
||||
/* If the stream is open, enable the write event. */
|
||||
if (sudo_ev_add(closure->evbase, closure->output_ev, NULL, false) == -1)
|
||||
sudo_fatal(U_("unable to add event to queue"));
|
||||
@@ -950,8 +923,8 @@ signal_cb(int signo, int what, void *v)
|
||||
}
|
||||
|
||||
static struct replay_closure *
|
||||
replay_closure_alloc(struct timespec *max_delay, const char *decimal,
|
||||
bool interactive, bool suspend_wait)
|
||||
replay_closure_alloc(const char *iolog_dir, struct timespec *max_delay,
|
||||
const char *decimal, bool interactive, bool suspend_wait)
|
||||
{
|
||||
struct replay_closure *closure;
|
||||
debug_decl(replay_closure_alloc, SUDO_DEBUG_UTIL)
|
||||
@@ -959,6 +932,7 @@ replay_closure_alloc(struct timespec *max_delay, const char *decimal,
|
||||
if ((closure = calloc(1, sizeof(*closure))) == NULL)
|
||||
debug_return_ptr(NULL);
|
||||
|
||||
closure->iolog_dir = iolog_dir;
|
||||
closure->interactive = interactive;
|
||||
closure->suspend_wait = suspend_wait;
|
||||
closure->max_delay = max_delay;
|
||||
@@ -1033,15 +1007,15 @@ bad:
|
||||
}
|
||||
|
||||
static int
|
||||
replay_session(struct timespec *max_delay, const char *decimal,
|
||||
bool interactive, bool suspend_wait)
|
||||
replay_session(const char *iolog_dir, struct timespec *max_delay,
|
||||
const char *decimal, bool interactive, bool suspend_wait)
|
||||
{
|
||||
struct replay_closure *closure;
|
||||
int ret = 0;
|
||||
debug_decl(replay_session, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Allocate the delay closure and read the first timing record. */
|
||||
closure = replay_closure_alloc(max_delay, decimal, interactive,
|
||||
closure = replay_closure_alloc(iolog_dir, max_delay, decimal, interactive,
|
||||
suspend_wait);
|
||||
if (read_timing_record(closure) != 0) {
|
||||
ret = 1;
|
||||
@@ -1059,28 +1033,6 @@ done:
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
open_io_fd(char *path, int len, struct io_log_file *iol)
|
||||
{
|
||||
debug_decl(open_io_fd, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (!iol->enabled)
|
||||
debug_return_int(0);
|
||||
|
||||
path[len] = '\0';
|
||||
strlcat(path, iol->suffix, PATH_MAX);
|
||||
#ifdef HAVE_ZLIB_H
|
||||
iol->fd.g = gzopen(path, "r");
|
||||
#else
|
||||
iol->fd.f = fopen(path, "r");
|
||||
#endif
|
||||
if (iol->fd.v == NULL) {
|
||||
iol->enabled = false;
|
||||
debug_return_int(-1);
|
||||
}
|
||||
debug_return_int(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the I/O buffer.
|
||||
*/
|
||||
|
@@ -50,12 +50,6 @@
|
||||
# define NDEBUG
|
||||
#endif
|
||||
|
||||
#ifdef __TANDEM
|
||||
# define ROOT_UID 65535
|
||||
#else
|
||||
# define ROOT_UID 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Various modes sudo can be in (based on arguments) in hex
|
||||
*/
|
||||
|
Reference in New Issue
Block a user