Add support for logging to the log server
This commit is contained in:
2
MANIFEST
2
MANIFEST
@@ -359,7 +359,9 @@ plugins/sudoers/insults.h
|
||||
plugins/sudoers/interfaces.c
|
||||
plugins/sudoers/interfaces.h
|
||||
plugins/sudoers/iolog.c
|
||||
plugins/sudoers/iolog_client.c
|
||||
plugins/sudoers/iolog_path_escapes.c
|
||||
plugins/sudoers/iolog_plugin.h
|
||||
plugins/sudoers/ldap.c
|
||||
plugins/sudoers/ldap_conf.c
|
||||
plugins/sudoers/ldap_util.c
|
||||
|
@@ -54,9 +54,10 @@ INSTALL_BACKUP = @INSTALL_BACKUP@
|
||||
# Libraries
|
||||
LIBUTIL = $(top_builddir)/lib/util/libsudo_util.la
|
||||
LIBIOLOG = $(top_builddir)/lib/iolog/libsudo_iolog.la
|
||||
LIBLOGSRV = $(top_builddir)/lib/logsrv/liblogsrv.la
|
||||
LIBS = $(LIBUTIL)
|
||||
NET_LIBS = @NET_LIBS@
|
||||
SUDOERS_LIBS = @SUDOERS_LIBS@ @AFS_LIBS@ @GETGROUPS_LIB@ $(NET_LIBS) $(LIBIOLOG)
|
||||
SUDOERS_LIBS = @SUDOERS_LIBS@ @AFS_LIBS@ @GETGROUPS_LIB@ $(NET_LIBS) $(LIBIOLOG) $(LIBLOGSRV)
|
||||
REPLAY_LIBS = @REPLAY_LIBS@ $(LIBIOLOG)
|
||||
VISUDO_LIBS = $(NET_LIBS)
|
||||
CVTSUDOERS_LIBS = $(NET_LIBS)
|
||||
@@ -158,17 +159,17 @@ LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo digestname.lo \
|
||||
filedigest.lo gentime.lo gmtoff.lo gram.lo hexchar.lo \
|
||||
match.lo match_addr.lo match_command.lo match_digest.lo \
|
||||
pwutil.lo pwutil_impl.lo rcstr.lo redblack.lo \
|
||||
sudoers_debug.lo timeout.lo timestr.lo toke.lo \
|
||||
toke_util.lo
|
||||
strlist.lo sudoers_debug.lo timeout.lo timestr.lo \
|
||||
toke.lo toke_util.lo
|
||||
|
||||
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_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@
|
||||
iolog_path_escapes.lo locale.lo iolog_client.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@
|
||||
|
||||
SUDOERS_IOBJS = $(SUDOERS_OBJS:.lo=.i)
|
||||
|
||||
@@ -179,17 +180,17 @@ VISUDO_IOBJS = sudo_printf.i visudo.i
|
||||
|
||||
CVTSUDOERS_OBJS = cvtsudoers.o cvtsudoers_json.o cvtsudoers_ldif.o \
|
||||
cvtsudoers_pwutil.o fmtsudoers.lo locale.lo parse_ldif.o \
|
||||
strlist.o stubs.o sudo_printf.o ldap_util.lo
|
||||
stubs.o sudo_printf.o ldap_util.lo
|
||||
|
||||
CVTSUDOERS_IOBJS = cvtsudoers.i cvtsudoers_json.i cvtsudoers_ldif.i \
|
||||
cvtsudoers_pwutil.i strlist.i
|
||||
cvtsudoers_pwutil.i
|
||||
|
||||
REPLAY_OBJS = getdate.o sudoreplay.o
|
||||
|
||||
REPLAY_IOBJS = $(REPLAY_OBJS:.o=.i)
|
||||
|
||||
TEST_OBJS = fmtsudoers.lo group_plugin.lo interfaces.lo ldap_util.lo \
|
||||
locale.lo net_ifs.o parse_ldif.o strlist.o sudo_printf.o \
|
||||
locale.lo net_ifs.o parse_ldif.o sudo_printf.o \
|
||||
testsudoers.o tsgetgrpw.o
|
||||
|
||||
IOBJS = $(LIBPARSESUDOERS_IOBJS) $(SUDOERS_IOBJS) $(VISUDO_IOBJS) \
|
||||
@@ -214,8 +215,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_PLUGIN_OBJS = check_iolog_plugin.o iolog.lo locale.lo pwutil.lo \
|
||||
pwutil_impl.lo redblack.lo sudoers_debug.lo
|
||||
CHECK_IOLOG_PLUGIN_OBJS = check_iolog_plugin.o iolog.lo iolog_client.lo \
|
||||
locale.lo pwutil.lo pwutil_impl.lo redblack.lo \
|
||||
strlist.lo sudoers_debug.lo
|
||||
|
||||
CHECK_SYMBOLS_OBJS = check_symbols.o
|
||||
|
||||
@@ -266,7 +268,7 @@ Makefile: $(srcdir)/Makefile.in
|
||||
libparsesudoers.la: $(LIBPARSESUDOERS_OBJS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(LIBPARSESUDOERS_OBJS) -no-install
|
||||
|
||||
sudoers.la: $(SUDOERS_OBJS) $(LIBUTIL) $(LIBIOLOG) libparsesudoers.la @LT_LDDEP@
|
||||
sudoers.la: $(SUDOERS_OBJS) $(LIBUTIL) $(LIBIOLOG) $(LIBLOGSRV) 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;; \
|
||||
@@ -310,8 +312,8 @@ check_gentime: $(CHECK_GENTIME_OBJS) $(LIBUTIL)
|
||||
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_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) $(LIBUTIL) $(LIBIOLOG) $(LIBLOGSRV)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_PLUGIN_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBIOLOG) $(LIBLOGSRV)
|
||||
|
||||
check_starttime: $(CHECK_STARTTIME_OBJS) $(LIBUTIL)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_STARTTIME_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
@@ -1494,25 +1496,57 @@ interfaces.i: $(srcdir)/interfaces.c $(devdir)/def_data.h \
|
||||
interfaces.plog: interfaces.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/interfaces.c --i-file $< --output-file $@
|
||||
iolog.lo: $(srcdir)/iolog.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/log_server.pb-c.h $(incdir)/protobuf-c/protobuf-c.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
|
||||
$(srcdir)/iolog_plugin.h $(srcdir)/logging.h $(srcdir)/parse.h \
|
||||
$(srcdir)/strlist.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.c
|
||||
iolog.i: $(srcdir)/iolog.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/log_server.pb-c.h $(incdir)/protobuf-c/protobuf-c.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
|
||||
$(srcdir)/iolog_plugin.h $(srcdir)/logging.h $(srcdir)/parse.h \
|
||||
$(srcdir)/strlist.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_client.lo: $(srcdir)/iolog_client.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/getaddrinfo.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/log_server.pb-c.h $(incdir)/protobuf-c/protobuf-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_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/defaults.h \
|
||||
$(srcdir)/iolog_plugin.h $(srcdir)/logging.h \
|
||||
$(srcdir)/parse.h $(srcdir)/strlist.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_client.c
|
||||
iolog_client.i: $(srcdir)/iolog_client.c $(devdir)/def_data.h \
|
||||
$(incdir)/compat/getaddrinfo.h $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/log_server.pb-c.h $(incdir)/protobuf-c/protobuf-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_plugin.h $(incdir)/sudo_queue.h \
|
||||
$(incdir)/sudo_util.h $(srcdir)/defaults.h \
|
||||
$(srcdir)/iolog_plugin.h $(srcdir)/logging.h \
|
||||
$(srcdir)/parse.h $(srcdir)/strlist.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_client.plog: iolog_client.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog_client.c --i-file $< --output-file $@
|
||||
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 \
|
||||
@@ -2201,11 +2235,11 @@ starttime.i: $(srcdir)/starttime.c $(devdir)/def_data.h \
|
||||
$(CC) -E -o $@ $(CPPFLAGS) $<
|
||||
starttime.plog: starttime.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/starttime.c --i-file $< --output-file $@
|
||||
strlist.o: $(srcdir)/strlist.c $(incdir)/compat/stdbool.h \
|
||||
strlist.lo: $(srcdir)/strlist.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/strlist.h \
|
||||
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/strlist.c
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/strlist.c
|
||||
strlist.i: $(srcdir)/strlist.c $(incdir)/compat/stdbool.h \
|
||||
$(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/strlist.h \
|
||||
|
@@ -505,6 +505,14 @@ struct sudo_defs_types sudo_defs_table[] = {
|
||||
"log_denied", T_FLAG,
|
||||
N_("Log when a command is denied by sudoers"),
|
||||
NULL,
|
||||
}, {
|
||||
"log_server", T_LIST|T_BOOL,
|
||||
N_("Sudo log server(s) to connect to with optional port"),
|
||||
NULL,
|
||||
}, {
|
||||
"log_server_timeout", T_TIMEOUT|T_BOOL,
|
||||
N_("Sudo log server timeout in seconds: %u"),
|
||||
NULL,
|
||||
}, {
|
||||
NULL, 0, NULL
|
||||
}
|
||||
|
@@ -232,6 +232,10 @@
|
||||
#define def_log_allowed (sudo_defs_table[I_LOG_ALLOWED].sd_un.flag)
|
||||
#define I_LOG_DENIED 116
|
||||
#define def_log_denied (sudo_defs_table[I_LOG_DENIED].sd_un.flag)
|
||||
#define I_LOG_SERVER 117
|
||||
#define def_log_server (sudo_defs_table[I_LOG_SERVER].sd_un.list)
|
||||
#define I_LOG_SERVER_TIMEOUT 118
|
||||
#define def_log_server_timeout (sudo_defs_table[I_LOG_SERVER_TIMEOUT].sd_un.ival)
|
||||
|
||||
enum def_tuple {
|
||||
never,
|
||||
|
@@ -366,3 +366,9 @@ log_allowed
|
||||
log_denied
|
||||
T_FLAG
|
||||
"Log when a command is denied by sudoers"
|
||||
log_server
|
||||
T_LIST|T_BOOL
|
||||
"Sudo log server(s) to connect to with optional port"
|
||||
log_server_timeout
|
||||
T_TIMEOUT|T_BOOL
|
||||
"Sudo log server timeout in seconds: %u"
|
||||
|
@@ -562,6 +562,7 @@ init_defaults(void)
|
||||
#ifdef HAVE_ZLIB_H
|
||||
def_compress_io = true;
|
||||
#endif
|
||||
def_log_server_timeout = 30;
|
||||
def_ignore_audit_errors = true;
|
||||
def_ignore_iolog_errors = false;
|
||||
def_ignore_logfile_errors = true;
|
||||
|
@@ -43,23 +43,7 @@
|
||||
|
||||
#include "sudoers.h"
|
||||
#include "sudo_iolog.h"
|
||||
|
||||
/* XXX - separate sudoers.h and iolog.h? */
|
||||
#undef runas_pw
|
||||
#undef runas_gr
|
||||
|
||||
struct iolog_details {
|
||||
const char *cwd;
|
||||
const char *tty;
|
||||
const char *user;
|
||||
const char *command;
|
||||
const char *iolog_path;
|
||||
struct passwd *runas_pw;
|
||||
struct group *runas_gr;
|
||||
int lines;
|
||||
int cols;
|
||||
bool ignore_iolog_errors;
|
||||
};
|
||||
#include "iolog_plugin.h"
|
||||
|
||||
static struct iolog_file iolog_files[] = {
|
||||
{ false }, /* IOFD_STDIN */
|
||||
@@ -70,6 +54,7 @@ static struct iolog_file iolog_files[] = {
|
||||
{ true, }, /* IOFD_TIMING */
|
||||
};
|
||||
|
||||
static struct client_closure client_closure = CLIENT_CLOSURE_INITIALIZER(client_closure);
|
||||
static struct iolog_details iolog_details;
|
||||
static bool warned = false;
|
||||
static struct timespec last_time;
|
||||
@@ -77,6 +62,8 @@ static struct timespec last_time;
|
||||
/* sudoers_io is declared at the end of this file. */
|
||||
extern __dso_public struct io_plugin sudoers_io;
|
||||
|
||||
#define iolog_remote (client_closure.sock != -1)
|
||||
|
||||
/*
|
||||
* Sudoers callback for maxseq Defaults setting.
|
||||
*/
|
||||
@@ -162,10 +149,47 @@ cb_iolog_mode(const union sudo_defs_val *sd_un)
|
||||
}
|
||||
|
||||
/*
|
||||
* Pull out I/O log related data from user_info and command_info arrays.
|
||||
* Returns true if I/O logging is enabled, else false.
|
||||
* Convert a comma-separated list to a string list.
|
||||
*/
|
||||
static bool
|
||||
static struct sudoers_str_list *
|
||||
deserialize_stringlist(const char *s)
|
||||
{
|
||||
struct sudoers_str_list *strlist;
|
||||
struct sudoers_string *str;
|
||||
const char *s_end = s + strlen(s);
|
||||
const char *cp, *ep;
|
||||
debug_decl(deserialize_stringlist, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
if ((strlist = str_list_alloc()) == NULL)
|
||||
debug_return_ptr(NULL);
|
||||
|
||||
for (cp = sudo_strsplit(s, s_end, ",", &ep); cp != NULL;
|
||||
cp = sudo_strsplit(NULL, s_end, ",", &ep)) {
|
||||
if (cp == ep)
|
||||
continue;
|
||||
if ((str = malloc(sizeof(*str))) == NULL)
|
||||
goto bad;
|
||||
if ((str->str = strndup(cp, (ep - cp))) == NULL) {
|
||||
free(str);
|
||||
goto bad;
|
||||
}
|
||||
STAILQ_INSERT_TAIL(strlist, str, entries);
|
||||
}
|
||||
if (STAILQ_EMPTY(strlist))
|
||||
goto bad;
|
||||
|
||||
debug_return_ptr(strlist);
|
||||
|
||||
bad:
|
||||
str_list_free(strlist);
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pull out I/O log related data from user_info and command_info arrays.
|
||||
* Returns true if I/O logging is enabled, false if not and -1 on error.
|
||||
*/
|
||||
static int
|
||||
iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
|
||||
char * const command_info[])
|
||||
{
|
||||
@@ -197,6 +221,12 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (strncmp(*cur, "host=", sizeof("host=") - 1) == 0) {
|
||||
details->host = *cur + sizeof("host=") - 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if (strncmp(*cur, "lines=", sizeof("lines=") - 1) == 0) {
|
||||
int n = sudo_strtonum(*cur + sizeof("lines=") - 1, 1, INT_MAX,
|
||||
@@ -319,6 +349,21 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if (strncmp(*cur, "log_servers=", sizeof("log_servers=") - 1) == 0) {
|
||||
details->log_servers =
|
||||
deserialize_stringlist(*cur + sizeof("log_servers=") - 1);
|
||||
if (!details->log_servers)
|
||||
goto oom;
|
||||
continue;
|
||||
}
|
||||
if (strncmp(*cur, "log_server_timeout=", sizeof("log_server_timeout=") - 1) == 0) {
|
||||
details->server_timeout.tv_sec =
|
||||
sudo_strtonum(*cur + sizeof("log_server_timeout=") - 1, 1,
|
||||
TIME_T_MAX, NULL);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
if (strncmp(*cur, "maxseq=", sizeof("maxseq=") - 1) == 0) {
|
||||
union sudo_defs_val sd_un;
|
||||
@@ -385,10 +430,14 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
|
||||
details->runas_gr = sudo_fakegrnam(idbuf);
|
||||
}
|
||||
}
|
||||
debug_return_bool(
|
||||
debug_return_int(
|
||||
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);
|
||||
oom:
|
||||
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
str_list_free(details->log_servers);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -396,8 +445,7 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
|
||||
* This file is not compressed.
|
||||
*/
|
||||
static bool
|
||||
write_info_log(int dfd, char *iolog_dir, struct iolog_details *details,
|
||||
char * const argv[])
|
||||
write_info_log(int dfd, char *iolog_dir, struct iolog_details *details)
|
||||
{
|
||||
struct iolog_info iolog_info;
|
||||
debug_decl(write_info_log, SUDOERS_DEBUG_UTIL)
|
||||
@@ -414,7 +462,7 @@ write_info_log(int dfd, char *iolog_dir, struct iolog_details *details,
|
||||
iolog_info.lines = details->lines;
|
||||
iolog_info.cols = details->cols;
|
||||
|
||||
if (!iolog_write_info_file(dfd, iolog_dir, &iolog_info, argv)) {
|
||||
if (!iolog_write_info_file(dfd, iolog_dir, &iolog_info, details->argv)) {
|
||||
log_warning(SLOG_SEND_MAIL,
|
||||
N_("unable to write to I/O log file: %s"), strerror(errno));
|
||||
warned = true;
|
||||
@@ -424,55 +472,13 @@ write_info_log(int dfd, char *iolog_dir, struct iolog_details *details,
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
||||
sudo_printf_t plugin_printf, char * const settings[],
|
||||
char * const user_info[], char * const command_info[],
|
||||
int argc, char * const argv[], char * const user_env[], char * const args[])
|
||||
sudoers_io_open_local(void)
|
||||
{
|
||||
struct sudo_conf_debug_file_list debug_files = TAILQ_HEAD_INITIALIZER(debug_files);
|
||||
char iolog_path[PATH_MAX], sessid[7];
|
||||
char * const *cur;
|
||||
const char *cp, *plugin_path = NULL;
|
||||
size_t len;
|
||||
int i, ret = -1;
|
||||
int iolog_dir_fd = -1;
|
||||
debug_decl(sudoers_io_open, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
sudo_conv = conversation;
|
||||
sudo_printf = plugin_printf;
|
||||
|
||||
/* If we have no command (because -V was specified) just return. */
|
||||
if (argc == 0)
|
||||
debug_return_int(true);
|
||||
|
||||
bindtextdomain("sudoers", LOCALEDIR);
|
||||
|
||||
/* Initialize the debug subsystem. */
|
||||
for (cur = settings; (cp = *cur) != NULL; cur++) {
|
||||
if (strncmp(cp, "debug_flags=", sizeof("debug_flags=") - 1) == 0) {
|
||||
cp += sizeof("debug_flags=") - 1;
|
||||
if (!sudoers_debug_parse_flags(&debug_files, cp))
|
||||
debug_return_int(-1);
|
||||
continue;
|
||||
}
|
||||
if (strncmp(cp, "plugin_path=", sizeof("plugin_path=") - 1) == 0) {
|
||||
plugin_path = cp + sizeof("plugin_path=") - 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sudoers_debug_register(plugin_path, &debug_files)) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pull iolog settings out of command_info.
|
||||
*/
|
||||
if (!iolog_deserialize_info(&iolog_details, user_info, command_info)) {
|
||||
ret = false;
|
||||
goto done;
|
||||
}
|
||||
int i, ret = -1;
|
||||
debug_decl(sudoers_io_open_local, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
/* If no I/O log path defined we need to figure it out ourselves. */
|
||||
if (iolog_details.iolog_path == NULL) {
|
||||
@@ -517,7 +523,7 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
||||
}
|
||||
|
||||
/* Write log file with user and command details. */
|
||||
if (!write_info_log(iolog_dir_fd, iolog_path, &iolog_details, argv))
|
||||
if (!write_info_log(iolog_dir_fd, iolog_path, &iolog_details))
|
||||
goto done;
|
||||
|
||||
/* Create the timing and I/O log files. */
|
||||
@@ -529,6 +535,107 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
||||
}
|
||||
}
|
||||
|
||||
ret = true;
|
||||
|
||||
done:
|
||||
if (iolog_dir_fd != -1)
|
||||
close(iolog_dir_fd);
|
||||
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_open_remote(void)
|
||||
{
|
||||
int sock, ret = -1;
|
||||
debug_decl(sudoers_io_open_remote, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
/* Connect to log server. */
|
||||
sock = log_server_connect(iolog_details.log_servers,
|
||||
&iolog_details.server_timeout);
|
||||
if (sock == -1) {
|
||||
/* TODO: support offline logs if server unreachable */
|
||||
sudo_warnx(U_("unable to connect to log server"));
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!client_closure_fill(&client_closure, sock, &iolog_details, &sudoers_io)) {
|
||||
close(sock);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Enable reader for server hello */
|
||||
ret = client_closure.read_ev->add(client_closure.read_ev,
|
||||
&iolog_details.server_timeout);
|
||||
if (ret == -1)
|
||||
sudo_warn(U_("unable to add event to queue"));
|
||||
|
||||
done:
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
||||
sudo_printf_t plugin_printf, char * const settings[],
|
||||
char * const user_info[], char * const command_info[],
|
||||
int argc, char * const argv[], char * const user_env[], char * const args[])
|
||||
{
|
||||
struct sudo_conf_debug_file_list debug_files = TAILQ_HEAD_INITIALIZER(debug_files);
|
||||
char * const *cur;
|
||||
const char *cp, *plugin_path = NULL;
|
||||
int ret = -1;
|
||||
debug_decl(sudoers_io_open, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
sudo_conv = conversation;
|
||||
sudo_printf = plugin_printf;
|
||||
|
||||
/* If we have no command (because -V was specified) just return. */
|
||||
if (argc == 0)
|
||||
debug_return_int(true);
|
||||
|
||||
bindtextdomain("sudoers", LOCALEDIR);
|
||||
|
||||
/* Initialize the debug subsystem. */
|
||||
for (cur = settings; (cp = *cur) != NULL; cur++) {
|
||||
if (strncmp(cp, "debug_flags=", sizeof("debug_flags=") - 1) == 0) {
|
||||
cp += sizeof("debug_flags=") - 1;
|
||||
if (!sudoers_debug_parse_flags(&debug_files, cp))
|
||||
debug_return_int(-1);
|
||||
continue;
|
||||
}
|
||||
if (strncmp(cp, "plugin_path=", sizeof("plugin_path=") - 1) == 0) {
|
||||
plugin_path = cp + sizeof("plugin_path=") - 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sudoers_debug_register(plugin_path, &debug_files)) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pull iolog settings out of command_info.
|
||||
*/
|
||||
ret = iolog_deserialize_info(&iolog_details, user_info, command_info);
|
||||
if (ret != true)
|
||||
goto done;
|
||||
iolog_details.user_env = user_env;
|
||||
iolog_details.argv = argv;
|
||||
iolog_details.argc = argc;
|
||||
|
||||
/*
|
||||
* Create local I/O log file or connect to remote log server.
|
||||
*/
|
||||
if (sudoers_io.event_alloc != NULL && iolog_details.log_servers != NULL)
|
||||
ret = sudoers_io_open_remote();
|
||||
else
|
||||
ret = sudoers_io_open_local();
|
||||
if (ret != true)
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Clear I/O log function pointers for disabled log functions.
|
||||
*/
|
||||
@@ -548,18 +655,19 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
||||
"%s: unable to get time of day", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
if (iolog_remote)
|
||||
client_closure.start_time = last_time;
|
||||
|
||||
done:
|
||||
if (iolog_dir_fd != -1)
|
||||
close(iolog_dir_fd);
|
||||
if (ret != true) {
|
||||
client_closure_free(&client_closure);
|
||||
if (iolog_details.runas_pw)
|
||||
sudo_pw_delref(iolog_details.runas_pw);
|
||||
if (iolog_details.runas_gr)
|
||||
sudo_gr_delref(iolog_details.runas_gr);
|
||||
sudo_freepwcache();
|
||||
sudo_freegrcache();
|
||||
}
|
||||
|
||||
/* Ignore errors if they occur if the policy says so. */
|
||||
if (ret == -1 && iolog_details.ignore_iolog_errors)
|
||||
@@ -575,11 +683,35 @@ sudoers_io_close(int exit_status, int error)
|
||||
int i;
|
||||
debug_decl(sudoers_io_close, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
if (iolog_remote) {
|
||||
if (client_closure.disabled)
|
||||
goto done;
|
||||
|
||||
if (!fmt_exit_message(&client_closure, exit_status, error))
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Main sudo event loop exited, use our own mini event loop
|
||||
* to flush the write queue and read the final commit messages.
|
||||
*/
|
||||
if (!client_loop(&client_closure))
|
||||
goto done;
|
||||
} else {
|
||||
for (i = 0; i < IOFD_MAX; i++) {
|
||||
if (iolog_files[i].fd.v == NULL)
|
||||
continue;
|
||||
iolog_close(&iolog_files[i], &errstr);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
client_closure_free(&client_closure);
|
||||
if (iolog_details.runas_pw)
|
||||
sudo_pw_delref(iolog_details.runas_pw);
|
||||
if (iolog_details.runas_gr)
|
||||
sudo_gr_delref(iolog_details.runas_gr);
|
||||
sudo_freepwcache();
|
||||
sudo_freegrcache();
|
||||
|
||||
if (errstr != NULL && !warned) {
|
||||
/* Only warn about I/O log file errors once. */
|
||||
@@ -605,52 +737,128 @@ sudoers_io_version(int verbose)
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic I/O logging function. Called by the I/O logging entry points.
|
||||
* Write an I/O log entry to the local file system.
|
||||
* Returns 1 on success and -1 on error.
|
||||
* Fills in errstr on error.
|
||||
*/
|
||||
static int
|
||||
sudoers_io_log(struct iolog_file *iol, const char *buf, unsigned int len,
|
||||
int event)
|
||||
sudoers_io_log_local(int event, const char *buf, unsigned int len,
|
||||
struct timespec *delay, const char **errstr)
|
||||
{
|
||||
struct timespec now, delay;
|
||||
struct iolog_file *iol;
|
||||
char tbuf[1024];
|
||||
const char *errstr = NULL;
|
||||
int ret = -1;
|
||||
debug_decl(sudoers_io_log, SUDOERS_DEBUG_PLUGIN)
|
||||
debug_decl(sudoers_io_log_local, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
if (event < 0 || event >= IOFD_MAX) {
|
||||
*errstr = NULL;
|
||||
sudo_warnx(U_("unexpected I/O event %d"), event);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
iol = &iolog_files[event];
|
||||
if (!iol->enabled) {
|
||||
*errstr = NULL;
|
||||
sudo_warnx(U_("%s: internal error, I/O log file for event %d not open"),
|
||||
__func__, event);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
/* Write I/O log file entry. */
|
||||
if (iolog_write(iol, buf, len, errstr) == -1)
|
||||
goto done;
|
||||
|
||||
/* Write timing file entry. */
|
||||
len = (unsigned int)snprintf(tbuf, sizeof(tbuf), "%d %lld.%09ld %u\n",
|
||||
event, (long long)delay->tv_sec, delay->tv_nsec, len);
|
||||
if (len >= sizeof(tbuf)) {
|
||||
/* Not actually possible due to the size of tbuf[]. */
|
||||
*errstr = strerror(EOVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
if (iolog_write(&iolog_files[IOFD_TIMING], tbuf, len, errstr) == -1)
|
||||
goto done;
|
||||
|
||||
/* Success. */
|
||||
ret = 1;
|
||||
|
||||
done:
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule an I/O log entry to be written to the log server.
|
||||
* Returns 1 on success and -1 on error.
|
||||
* Fills in errstr on error.
|
||||
*/
|
||||
static int
|
||||
sudoers_io_log_remote(int event, const char *buf, unsigned int len,
|
||||
struct timespec *delay, const char **errstr)
|
||||
{
|
||||
int type, ret = -1;
|
||||
debug_decl(sudoers_io_log_remote, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
if (client_closure.disabled)
|
||||
debug_return_int(1);
|
||||
|
||||
/* Track elapsed time for comparison with commit points. */
|
||||
sudo_timespecadd(delay, &client_closure.elapsed, &client_closure.elapsed);
|
||||
|
||||
switch (event) {
|
||||
case IO_EVENT_STDIN:
|
||||
type = CLIENT_MESSAGE__TYPE_STDIN_BUF;
|
||||
break;
|
||||
case IO_EVENT_STDOUT:
|
||||
type = CLIENT_MESSAGE__TYPE_STDOUT_BUF;
|
||||
break;
|
||||
case IO_EVENT_STDERR:
|
||||
type = CLIENT_MESSAGE__TYPE_STDERR_BUF;
|
||||
break;
|
||||
case IO_EVENT_TTYIN:
|
||||
type = CLIENT_MESSAGE__TYPE_TTYIN_BUF;
|
||||
break;
|
||||
case IO_EVENT_TTYOUT:
|
||||
type = CLIENT_MESSAGE__TYPE_TTYOUT_BUF;
|
||||
break;
|
||||
default:
|
||||
sudo_warnx(U_("unexpected I/O event %d"), event);
|
||||
goto done;
|
||||
}
|
||||
if (fmt_io_buf(&client_closure, type, buf, len, delay)) {
|
||||
ret = client_closure.write_ev->add(client_closure.write_ev,
|
||||
&iolog_details.server_timeout);
|
||||
if (ret == -1)
|
||||
sudo_warn(U_("unable to add event to queue"));
|
||||
}
|
||||
|
||||
done:
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic I/O logging function. Called by the I/O logging entry points.
|
||||
* Returns 1 on success and -1 on error.
|
||||
*/
|
||||
static int
|
||||
sudoers_io_log(const char *buf, unsigned int len, int event)
|
||||
{
|
||||
struct timespec now, delay;
|
||||
const char *errstr = NULL;
|
||||
int ret = -1;
|
||||
debug_decl(sudoers_io_log, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
if (sudo_gettime_awake(&now) == -1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||
"%s: unable to get time of day", __func__);
|
||||
errstr = strerror(errno);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Write I/O log file entry. */
|
||||
if (iolog_write(iol, buf, len, &errstr) == -1)
|
||||
goto done;
|
||||
|
||||
/* Write timing file entry. */
|
||||
sudo_timespecsub(&now, &last_time, &delay);
|
||||
len = (unsigned int)snprintf(tbuf, sizeof(tbuf), "%d %lld.%09ld %u\n",
|
||||
event, (long long)delay.tv_sec, delay.tv_nsec, len);
|
||||
if (len >= sizeof(tbuf)) {
|
||||
/* Not actually possible due to the size of tbuf[]. */
|
||||
errstr = strerror(EOVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
if (iolog_write(&iolog_files[IOFD_TIMING], tbuf, len, &errstr) == -1)
|
||||
goto done;
|
||||
|
||||
/* Success. */
|
||||
ret = 1;
|
||||
if (iolog_remote)
|
||||
ret = sudoers_io_log_remote(event, buf, len, &delay, &errstr);
|
||||
else
|
||||
ret = sudoers_io_log_local(event, buf, len, &delay, &errstr);
|
||||
|
||||
done:
|
||||
last_time.tv_sec = now.tv_sec;
|
||||
last_time.tv_nsec = now.tv_nsec;
|
||||
|
||||
@@ -674,39 +882,87 @@ bad:
|
||||
static int
|
||||
sudoers_io_log_stdin(const char *buf, unsigned int len)
|
||||
{
|
||||
return sudoers_io_log(&iolog_files[IOFD_STDIN], buf, len, IO_EVENT_STDIN);
|
||||
return sudoers_io_log(buf, len, IO_EVENT_STDIN);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_log_stdout(const char *buf, unsigned int len)
|
||||
{
|
||||
return sudoers_io_log(&iolog_files[IOFD_STDOUT], buf, len, IO_EVENT_STDOUT);
|
||||
return sudoers_io_log(buf, len, IO_EVENT_STDOUT);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_log_stderr(const char *buf, unsigned int len)
|
||||
{
|
||||
return sudoers_io_log(&iolog_files[IOFD_STDERR], buf, len, IO_EVENT_STDERR);
|
||||
return sudoers_io_log(buf, len, IO_EVENT_STDERR);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_log_ttyin(const char *buf, unsigned int len)
|
||||
{
|
||||
return sudoers_io_log(&iolog_files[IOFD_TTYIN], buf, len, IO_EVENT_TTYIN);
|
||||
return sudoers_io_log(buf, len, IO_EVENT_TTYIN);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_log_ttyout(const char *buf, unsigned int len)
|
||||
{
|
||||
return sudoers_io_log(&iolog_files[IOFD_TTYOUT], buf, len, IO_EVENT_TTYOUT);
|
||||
return sudoers_io_log(buf, len, IO_EVENT_TTYOUT);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_change_winsize_local(unsigned int lines, unsigned int cols,
|
||||
struct timespec *delay, const char **errstr)
|
||||
{
|
||||
char tbuf[1024];
|
||||
int len, ret = -1;
|
||||
debug_decl(sudoers_io_change_winsize_local, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
/* Write window change event to the timing file. */
|
||||
len = snprintf(tbuf, sizeof(tbuf), "%d %lld.%09ld %u %u\n",
|
||||
IO_EVENT_WINSIZE, (long long)delay->tv_sec, delay->tv_nsec,
|
||||
lines, cols);
|
||||
if (len < 0 || len >= ssizeof(tbuf)) {
|
||||
/* Not actually possible due to the size of tbuf[]. */
|
||||
*errstr = strerror(EOVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
if (iolog_write(&iolog_files[IOFD_TIMING], tbuf, len, errstr) == -1)
|
||||
goto done;
|
||||
|
||||
/* Success. */
|
||||
ret = 1;
|
||||
|
||||
done:
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_change_winsize_remote(unsigned int lines, unsigned int cols,
|
||||
struct timespec *delay, const char **errstr)
|
||||
{
|
||||
int ret = -1;
|
||||
debug_decl(sudoers_io_change_winsize_remote, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
if (client_closure.disabled)
|
||||
debug_return_int(1);
|
||||
|
||||
/* Track elapsed time for comparison with commit points. */
|
||||
sudo_timespecadd(delay, &client_closure.elapsed, &client_closure.elapsed);
|
||||
|
||||
if (fmt_winsize(&client_closure, lines, cols, delay)) {
|
||||
ret = client_closure.write_ev->add(client_closure.write_ev,
|
||||
&iolog_details.server_timeout);
|
||||
if (ret == -1)
|
||||
sudo_warn(U_("unable to add event to queue"));
|
||||
}
|
||||
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_change_winsize(unsigned int lines, unsigned int cols)
|
||||
{
|
||||
struct timespec now, delay;
|
||||
unsigned int len;
|
||||
char tbuf[1024];
|
||||
const char *errstr = NULL;
|
||||
int ret = -1;
|
||||
debug_decl(sudoers_io_change_winsize, SUDOERS_DEBUG_PLUGIN)
|
||||
@@ -717,23 +973,13 @@ sudoers_io_change_winsize(unsigned int lines, unsigned int cols)
|
||||
errstr = strerror(errno);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Write window change event to the timing file. */
|
||||
sudo_timespecsub(&now, &last_time, &delay);
|
||||
len = (unsigned int)snprintf(tbuf, sizeof(tbuf), "%d %lld.%09ld %u %u\n",
|
||||
IO_EVENT_WINSIZE, (long long)delay.tv_sec, delay.tv_nsec, lines, cols);
|
||||
if (len >= sizeof(tbuf)) {
|
||||
/* Not actually possible due to the size of tbuf[]. */
|
||||
errstr = strerror(EOVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
if (iolog_write(&iolog_files[IOFD_TIMING], tbuf, len, &errstr) == -1)
|
||||
goto done;
|
||||
|
||||
/* Success. */
|
||||
ret = 1;
|
||||
if (iolog_remote)
|
||||
ret = sudoers_io_change_winsize_remote(lines, cols, &delay, &errstr);
|
||||
else
|
||||
ret = sudoers_io_change_winsize_local(lines, cols, &delay, &errstr);
|
||||
|
||||
done:
|
||||
last_time.tv_sec = now.tv_sec;
|
||||
last_time.tv_nsec = now.tv_nsec;
|
||||
|
||||
@@ -754,13 +1000,61 @@ bad:
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_suspend_local(const char *signame, struct timespec *delay,
|
||||
const char **errstr)
|
||||
{
|
||||
unsigned int len;
|
||||
char tbuf[1024];
|
||||
int ret = -1;
|
||||
debug_decl(sudoers_io_suspend_local, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
/* Write suspend event to the timing file. */
|
||||
len = (unsigned int)snprintf(tbuf, sizeof(tbuf), "%d %lld.%09ld %s\n",
|
||||
IO_EVENT_SUSPEND, (long long)delay->tv_sec, delay->tv_nsec, signame);
|
||||
if (len >= sizeof(tbuf)) {
|
||||
/* Not actually possible due to the size of tbuf[]. */
|
||||
*errstr = strerror(EOVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
if (iolog_write(&iolog_files[IOFD_TIMING], tbuf, len, errstr) == -1)
|
||||
goto done;
|
||||
|
||||
/* Success. */
|
||||
ret = 1;
|
||||
|
||||
done:
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_suspend_remote(const char *signame, struct timespec *delay,
|
||||
const char **errstr)
|
||||
{
|
||||
int ret = -1;
|
||||
debug_decl(sudoers_io_suspend_remote, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
if (client_closure.disabled)
|
||||
debug_return_int(1);
|
||||
|
||||
/* Track elapsed time for comparison with commit points. */
|
||||
sudo_timespecadd(delay, &client_closure.elapsed, &client_closure.elapsed);
|
||||
|
||||
if (fmt_suspend(&client_closure, signame, delay)) {
|
||||
ret = client_closure.write_ev->add(client_closure.write_ev,
|
||||
&iolog_details.server_timeout);
|
||||
if (ret == -1)
|
||||
sudo_warn(U_("unable to add event to queue"));
|
||||
}
|
||||
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
sudoers_io_suspend(int signo)
|
||||
{
|
||||
struct timespec now, delay;
|
||||
unsigned int len;
|
||||
char signame[SIG2STR_MAX];
|
||||
char tbuf[1024];
|
||||
const char *errstr = NULL;
|
||||
int ret = -1;
|
||||
debug_decl(sudoers_io_suspend, SUDOERS_DEBUG_PLUGIN)
|
||||
@@ -777,23 +1071,14 @@ sudoers_io_suspend(int signo)
|
||||
errstr = strerror(errno);
|
||||
goto bad;
|
||||
}
|
||||
sudo_timespecsub(&now, &last_time, &delay);
|
||||
|
||||
/* Write suspend event to the timing file. */
|
||||
sudo_timespecsub(&now, &last_time, &delay);
|
||||
len = (unsigned int)snprintf(tbuf, sizeof(tbuf), "%d %lld.%09ld %s\n",
|
||||
IO_EVENT_SUSPEND, (long long)delay.tv_sec, delay.tv_nsec, signame);
|
||||
if (len >= sizeof(tbuf)) {
|
||||
/* Not actually possible due to the size of tbuf[]. */
|
||||
errstr = strerror(EOVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
if (iolog_write(&iolog_files[IOFD_TIMING], tbuf, len, &errstr) == -1)
|
||||
goto done;
|
||||
if (iolog_remote)
|
||||
ret = sudoers_io_suspend_remote(signame, &delay, &errstr);
|
||||
else
|
||||
ret = sudoers_io_suspend_local(signame, &delay, &errstr);
|
||||
|
||||
/* Success. */
|
||||
ret = 1;
|
||||
|
||||
done:
|
||||
last_time.tv_sec = now.tv_sec;
|
||||
last_time.tv_nsec = now.tv_nsec;
|
||||
|
||||
|
1159
plugins/sudoers/iolog_client.c
Normal file
1159
plugins/sudoers/iolog_client.c
Normal file
File diff suppressed because it is too large
Load Diff
115
plugins/sudoers/iolog_plugin.h
Normal file
115
plugins/sudoers/iolog_plugin.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* 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_CLIENT_H
|
||||
#define SUDOERS_IOLOG_CLIENT_H
|
||||
|
||||
#include "log_server.pb-c.h"
|
||||
#include "strlist.h"
|
||||
|
||||
#if PROTOBUF_C_VERSION_NUMBER < 1003000
|
||||
# error protobuf-c version 1.30 or higher required
|
||||
#endif
|
||||
|
||||
/* Default port to listen on */
|
||||
#define DEFAULT_PORT_STR "30344"
|
||||
|
||||
/* Maximum message size (2Mb) */
|
||||
#define MESSAGE_SIZE_MAX (2 * 1024 * 1024)
|
||||
|
||||
/* TODO - share with logsrvd/sendlog */
|
||||
struct connection_buffer {
|
||||
TAILQ_ENTRY(connection_buffer) entries;
|
||||
uint8_t *data;
|
||||
unsigned int size;
|
||||
unsigned int len;
|
||||
unsigned int off;
|
||||
};
|
||||
TAILQ_HEAD(connection_buffer_list, connection_buffer);
|
||||
|
||||
/* XXX - remove dependency on sudoers.h? */
|
||||
#undef runas_pw
|
||||
#undef runas_gr
|
||||
|
||||
struct iolog_details {
|
||||
const char *cwd;
|
||||
const char *host;
|
||||
const char *tty;
|
||||
const char *user;
|
||||
const char *command;
|
||||
const char *iolog_path;
|
||||
struct passwd *runas_pw;
|
||||
struct group *runas_gr;
|
||||
char * const *argv;
|
||||
char * const *user_env;
|
||||
struct sudoers_str_list *log_servers;
|
||||
struct timespec server_timeout;
|
||||
int argc;
|
||||
int lines;
|
||||
int cols;
|
||||
bool ignore_iolog_errors;
|
||||
};
|
||||
|
||||
enum client_state {
|
||||
ERROR,
|
||||
RECV_HELLO,
|
||||
SEND_RESTART, /* TODO: currently unimplemented */
|
||||
SEND_ACCEPT,
|
||||
SEND_IO,
|
||||
SEND_EXIT,
|
||||
CLOSING,
|
||||
FINISHED
|
||||
};
|
||||
|
||||
/* Remote connection closure, non-zero fields must come first. */
|
||||
struct client_closure {
|
||||
int sock;
|
||||
enum client_state state;
|
||||
bool disabled;
|
||||
struct connection_buffer_list write_bufs;
|
||||
struct connection_buffer_list free_bufs;
|
||||
struct connection_buffer read_buf;
|
||||
struct sudo_plugin_event *read_ev;
|
||||
struct sudo_plugin_event *write_ev;
|
||||
struct iolog_details *log_details;
|
||||
struct timespec start_time;
|
||||
struct timespec elapsed;
|
||||
struct timespec committed;
|
||||
char *iolog_id;
|
||||
};
|
||||
|
||||
#define CLIENT_CLOSURE_INITIALIZER(_c) \
|
||||
{ \
|
||||
-1, \
|
||||
ERROR, \
|
||||
false, \
|
||||
TAILQ_HEAD_INITIALIZER((_c).write_bufs), \
|
||||
TAILQ_HEAD_INITIALIZER((_c).free_bufs) \
|
||||
}
|
||||
|
||||
/* iolog_client.c */
|
||||
bool client_closure_fill(struct client_closure *closure, int sock, struct iolog_details *details, struct io_plugin *sudoers_io);
|
||||
bool client_loop(struct client_closure *closure);
|
||||
bool fmt_accept_message(struct client_closure *closure);
|
||||
bool fmt_client_message(struct client_closure *closure, ClientMessage *msg);
|
||||
bool fmt_exit_message(struct client_closure *closure, int exit_status, int error);
|
||||
bool fmt_io_buf(struct client_closure *closure, int type, const char *buf, unsigned int len, struct timespec *delay);
|
||||
bool fmt_suspend(struct client_closure *closure, const char *signame, struct timespec *delay);
|
||||
bool fmt_winsize(struct client_closure *closure, unsigned int lines, unsigned int cols, struct timespec *delay);
|
||||
int log_server_connect(struct sudoers_str_list *servers, struct timespec *timo);
|
||||
void client_closure_free(struct client_closure *closure);
|
||||
|
||||
#endif /* SUDOERS_IOLOG_CLIENT_H */
|
@@ -506,6 +506,45 @@ bad:
|
||||
debug_return_int(MODE_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert struct list_members to a comma-separated string with
|
||||
* the given variable name.
|
||||
*/
|
||||
static char *
|
||||
serialize_list(const char *varname, struct list_members *members)
|
||||
{
|
||||
struct list_member *lm, *next;
|
||||
size_t len, result_size;
|
||||
char *result;
|
||||
debug_decl(serialize_list, SUDOERS_DEBUG_PLUGIN)
|
||||
|
||||
result_size = strlen(varname) + 1;
|
||||
SLIST_FOREACH(lm, members, entries) {
|
||||
result_size += strlen(lm->value) + 1;
|
||||
}
|
||||
if ((result = malloc(result_size)) == NULL)
|
||||
goto bad;
|
||||
/* No need to check len for overflow here. */
|
||||
len = strlcpy(result, varname, result_size);
|
||||
result[len++] = '=';
|
||||
result[len] = '\0';
|
||||
SLIST_FOREACH_SAFE(lm, members, entries, next) {
|
||||
len = strlcat(result, lm->value, result_size);
|
||||
if (len + (next != NULL) >= result_size) {
|
||||
sudo_warnx(U_("internal error, %s overflow"), __func__);
|
||||
goto bad;
|
||||
}
|
||||
if (next != NULL) {
|
||||
result[len++] = ',';
|
||||
result[len] = '\0';
|
||||
}
|
||||
}
|
||||
debug_return_str(result);
|
||||
bad:
|
||||
free(result);
|
||||
debug_return_str(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the execution environment.
|
||||
* Builds up the command_info list and sets argv and envp.
|
||||
@@ -686,6 +725,15 @@ sudoers_policy_exec_setup(char *argv[], char *envp[], mode_t cmnd_umask,
|
||||
if ((command_info[info_len++] = sudo_new_key_val("iolog_group", def_iolog_group)) == NULL)
|
||||
goto oom;
|
||||
}
|
||||
if (!SLIST_EMPTY(&def_log_server)) {
|
||||
char *log_servers = serialize_list("log_servers", &def_log_server);
|
||||
if (log_servers == NULL)
|
||||
goto oom;
|
||||
command_info[info_len++] = log_servers;
|
||||
|
||||
if (asprintf(&command_info[info_len++], "log_server_timeout=%u", def_log_server_timeout) == -1)
|
||||
goto oom;
|
||||
}
|
||||
if (def_command_timeout > 0 || user_timeout > 0) {
|
||||
int timeout = user_timeout;
|
||||
if (timeout == 0 || def_command_timeout < timeout)
|
||||
|
@@ -438,6 +438,7 @@ exec_nopty(struct command_details *details, struct command_status *cstat)
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR, "event loop exited prematurely");
|
||||
/* kill command */
|
||||
terminate_command(ec.cmnd_pid, true);
|
||||
ec.cmnd_pid = -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
|
@@ -1581,7 +1581,12 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
||||
if (sudo_ev_got_break(ec.evbase)) {
|
||||
/* error from callback or monitor died */
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR, "event loop exited prematurely");
|
||||
/* XXX - may need to terminate command if cmnd_pid != -1 */
|
||||
/* kill command */
|
||||
terminate_command(ec.cmnd_pid, true);
|
||||
ec.cmnd_pid = -1;
|
||||
/* TODO: need way to pass an error to the sudo front end */
|
||||
cstat->type = CMD_WSTATUS;
|
||||
cstat->val = W_EXITCODE(1, SIGKILL);
|
||||
}
|
||||
|
||||
/* Flush any remaining output, free I/O bufs and events, do logout. */
|
||||
|
@@ -1479,6 +1479,7 @@ sudo_plugin_event_alloc(void)
|
||||
ev_int->public.fd = plugin_event_fd;
|
||||
ev_int->public.timeleft = plugin_event_timeleft;
|
||||
ev_int->public.setbase = plugin_event_setbase;
|
||||
ev_int->public.loopbreak = plugin_event_loopbreak;
|
||||
ev_int->public.free = plugin_event_free;
|
||||
|
||||
/* Clear private portion in case caller tries to use us uninitialized. */
|
||||
|
Reference in New Issue
Block a user