mirror of
https://github.com/sudo-project/sudo.git
synced 2025-08-22 09:57:41 +00:00
Refactor I/O log code so it can be shared between sudoers and logsrvd
This commit is contained in:
parent
2272430716
commit
4dacf81082
3
MANIFEST
3
MANIFEST
@ -231,8 +231,6 @@ logsrvd/Makefile.in
|
||||
logsrvd/log_server.pb-c.c
|
||||
logsrvd/log_server.pb-c.h
|
||||
logsrvd/log_server.proto
|
||||
logsrvd/iolog.h
|
||||
logsrvd/iolog_reader.c
|
||||
logsrvd/iolog_writer.c
|
||||
logsrvd/logsrvd.c
|
||||
logsrvd/logsrvd.h
|
||||
@ -330,6 +328,7 @@ 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/ldap.c
|
||||
plugins/sudoers/ldap_conf.c
|
||||
plugins/sudoers/ldap_util.c
|
||||
|
@ -24,6 +24,7 @@ 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@
|
||||
@ -48,7 +49,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$(top_srcdir) $(CPPDEFS) @CPPFLAGS@
|
||||
-I$(sudoers_srcdir) -I$(top_srcdir) $(CPPDEFS) @CPPFLAGS@
|
||||
|
||||
# Usually -O and/or -g
|
||||
CFLAGS = @CFLAGS@
|
||||
@ -109,7 +110,7 @@ PROGS = logsrvd sendlog
|
||||
|
||||
LOGSRVD_OBJS = iolog_writer.o logsrvd.o log_server.pb-c.o
|
||||
|
||||
SENDLOG_OBJS = sendlog.o iolog_reader.o log_server.pb-c.o
|
||||
SENDLOG_OBJS = sendlog.o iolog_util.o log_server.pb-c.o
|
||||
|
||||
IOBJS = $(LOGSRVD_OBJS:.o=.i) $(SENDLOG_OBJS:.o=.i)
|
||||
|
||||
@ -209,31 +210,35 @@ realclean: distclean
|
||||
cleandir: realclean
|
||||
|
||||
# Autogenerated dependencies, do not modify
|
||||
iolog_reader.o: $(srcdir)/iolog_reader.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)/iolog.h \
|
||||
$(srcdir)/sendlog.h $(top_builddir)/config.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/iolog_reader.c
|
||||
iolog_reader.i: $(srcdir)/iolog_reader.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)/iolog.h \
|
||||
$(srcdir)/sendlog.h $(top_builddir)/config.h
|
||||
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_reader.plog: iolog_reader.i
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog_reader.c --i-file $< --output-file $@
|
||||
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)/iolog.h \
|
||||
$(srcdir)/logsrvd.h $(top_builddir)/config.h
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/logsrvd.h $(sudoers_srcdir)/iolog.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)/iolog.h \
|
||||
$(srcdir)/logsrvd.h $(top_builddir)/config.h
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/logsrvd.h $(sudoers_srcdir)/iolog.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 $@
|
||||
@ -264,16 +269,18 @@ 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 $(srcdir)/iolog.h \
|
||||
$(srcdir)/sendlog.h $(top_builddir)/config.h
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.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 \
|
||||
$(incdir)/compat/getaddrinfo.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_util.h $(srcdir)/iolog.h \
|
||||
$(srcdir)/sendlog.h $(top_builddir)/config.h
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.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
|
||||
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/sendlog.c --i-file $< --output-file $@
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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 LOGSRVD_IOLOG_H
|
||||
#define LOGSRVD_IOLOG_H
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
/*
|
||||
* Contents of the sudo I/O info log
|
||||
*/
|
||||
struct log_info {
|
||||
char *command;
|
||||
char *cwd;
|
||||
char *iolog_dir;
|
||||
char *rungroup;
|
||||
char *runuser;
|
||||
char *submithost;
|
||||
char *submituser;
|
||||
char *ttyname;
|
||||
char **argv;
|
||||
time_t start_time;
|
||||
int argc;
|
||||
int lines;
|
||||
int columns;
|
||||
};
|
||||
|
||||
#endif /* LOGSRVD_IOLOG_H */
|
@ -1,452 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log_server.pb-c.h"
|
||||
#include "sudo_compat.h"
|
||||
#include "sudo_debug.h"
|
||||
#include "sudo_util.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "iolog.h"
|
||||
#include "sendlog.h"
|
||||
|
||||
static int timing_event_adj;
|
||||
static gzFile io_fds[IOFD_MAX];
|
||||
|
||||
/* I/O log file names relative to 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 */
|
||||
};
|
||||
|
||||
void
|
||||
free_log_info(struct log_info *li)
|
||||
{
|
||||
if (li != NULL) {
|
||||
free(li->cwd);
|
||||
free(li->submituser);
|
||||
free(li->runuser);
|
||||
free(li->rungroup);
|
||||
free(li->ttyname);
|
||||
free(li->command);
|
||||
free(li);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Open any I/O log files that are present.
|
||||
* The timing file must always exist.
|
||||
*/
|
||||
bool
|
||||
iolog_open(const char *iolog_path)
|
||||
{
|
||||
char fname[PATH_MAX];
|
||||
int i, len;
|
||||
debug_decl(iolog_open, 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]);
|
||||
}
|
||||
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]);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
struct log_info *
|
||||
parse_logfile(const char *logfile)
|
||||
{
|
||||
FILE *fp;
|
||||
char *buf = NULL, *cp, *ep;
|
||||
size_t bufsize = 0, cwdsize = 0, cmdsize = 0;
|
||||
long long llval;
|
||||
struct log_info *li = NULL;
|
||||
debug_decl(parse_logfile, SUDO_DEBUG_UTIL)
|
||||
|
||||
fp = fopen(logfile, "r");
|
||||
if (fp == NULL) {
|
||||
sudo_warn("unable to open %s", logfile);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* ID file has three lines:
|
||||
* 1) a log info line
|
||||
* 2) cwd
|
||||
* 3) command with args
|
||||
*/
|
||||
if ((li = calloc(1, sizeof(*li))) == NULL)
|
||||
sudo_fatalx("%s: %s", __func__, "unable to allocate memory");
|
||||
if (getdelim(&buf, &bufsize, '\n', fp) == -1 ||
|
||||
getdelim(&li->cwd, &cwdsize, '\n', fp) == -1 ||
|
||||
getdelim(&li->command, &cmdsize, '\n', fp) == -1) {
|
||||
sudo_warn("%s: invalid log file", logfile);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Strip the newline from the cwd and command. */
|
||||
li->cwd[strcspn(li->cwd, "\n")] = '\0';
|
||||
li->command[strcspn(li->command, "\n")] = '\0';
|
||||
|
||||
/*
|
||||
* Crack the log line (lines and columns not present in old versions).
|
||||
* timestamp:submituser:runuser:rungroup:ttyname:lines:columns
|
||||
* XXX - probably better to use strtok and switch on the state.
|
||||
*/
|
||||
buf[strcspn(buf, "\n")] = '\0';
|
||||
cp = buf;
|
||||
|
||||
/* timestamp */
|
||||
errno = 0;
|
||||
llval = strtoll(cp, &ep, 10);
|
||||
if (cp == ep || *ep != ':') {
|
||||
sudo_warn("%s: time stamp field is missing", logfile);
|
||||
goto bad;
|
||||
}
|
||||
if (errno == ERANGE && (llval == LLONG_MAX || llval == LLONG_MIN)) {
|
||||
sudo_warn("%s: time stamp %s: out of range", logfile, cp);
|
||||
goto bad;
|
||||
}
|
||||
li->start_time = llval;
|
||||
|
||||
/* submituser */
|
||||
cp = ep + 1;
|
||||
if ((ep = strchr(cp, ':')) == NULL) {
|
||||
sudo_warn("%s: submituser field is missing", logfile);
|
||||
goto bad;
|
||||
}
|
||||
if ((li->submituser = strndup(cp, (size_t)(ep - cp))) == NULL)
|
||||
sudo_fatalx("%s: %s", __func__, "unable to allocate memory");
|
||||
|
||||
/* runuser */
|
||||
cp = ep + 1;
|
||||
if ((ep = strchr(cp, ':')) == NULL) {
|
||||
sudo_warn("%s: runuser field is missing", logfile);
|
||||
goto bad;
|
||||
}
|
||||
if ((li->runuser = strndup(cp, (size_t)(ep - cp))) == NULL)
|
||||
sudo_fatalx("%s: %s", __func__, "unable to allocate memory");
|
||||
|
||||
/* rungroup */
|
||||
cp = ep + 1;
|
||||
if ((ep = strchr(cp, ':')) == NULL) {
|
||||
sudo_warn("%s: rungroup field is missing", logfile);
|
||||
goto bad;
|
||||
}
|
||||
if (cp != ep) {
|
||||
if ((li->rungroup = strndup(cp, (size_t)(ep - cp))) == NULL)
|
||||
sudo_fatalx("%s: %s", __func__, "unable to allocate memory");
|
||||
}
|
||||
|
||||
/* ttyname, followed by optional lines + columns */
|
||||
cp = ep + 1;
|
||||
if ((ep = strchr(cp, ':')) == NULL) {
|
||||
/* just the ttyname */
|
||||
if ((li->ttyname = strdup(cp)) == NULL)
|
||||
sudo_fatalx("%s: %s", __func__, "unable to allocate memory");
|
||||
} else {
|
||||
/* ttyname followed by lines + columns */
|
||||
unsigned long ulval;
|
||||
|
||||
if ((li->ttyname = strndup(cp, (size_t)(ep - cp))) == NULL)
|
||||
sudo_fatalx("%s: %s", __func__, "unable to allocate memory");
|
||||
|
||||
/* lines */
|
||||
cp = ep + 1;
|
||||
errno = 0;
|
||||
ulval = strtoul(cp, &ep, 10);
|
||||
if (cp == ep || *ep != ':') {
|
||||
sudo_warn("%s: terminal lines field is missing", logfile);
|
||||
goto bad;
|
||||
}
|
||||
if ((errno == ERANGE && ulval == ULONG_MAX) || ulval > INT_MAX) {
|
||||
sudo_warn("%s: terminal lines %s: out of range", logfile, cp);
|
||||
goto bad;
|
||||
}
|
||||
li->lines = (int)ulval;
|
||||
|
||||
/* columns */
|
||||
cp = ep + 1;
|
||||
errno = 0;
|
||||
ulval = strtoul(cp, &ep, 10);
|
||||
if (cp == ep || (*ep != ':' && *ep != '\0')) {
|
||||
sudo_warn("%s: terminal columns field is missing", logfile);
|
||||
goto bad;
|
||||
}
|
||||
if ((errno == ERANGE && ulval == ULONG_MAX) || ulval > INT_MAX) {
|
||||
sudo_warn("%s: terminal columns %s: out of range", logfile, cp);
|
||||
goto bad;
|
||||
}
|
||||
li->columns = (int)ulval;
|
||||
}
|
||||
fclose(fp);
|
||||
free(buf);
|
||||
debug_return_ptr(li);
|
||||
|
||||
bad:
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
free(buf);
|
||||
free_log_info(li);
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the delay as seconds and nanoseconds: %lld.%09ld
|
||||
* Sudo used to write this as a double, but since timing data is logged
|
||||
* in the C locale this may not match the current locale.
|
||||
*/
|
||||
static char *
|
||||
parse_delay(const char *cp, struct timespec *delay)
|
||||
{
|
||||
long long llval;
|
||||
size_t len;
|
||||
char *ep;
|
||||
debug_decl(parse_delay, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Parse seconds (whole number portion). */
|
||||
errno = 0;
|
||||
llval = strtoll(cp, &ep, 10);
|
||||
/* Radix may be in user's locale for sudo < 1.7.4 so accept that too. */
|
||||
if (cp == ep || *ep != '.') {
|
||||
sudo_warnx("invalid characters after seconds: %s", ep);
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
if (errno == ERANGE && (llval == LLONG_MAX || llval == LLONG_MIN)) {
|
||||
sudo_warnx("%s: number of seconds out of range", cp);
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
delay->tv_sec = (time_t)llval;
|
||||
cp = ep + 1;
|
||||
|
||||
/* Parse fractional part, we may read more precision than we can store. */
|
||||
errno = 0;
|
||||
llval = strtoll(cp, &ep, 10);
|
||||
if (cp == ep || (*ep != ' ' && *ep != '\0')) {
|
||||
sudo_warnx("invalid characters after nanoseconds: %s", ep);
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
if (errno == ERANGE && (llval == LLONG_MAX || llval == LLONG_MIN)) {
|
||||
sudo_warnx("%s: number of nanoseconds out of range", cp);
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
/* Adjust fractional part to nanosecond precision. */
|
||||
len = (size_t)(ep - cp);
|
||||
if (len < 9) {
|
||||
/* Convert to nanosecond precision. */
|
||||
do {
|
||||
llval *= 10;
|
||||
} while (++len < 9);
|
||||
} else if (len > 9) {
|
||||
/* Clamp to nanoseconds. */
|
||||
do {
|
||||
llval /= 10;
|
||||
} while (--len > 9);
|
||||
}
|
||||
delay->tv_nsec = (long)llval;
|
||||
|
||||
/* Advance to the next field. */
|
||||
while (isspace((unsigned char)*ep))
|
||||
ep++;
|
||||
|
||||
debug_return_str((char *)ep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a timing line, which is formatted as:
|
||||
* IO_EVENT_TTYOUT sleep_time num_bytes
|
||||
* IO_EVENT_WINSIZE sleep_time lines columns
|
||||
* IO_EVENT_SUSPEND sleep_time signal
|
||||
* Where type is IO_EVENT_*, sleep_time is the number of seconds to sleep
|
||||
* before writing the data and num_bytes is the number of bytes to output.
|
||||
* Returns true on success and false on failure.
|
||||
*/
|
||||
static bool
|
||||
parse_timing(const char *buf, struct timing_closure *timing)
|
||||
{
|
||||
unsigned long ulval;
|
||||
char *cp, *ep;
|
||||
debug_decl(parse_timing, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Parse event type. */
|
||||
ulval = strtoul(buf, &ep, 10);
|
||||
if (ep == buf || !isspace((unsigned char) *ep))
|
||||
goto bad;
|
||||
if (ulval >= IO_EVENT_COUNT)
|
||||
goto bad;
|
||||
if (ulval == IO_EVENT_TTYOUT_1_8_7) {
|
||||
/* work around a bug in timing files generated by sudo 1.8.7 */
|
||||
timing_event_adj = 2;
|
||||
}
|
||||
timing->event = (int)ulval - timing_event_adj;
|
||||
for (cp = ep + 1; isspace((unsigned char) *cp); cp++)
|
||||
continue;
|
||||
|
||||
/* Parse delay, returns the next field or NULL on error. */
|
||||
if ((cp = parse_delay(cp, &timing->delay)) == NULL)
|
||||
goto bad;
|
||||
|
||||
switch (timing->event) {
|
||||
case IO_EVENT_SUSPEND:
|
||||
/* Signal name (no leading SIG prefix) or number. */
|
||||
if (isdigit((unsigned char)*cp)) {
|
||||
/* Signal number, convert to name. */
|
||||
ulval = strtoul(cp, &ep, 10);
|
||||
if (ep == cp || *ep != '\0')
|
||||
goto bad;
|
||||
if (ulval > INT_MAX)
|
||||
goto bad;
|
||||
if (sig2str(ulval, timing->buf) == -1)
|
||||
goto bad;
|
||||
} else {
|
||||
/* Signal name. */
|
||||
if (strlcpy(timing->buf, cp, timing->bufsize) >= timing->bufsize)
|
||||
goto bad;
|
||||
}
|
||||
break;
|
||||
case IO_EVENT_WINSIZE:
|
||||
ulval = strtoul(cp, &ep, 10);
|
||||
if (ep == cp || !isspace((unsigned char) *ep))
|
||||
goto bad;
|
||||
if (ulval > INT_MAX)
|
||||
goto bad;
|
||||
timing->u.winsize.lines = (int)ulval;
|
||||
for (cp = ep + 1; isspace((unsigned char) *cp); cp++)
|
||||
continue;
|
||||
|
||||
ulval = strtoul(cp, &ep, 10);
|
||||
if (ep == cp || *ep != '\0')
|
||||
goto bad;
|
||||
if (ulval > INT_MAX)
|
||||
goto bad;
|
||||
timing->u.winsize.columns = (int)ulval;
|
||||
break;
|
||||
default:
|
||||
errno = 0;
|
||||
ulval = strtoul(cp, &ep, 10);
|
||||
if (ep == cp || *ep != '\0')
|
||||
goto bad;
|
||||
/* Note: assumes SIZE_MAX == ULONG_MAX */
|
||||
if (errno == ERANGE && ulval == ULONG_MAX)
|
||||
goto bad;
|
||||
timing->u.nbytes = (size_t)ulval;
|
||||
break;
|
||||
}
|
||||
|
||||
debug_return_bool(true);
|
||||
bad:
|
||||
debug_return_bool(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the next record from the timing file.
|
||||
* Return 0 on success, 1 on EOF and -1 on error.
|
||||
*/
|
||||
int
|
||||
read_timing_record(struct timing_closure *timing)
|
||||
{
|
||||
const char *errstr;
|
||||
char line[LINE_MAX];
|
||||
int errnum;
|
||||
debug_decl(read_timing_record, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Read next record from timing file. */
|
||||
if (gzgets(io_fds[IOFD_TIMING], line, sizeof(line)) == 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);
|
||||
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);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
debug_return_int(0);
|
||||
}
|
||||
|
||||
bool
|
||||
read_io_buf(struct timing_closure *timing)
|
||||
{
|
||||
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]);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
|
||||
/* Expand buf as needed. */
|
||||
if (timing->u.nbytes > timing->bufsize) {
|
||||
free(timing->buf);
|
||||
do {
|
||||
timing->bufsize *= 2;
|
||||
} while (timing->u.nbytes > timing->bufsize);
|
||||
if ((timing->buf = malloc(timing->bufsize)) == NULL) {
|
||||
sudo_warn("malloc %zu", timing->bufsize);
|
||||
timing->u.nbytes = 0;
|
||||
debug_return_bool(false);
|
||||
}
|
||||
}
|
||||
|
||||
nread = gzread(io_fds[timing->event], timing->buf, timing->u.nbytes);
|
||||
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);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
@ -75,24 +75,24 @@ has_strlistval(InfoMessage *info)
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in log info from an ExecMessage
|
||||
* Fill in I/O log details from an ExecMessage
|
||||
* Only makes a shallow copy of strings and string lists.
|
||||
*/
|
||||
static bool
|
||||
log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
iolog_details_fill(struct iolog_details *details, ExecMessage *msg)
|
||||
{
|
||||
size_t idx;
|
||||
bool ret = true;
|
||||
debug_decl(log_info_fill, SUDO_DEBUG_UTIL)
|
||||
debug_decl(iolog_details_fill, SUDO_DEBUG_UTIL)
|
||||
|
||||
memset(log_info, 0, sizeof(*log_info));
|
||||
memset(details, 0, sizeof(*details));
|
||||
|
||||
/* Start time. */
|
||||
log_info->start_time = msg->start_time->tv_sec;
|
||||
details->start_time = msg->start_time->tv_sec;
|
||||
|
||||
/* Default values */
|
||||
log_info->lines = 24;
|
||||
log_info->columns = 80;
|
||||
details->lines = 24;
|
||||
details->columns = 80;
|
||||
|
||||
/* Pull out values by key from info array. */
|
||||
for (idx = 0; idx < msg->n_info_msgs; idx++) {
|
||||
@ -106,13 +106,13 @@ log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
} else if (info->numval <= 0 || info->numval > INT_MAX) {
|
||||
sudo_warnx("columns (%" PRId64 ") out of range", info->numval);
|
||||
} else {
|
||||
log_info->columns = info->numval;
|
||||
details->columns = info->numval;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp(key, "command") == 0) {
|
||||
if (has_strval(info)) {
|
||||
log_info->command = info->strval;
|
||||
details->command = info->strval;
|
||||
} else {
|
||||
sudo_warnx("command specified but not a string");
|
||||
}
|
||||
@ -120,7 +120,7 @@ log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
}
|
||||
if (strcmp(key, "cwd") == 0) {
|
||||
if (has_strval(info)) {
|
||||
log_info->cwd = info->strval;
|
||||
details->cwd = info->strval;
|
||||
} else {
|
||||
sudo_warnx("cwd specified but not a string");
|
||||
}
|
||||
@ -134,7 +134,7 @@ log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
} else if (info->numval <= 0 || info->numval > INT_MAX) {
|
||||
sudo_warnx("lines (%" PRId64 ") out of range", info->numval);
|
||||
} else {
|
||||
log_info->lines = info->numval;
|
||||
details->lines = info->numval;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -142,8 +142,8 @@ log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
case 'r':
|
||||
if (strcmp(key, "runargv") == 0) {
|
||||
if (has_strlistval(info)) {
|
||||
log_info->argv = info->strlistval->strings;
|
||||
log_info->argc = info->strlistval->n_strings;
|
||||
details->argv = info->strlistval->strings;
|
||||
details->argc = info->strlistval->n_strings;
|
||||
} else {
|
||||
sudo_warnx("runargv specified but not a string list");
|
||||
}
|
||||
@ -151,7 +151,7 @@ log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
}
|
||||
if (strcmp(key, "rungroup") == 0) {
|
||||
if (has_strval(info)) {
|
||||
log_info->rungroup = info->strval;
|
||||
details->rungroup = info->strval;
|
||||
} else {
|
||||
sudo_warnx("rungroup specified but not a string");
|
||||
}
|
||||
@ -159,7 +159,7 @@ log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
}
|
||||
if (strcmp(key, "runuser") == 0) {
|
||||
if (has_strval(info)) {
|
||||
log_info->runuser = info->strval;
|
||||
details->runuser = info->strval;
|
||||
} else {
|
||||
sudo_warnx("runuser specified but not a string");
|
||||
}
|
||||
@ -169,7 +169,7 @@ log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
case 's':
|
||||
if (strcmp(key, "submithost") == 0) {
|
||||
if (has_strval(info)) {
|
||||
log_info->submithost = info->strval;
|
||||
details->submithost = info->strval;
|
||||
} else {
|
||||
sudo_warnx("submithost specified but not a string");
|
||||
}
|
||||
@ -177,7 +177,7 @@ log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
}
|
||||
if (strcmp(key, "submituser") == 0) {
|
||||
if (has_strval(info)) {
|
||||
log_info->submituser = info->strval;
|
||||
details->submituser = info->strval;
|
||||
} else {
|
||||
sudo_warnx("submituser specified but not a string");
|
||||
}
|
||||
@ -187,7 +187,7 @@ log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
case 't':
|
||||
if (strcmp(key, "ttyname") == 0) {
|
||||
if (has_strval(info)) {
|
||||
log_info->ttyname = info->strval;
|
||||
details->ttyname = info->strval;
|
||||
} else {
|
||||
sudo_warnx("ttyname specified but not a string");
|
||||
}
|
||||
@ -198,15 +198,15 @@ log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
}
|
||||
|
||||
/* Check for required settings */
|
||||
if (log_info->submituser == NULL) {
|
||||
if (details->submituser == NULL) {
|
||||
sudo_warnx("missing user in ExecMessage");
|
||||
ret = false;
|
||||
}
|
||||
if (log_info->submithost == NULL) {
|
||||
if (details->submithost == NULL) {
|
||||
sudo_warnx("missing host in ExecMessage");
|
||||
ret = false;
|
||||
}
|
||||
if (log_info->command == NULL) {
|
||||
if (details->command == NULL) {
|
||||
sudo_warnx("missing command in ExecMessage");
|
||||
ret = false;
|
||||
}
|
||||
@ -219,7 +219,7 @@ log_info_fill(struct log_info *log_info, ExecMessage *msg)
|
||||
* Set iolog_dir and iolog_dir_fd in the closure
|
||||
*/
|
||||
static bool
|
||||
create_iolog_dir(struct log_info *log_info, struct connection_closure *closure)
|
||||
create_iolog_dir(struct iolog_details *details, struct connection_closure *closure)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int len;
|
||||
@ -231,7 +231,7 @@ create_iolog_dir(struct log_info *log_info, struct connection_closure *closure)
|
||||
goto bad;
|
||||
}
|
||||
len = snprintf(path, sizeof(path), "%s/%s", IOLOG_DIR,
|
||||
log_info->submithost);
|
||||
details->submithost);
|
||||
if (len < 0 || len >= ssizeof(path)) {
|
||||
sudo_warn("snprintf");
|
||||
goto bad;
|
||||
@ -241,7 +241,7 @@ create_iolog_dir(struct log_info *log_info, struct connection_closure *closure)
|
||||
goto bad;
|
||||
}
|
||||
len = snprintf(path, sizeof(path), "%s/%s/%s", IOLOG_DIR,
|
||||
log_info->submithost, log_info->submituser);
|
||||
details->submithost, details->submituser);
|
||||
if (len < 0 || len >= ssizeof(path)) {
|
||||
sudo_warn("snprintf");
|
||||
goto bad;
|
||||
@ -251,7 +251,7 @@ create_iolog_dir(struct log_info *log_info, struct connection_closure *closure)
|
||||
goto bad;
|
||||
}
|
||||
len = snprintf(path, sizeof(path), "%s/%s/%s/XXXXXX", IOLOG_DIR,
|
||||
log_info->submithost, log_info->submituser);
|
||||
details->submithost, details->submituser);
|
||||
if (len < 0 || len >= ssizeof(path)) {
|
||||
sudo_warn("snprintf");
|
||||
goto bad;
|
||||
@ -264,7 +264,7 @@ create_iolog_dir(struct log_info *log_info, struct connection_closure *closure)
|
||||
|
||||
/* Make a copy of iolog_dir for error messages. */
|
||||
if ((closure->iolog_dir = strdup(path)) == NULL) {
|
||||
sudo_warn("strdup");
|
||||
sudo_warn(NULL);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
@ -285,12 +285,12 @@ bad:
|
||||
* Write the sudo-style I/O log info file containing user and command info.
|
||||
*/
|
||||
static bool
|
||||
log_info_write(struct log_info *log_info, struct connection_closure *closure)
|
||||
iolog_details_write(struct iolog_details *details, struct connection_closure *closure)
|
||||
{
|
||||
int fd, i;
|
||||
FILE *fp;
|
||||
int error;
|
||||
debug_decl(log_info_write, SUDO_DEBUG_UTIL)
|
||||
debug_decl(iolog_details_write, SUDO_DEBUG_UTIL)
|
||||
|
||||
fd = openat(closure->iolog_dir_fd, "log", O_CREAT|O_EXCL|O_WRONLY, 0600);
|
||||
if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) {
|
||||
@ -301,16 +301,16 @@ log_info_write(struct log_info *log_info, struct connection_closure *closure)
|
||||
}
|
||||
|
||||
fprintf(fp, "%lld:%s:%s:%s:%s:%d:%d\n%s\n",
|
||||
(long long)log_info->start_time, log_info->submituser,
|
||||
log_info->runuser ? log_info->runuser : RUNAS_DEFAULT,
|
||||
log_info->rungroup ? log_info->rungroup : "",
|
||||
log_info->ttyname ? log_info->ttyname : "unknown",
|
||||
log_info->lines, log_info->columns,
|
||||
log_info->cwd ? log_info->cwd : "unknown");
|
||||
fputs(log_info->command, fp);
|
||||
for (i = 1; i < log_info->argc; i++) {
|
||||
(long long)details->start_time, details->submituser,
|
||||
details->runuser ? details->runuser : RUNAS_DEFAULT,
|
||||
details->rungroup ? details->rungroup : "",
|
||||
details->ttyname ? details->ttyname : "unknown",
|
||||
details->lines, details->columns,
|
||||
details->cwd ? details->cwd : "unknown");
|
||||
fputs(details->command, fp);
|
||||
for (i = 1; i < details->argc; i++) {
|
||||
fputc(' ', fp);
|
||||
fputs(log_info->argv[i], fp);
|
||||
fputs(details->argv[i], fp);
|
||||
}
|
||||
fputc('\n', fp);
|
||||
fflush(fp);
|
||||
@ -356,7 +356,7 @@ iolog_close(struct connection_closure *closure)
|
||||
bool
|
||||
iolog_init(ExecMessage *msg, struct connection_closure *closure)
|
||||
{
|
||||
struct log_info log_info;
|
||||
struct iolog_details details;
|
||||
int i;
|
||||
debug_decl(iolog_init, SUDO_DEBUG_UTIL)
|
||||
|
||||
@ -364,16 +364,16 @@ iolog_init(ExecMessage *msg, struct connection_closure *closure)
|
||||
for (i = 0; i < IOFD_MAX; i++)
|
||||
closure->io_fds[i] = -1;
|
||||
|
||||
/* Fill in log_info */
|
||||
if (!log_info_fill(&log_info, msg))
|
||||
/* Fill in iolog_details */
|
||||
if (!iolog_details_fill(&details, msg))
|
||||
debug_return_bool(false);
|
||||
|
||||
/* Create I/O log dir */
|
||||
if (!create_iolog_dir(&log_info, closure))
|
||||
if (!create_iolog_dir(&details, closure))
|
||||
debug_return_bool(false);
|
||||
|
||||
/* Write sudo I/O log info file */
|
||||
if (!log_info_write(&log_info, closure))
|
||||
if (!iolog_details_write(&details, closure))
|
||||
debug_return_bool(false);
|
||||
|
||||
/* Create timing, stdout, stderr and ttyout files for sudoreplay. */
|
||||
|
@ -40,6 +40,25 @@
|
||||
#define IOFD_TIMING 5
|
||||
#define IOFD_MAX 6
|
||||
|
||||
/*
|
||||
* I/O log details from the ExecMessage
|
||||
*/
|
||||
struct iolog_details {
|
||||
char *command;
|
||||
char *cwd;
|
||||
char *iolog_dir;
|
||||
char *rungroup;
|
||||
char *runuser;
|
||||
char *submithost;
|
||||
char *submituser;
|
||||
char *ttyname;
|
||||
char **argv;
|
||||
time_t start_time;
|
||||
int argc;
|
||||
int lines;
|
||||
int columns;
|
||||
};
|
||||
|
||||
/*
|
||||
* Connection status.
|
||||
* In the RUNNING state we expect I/O log buffers.
|
||||
|
@ -54,9 +54,23 @@
|
||||
#include "sudo_util.h"
|
||||
#include "sudo_event.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "iolog.h"
|
||||
#include "iolog_util.h"
|
||||
#include "sendlog.h"
|
||||
|
||||
static gzFile io_fds[IOFD_MAX];
|
||||
|
||||
/* I/O log file names relative to 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 void
|
||||
usage(void)
|
||||
{
|
||||
@ -135,13 +149,87 @@ client_closure_free(struct client_closure *closure)
|
||||
sudo_ev_free(closure->write_ev);
|
||||
free(closure->read_buf.data);
|
||||
free(closure->write_buf.data);
|
||||
free(closure->timing.buf);
|
||||
free(closure->buf);
|
||||
free(closure);
|
||||
}
|
||||
|
||||
debug_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the next record from the timing file.
|
||||
* Return 0 on success, 1 on EOF and -1 on error.
|
||||
*/
|
||||
int
|
||||
read_timing_record(struct timing_closure *timing)
|
||||
{
|
||||
const char *errstr;
|
||||
char line[LINE_MAX];
|
||||
int errnum;
|
||||
debug_decl(read_timing_record, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Read next record from timing file. */
|
||||
if (gzgets(io_fds[IOFD_TIMING], line, sizeof(line)) == 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);
|
||||
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);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
debug_return_int(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the next I/O buffer as described by closure->timing.
|
||||
*/
|
||||
static bool
|
||||
read_io_buf(struct client_closure *closure)
|
||||
{
|
||||
struct timing_closure *timing = &closure->timing;
|
||||
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]);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
|
||||
/* Expand buf as needed. */
|
||||
if (timing->u.nbytes > closure->bufsize) {
|
||||
free(closure->buf);
|
||||
do {
|
||||
closure->bufsize *= 2;
|
||||
} while (timing->u.nbytes > closure->bufsize);
|
||||
if ((closure->buf = malloc(closure->bufsize)) == NULL) {
|
||||
sudo_warn("malloc %zu", closure->bufsize);
|
||||
timing->u.nbytes = 0;
|
||||
debug_return_bool(false);
|
||||
}
|
||||
}
|
||||
|
||||
nread = gzread(io_fds[timing->event], closure->buf, timing->u.nbytes);
|
||||
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);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Format a ClientMessage and store the wire format message in buf.
|
||||
* Returns true on success, false on failure.
|
||||
@ -177,6 +265,40 @@ done:
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Split command + args into an array of strings.
|
||||
* Returns an array containing command and args, reusing space in "command".
|
||||
* Note that the returned array does not end with a terminating NULL.
|
||||
*/
|
||||
static char **
|
||||
split_command(char *command, size_t *lenp)
|
||||
{
|
||||
char *cp;
|
||||
char **args;
|
||||
size_t len;
|
||||
debug_decl(split_command, SUDO_DEBUG_UTIL)
|
||||
|
||||
for (cp = command, len = 0;;) {
|
||||
len++;
|
||||
if ((cp = strchr(cp, ' ')) == NULL)
|
||||
break;
|
||||
cp++;
|
||||
}
|
||||
args = reallocarray(NULL, len, sizeof(char *));
|
||||
if (args == NULL)
|
||||
debug_return_ptr(NULL);
|
||||
|
||||
for (cp = command, len = 0;;) {
|
||||
args[len++] = cp;
|
||||
if ((cp = strchr(cp, ' ')) == NULL)
|
||||
break;
|
||||
*cp++ = '\0';
|
||||
}
|
||||
|
||||
*lenp = len;
|
||||
debug_return_ptr(args);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build and format an ExecMessage wrapped in a ClientMessage.
|
||||
* Stores the wire format message in the closure's write buffer.
|
||||
@ -189,7 +311,7 @@ fmt_exec_message(struct client_closure *closure)
|
||||
ExecMessage exec_msg = EXEC_MESSAGE__INIT;
|
||||
TimeSpec tv = TIME_SPEC__INIT;
|
||||
InfoMessage__StringList runargv = INFO_MESSAGE__STRING_LIST__INIT;
|
||||
struct log_info *log_info = closure->log_info;
|
||||
struct iolog_info *log_info = closure->log_info;
|
||||
char hostname[1024];
|
||||
bool ret = false;
|
||||
size_t n;
|
||||
@ -205,15 +327,16 @@ fmt_exec_message(struct client_closure *closure)
|
||||
}
|
||||
hostname[sizeof(hostname) - 1] = '\0';
|
||||
|
||||
/* Format argv/argc as a StringList */
|
||||
runargv.strings = log_info->argv;
|
||||
runargv.n_strings = log_info->argc;
|
||||
|
||||
/* Sudo I/O logs only store start time in seconds. */
|
||||
tv.tv_sec = log_info->start_time;
|
||||
tv.tv_sec = log_info->tstamp;
|
||||
tv.tv_nsec = 0;
|
||||
exec_msg.start_time = &tv;
|
||||
|
||||
/* Split command into a StringList. */
|
||||
runargv.strings = split_command(log_info->cmd, &runargv.n_strings);
|
||||
if (runargv.strings == NULL)
|
||||
sudo_fatal(NULL);
|
||||
|
||||
/* The sudo I/O log info file has limited info. */
|
||||
exec_msg.n_info_msgs = 10;
|
||||
exec_msg.info_msgs = calloc(exec_msg.n_info_msgs, sizeof(InfoMessage *));
|
||||
@ -231,55 +354,56 @@ fmt_exec_message(struct client_closure *closure)
|
||||
/* Fill in info_msgs */
|
||||
n = 0;
|
||||
exec_msg.info_msgs[n]->key = "command";
|
||||
exec_msg.info_msgs[n]->strval = log_info->command;
|
||||
exec_msg.info_msgs[n]->strval = log_info->cmd;
|
||||
exec_msg.info_msgs[n]->value_case = INFO_MESSAGE__VALUE_STRVAL;
|
||||
|
||||
n++;
|
||||
|
||||
exec_msg.info_msgs[n]->key = "columns";
|
||||
exec_msg.info_msgs[n]->numval = log_info->columns;
|
||||
exec_msg.info_msgs[n]->numval = log_info->cols;
|
||||
exec_msg.info_msgs[n]->value_case = INFO_MESSAGE__VALUE_NUMVAL;
|
||||
|
||||
n++;
|
||||
|
||||
exec_msg.info_msgs[n]->key = "cwd";
|
||||
exec_msg.info_msgs[n]->strval = log_info->cwd;
|
||||
exec_msg.info_msgs[n]->value_case = INFO_MESSAGE__VALUE_STRVAL;
|
||||
|
||||
n++;
|
||||
|
||||
exec_msg.info_msgs[n]->key = "lines";
|
||||
exec_msg.info_msgs[n]->numval = log_info->lines;
|
||||
exec_msg.info_msgs[n]->value_case = INFO_MESSAGE__VALUE_NUMVAL;
|
||||
|
||||
n++;
|
||||
|
||||
exec_msg.info_msgs[n]->key = "runargv";
|
||||
exec_msg.info_msgs[n]->strlistval = &runargv;
|
||||
exec_msg.info_msgs[n]->value_case = INFO_MESSAGE__VALUE_STRLISTVAL;
|
||||
|
||||
if (log_info->rungroup != NULL) {
|
||||
n++;
|
||||
|
||||
if (log_info->runas_group != NULL) {
|
||||
exec_msg.info_msgs[n]->key = "rungroup";
|
||||
exec_msg.info_msgs[n]->strval = log_info->rungroup;
|
||||
exec_msg.info_msgs[n]->strval = log_info->runas_group;
|
||||
exec_msg.info_msgs[n]->value_case = INFO_MESSAGE__VALUE_STRVAL;
|
||||
n++;
|
||||
}
|
||||
|
||||
n++;
|
||||
exec_msg.info_msgs[n]->key = "runuser";
|
||||
exec_msg.info_msgs[n]->strval = log_info->runuser;
|
||||
exec_msg.info_msgs[n]->strval = log_info->runas_user;
|
||||
exec_msg.info_msgs[n]->value_case = INFO_MESSAGE__VALUE_STRVAL;
|
||||
|
||||
n++;
|
||||
|
||||
exec_msg.info_msgs[n]->key = "submithost";
|
||||
exec_msg.info_msgs[n]->strval = hostname;
|
||||
exec_msg.info_msgs[n]->value_case = INFO_MESSAGE__VALUE_STRVAL;
|
||||
|
||||
n++;
|
||||
|
||||
exec_msg.info_msgs[n]->key = "submituser";
|
||||
exec_msg.info_msgs[n]->strval = log_info->submituser;
|
||||
exec_msg.info_msgs[n]->strval = log_info->user;
|
||||
exec_msg.info_msgs[n]->value_case = INFO_MESSAGE__VALUE_STRVAL;
|
||||
|
||||
n++;
|
||||
|
||||
exec_msg.info_msgs[n]->key = "ttyname";
|
||||
exec_msg.info_msgs[n]->strval = log_info->ttyname;
|
||||
exec_msg.info_msgs[n]->strval = log_info->tty;
|
||||
exec_msg.info_msgs[n]->value_case = INFO_MESSAGE__VALUE_STRVAL;
|
||||
n++;
|
||||
|
||||
/* Update n_info_msgs. */
|
||||
exec_msg.n_info_msgs = n;
|
||||
@ -344,7 +468,7 @@ done:
|
||||
* Returns true on success, false on failure.
|
||||
*/
|
||||
static bool
|
||||
fmt_io_buf(int type, struct timing_closure *timing,
|
||||
fmt_io_buf(int type, struct client_closure *closure,
|
||||
struct connection_buffer *buf)
|
||||
{
|
||||
ClientMessage client_msg = CLIENT_MESSAGE__INIT;
|
||||
@ -353,15 +477,15 @@ fmt_io_buf(int type, struct timing_closure *timing,
|
||||
bool ret = false;
|
||||
debug_decl(fmt_io_buf, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (!read_io_buf(timing))
|
||||
if (!read_io_buf(closure))
|
||||
goto done;
|
||||
|
||||
/* Fill in IoBuffer. */
|
||||
delay.tv_sec = timing->delay.tv_sec;
|
||||
delay.tv_nsec = timing->delay.tv_nsec;
|
||||
delay.tv_sec = closure->timing.delay.tv_sec;
|
||||
delay.tv_nsec = closure->timing.delay.tv_nsec;
|
||||
iobuf_msg.delay = &delay;
|
||||
iobuf_msg.data.data = (void *)timing->buf;
|
||||
iobuf_msg.data.len = timing->u.nbytes;
|
||||
iobuf_msg.data.data = (void *)closure->buf;
|
||||
iobuf_msg.data.len = closure->timing.u.nbytes;
|
||||
|
||||
/* TODO: split buffer if it is too large */
|
||||
sudo_warnx("sending IoBuffer length %zu, type %d, size %zu", iobuf_msg.data.len, type, io_buffer__get_packed_size(&iobuf_msg)); // XXX
|
||||
@ -384,11 +508,12 @@ done:
|
||||
* Returns true on success, false on failure.
|
||||
*/
|
||||
static bool
|
||||
fmt_winsize(struct timing_closure *timing, struct connection_buffer *buf)
|
||||
fmt_winsize(struct client_closure *closure, struct connection_buffer *buf)
|
||||
{
|
||||
ClientMessage client_msg = CLIENT_MESSAGE__INIT;
|
||||
ChangeWindowSize winsize_msg = CHANGE_WINDOW_SIZE__INIT;
|
||||
TimeSpec delay = TIME_SPEC__INIT;
|
||||
struct timing_closure *timing = &closure->timing;
|
||||
bool ret = false;
|
||||
debug_decl(fmt_winsize, SUDO_DEBUG_UTIL)
|
||||
|
||||
@ -397,7 +522,7 @@ fmt_winsize(struct timing_closure *timing, struct connection_buffer *buf)
|
||||
delay.tv_nsec = timing->delay.tv_nsec;
|
||||
winsize_msg.delay = &delay;
|
||||
winsize_msg.rows = timing->u.winsize.lines;
|
||||
winsize_msg.cols = timing->u.winsize.columns;
|
||||
winsize_msg.cols = timing->u.winsize.cols;
|
||||
|
||||
sudo_warnx("sending ChangeWindowSize, %dx%d, size %zu", winsize_msg.rows, winsize_msg.cols, change_window_size__get_packed_size(&winsize_msg)); // XXX
|
||||
|
||||
@ -419,11 +544,12 @@ done:
|
||||
* Returns true on success, false on failure.
|
||||
*/
|
||||
static bool
|
||||
fmt_suspend(struct timing_closure *timing, struct connection_buffer *buf)
|
||||
fmt_suspend(struct client_closure *closure, struct connection_buffer *buf)
|
||||
{
|
||||
ClientMessage client_msg = CLIENT_MESSAGE__INIT;
|
||||
CommandSuspend suspend_msg = COMMAND_SUSPEND__INIT;
|
||||
TimeSpec delay = TIME_SPEC__INIT;
|
||||
struct timing_closure *timing = &closure->timing;
|
||||
bool ret = false;
|
||||
debug_decl(fmt_suspend, SUDO_DEBUG_UTIL)
|
||||
|
||||
@ -431,7 +557,9 @@ fmt_suspend(struct timing_closure *timing, struct connection_buffer *buf)
|
||||
delay.tv_sec = timing->delay.tv_sec;
|
||||
delay.tv_nsec = timing->delay.tv_nsec;
|
||||
suspend_msg.delay = &delay;
|
||||
suspend_msg.signal = timing->buf;
|
||||
if (sig2str(timing->u.signo, closure->buf) == -1)
|
||||
goto done;
|
||||
suspend_msg.signal = closure->buf;
|
||||
|
||||
sudo_warnx("sending CommandSuspend, %s, size %zu", suspend_msg.signal, command_suspend__get_packed_size(&suspend_msg)); // XXX
|
||||
|
||||
@ -481,25 +609,25 @@ fmt_next_iolog(struct client_closure *closure)
|
||||
|
||||
switch (timing->event) {
|
||||
case IO_EVENT_STDIN:
|
||||
ret = fmt_io_buf(CLIENT_MESSAGE__TYPE_STDIN_BUF, timing, buf);
|
||||
ret = fmt_io_buf(CLIENT_MESSAGE__TYPE_STDIN_BUF, closure, buf);
|
||||
break;
|
||||
case IO_EVENT_STDOUT:
|
||||
ret = fmt_io_buf(CLIENT_MESSAGE__TYPE_STDOUT_BUF, timing, buf);
|
||||
ret = fmt_io_buf(CLIENT_MESSAGE__TYPE_STDOUT_BUF, closure, buf);
|
||||
break;
|
||||
case IO_EVENT_STDERR:
|
||||
ret = fmt_io_buf(CLIENT_MESSAGE__TYPE_STDERR_BUF, timing, buf);
|
||||
ret = fmt_io_buf(CLIENT_MESSAGE__TYPE_STDERR_BUF, closure, buf);
|
||||
break;
|
||||
case IO_EVENT_TTYIN:
|
||||
ret = fmt_io_buf(CLIENT_MESSAGE__TYPE_TTYIN_BUF, timing, buf);
|
||||
ret = fmt_io_buf(CLIENT_MESSAGE__TYPE_TTYIN_BUF, closure, buf);
|
||||
break;
|
||||
case IO_EVENT_TTYOUT:
|
||||
ret = fmt_io_buf(CLIENT_MESSAGE__TYPE_TTYOUT_BUF, timing, buf);
|
||||
ret = fmt_io_buf(CLIENT_MESSAGE__TYPE_TTYOUT_BUF, closure, buf);
|
||||
break;
|
||||
case IO_EVENT_WINSIZE:
|
||||
ret = fmt_winsize(timing, buf);
|
||||
ret = fmt_winsize(closure, buf);
|
||||
break;
|
||||
case IO_EVENT_SUSPEND:
|
||||
ret = fmt_suspend(timing, buf);
|
||||
ret = fmt_suspend(closure, buf);
|
||||
break;
|
||||
default:
|
||||
sudo_warnx("unexpected I/O event %d", timing->event);
|
||||
@ -607,7 +735,7 @@ handle_log_id(char *id, struct client_closure *closure)
|
||||
debug_decl(handle_log_id, SUDO_DEBUG_UTIL)
|
||||
|
||||
sudo_warnx("remote log ID: %s", id);
|
||||
if ((closure->log_info->iolog_dir = strdup(id)) == NULL)
|
||||
if ((closure->iolog_dir = strdup(id)) == NULL)
|
||||
sudo_fatal(NULL);
|
||||
debug_return_bool(true);
|
||||
}
|
||||
@ -794,7 +922,7 @@ bad:
|
||||
* Allocate a new connection closure.
|
||||
*/
|
||||
static struct client_closure *
|
||||
client_closure_alloc(int sock, struct log_info *log_info)
|
||||
client_closure_alloc(int sock, struct iolog_info *log_info)
|
||||
{
|
||||
struct client_closure *closure;
|
||||
debug_decl(client_closure_alloc, SUDO_DEBUG_UTIL)
|
||||
@ -805,9 +933,9 @@ client_closure_alloc(int sock, struct log_info *log_info)
|
||||
closure->state = RECV_HELLO;
|
||||
closure->log_info = log_info;
|
||||
|
||||
closure->timing.bufsize = 10240;
|
||||
closure->timing.buf = malloc(closure->timing.bufsize);
|
||||
if (closure->timing.buf == NULL)
|
||||
closure->bufsize = 10240;
|
||||
closure->buf = malloc(closure->bufsize);
|
||||
if (closure->buf == NULL)
|
||||
goto bad;
|
||||
|
||||
closure->read_buf.size = UINT16_MAX + sizeof(uint16_t);
|
||||
@ -836,12 +964,40 @@ bad:
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open any I/O log files that are present.
|
||||
* The timing file must always exist.
|
||||
*/
|
||||
bool
|
||||
iolog_open_all(const char *iolog_path)
|
||||
{
|
||||
char fname[PATH_MAX];
|
||||
int i, len;
|
||||
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]);
|
||||
}
|
||||
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]);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct client_closure *closure;
|
||||
struct sudo_event_base *evbase;
|
||||
struct log_info *log_info;
|
||||
struct iolog_info *log_info;
|
||||
const char *host = "localhost";
|
||||
const char *port = DEFAULT_PORT_STR;
|
||||
char fname[PATH_MAX];
|
||||
@ -892,7 +1048,7 @@ main(int argc, char *argv[])
|
||||
sudo_warnx("parsed log file %s", fname); // XXX
|
||||
|
||||
/* Open the I/O log files. */
|
||||
if (!iolog_open(iolog_path))
|
||||
if (!iolog_open_all(iolog_path))
|
||||
goto bad;
|
||||
|
||||
/* Connect to server, setup events. */
|
||||
|
@ -33,6 +33,7 @@
|
||||
#define IOFD_TIMING 5
|
||||
#define IOFD_MAX 6
|
||||
|
||||
#if 0
|
||||
struct timing_closure {
|
||||
struct timespec delay;
|
||||
int event;
|
||||
@ -46,6 +47,7 @@ struct timing_closure {
|
||||
char *buf;
|
||||
size_t bufsize;
|
||||
};
|
||||
#endif
|
||||
|
||||
enum client_state {
|
||||
ERROR,
|
||||
@ -73,13 +75,9 @@ struct client_closure {
|
||||
struct connection_buffer write_buf;
|
||||
struct sudo_event *read_ev;
|
||||
struct sudo_event *write_ev;
|
||||
struct log_info *log_info;
|
||||
struct iolog_info *log_info;
|
||||
char *iolog_dir;
|
||||
char *buf; /* XXX */
|
||||
size_t bufsize; /* XXX */
|
||||
enum client_state state;
|
||||
};
|
||||
|
||||
/* iolog_reader.c */
|
||||
bool iolog_open(const char *iolog_path);
|
||||
bool read_io_buf(struct timing_closure *timing);
|
||||
int read_timing_record(struct timing_closure *timing);
|
||||
struct log_info *parse_logfile(const char *logfile);
|
||||
void free_log_info(struct log_info *li);
|
||||
|
3
mkdep.pl
3
mkdep.pl
@ -147,7 +147,8 @@ sub mkdep {
|
||||
$dir_vars{'devdir'} = $dir_vars{'srcdir'};
|
||||
$dir_vars{'authdir'} = $dir_vars{'srcdir'} . "/auth";
|
||||
$dir_vars{'builddir'} = $top_builddir . "/" . $dir_vars{'srcdir'};
|
||||
$dir_vars{'top_srcdir'} = '.';
|
||||
$dir_vars{'top_srcdir'} = $top_srcdir;
|
||||
$dir_vars{'sudoers_srcdir'} = $top_srcdir . "/plugins/sudoers";
|
||||
#$dir_vars{'top_builddir'} = '.';
|
||||
$dir_vars{'incdir'} = 'include';
|
||||
|
||||
|
@ -964,7 +964,8 @@ check_iolog_plugin.o: $(srcdir)/regress/iolog_plugin/check_iolog_plugin.c \
|
||||
$(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)/logging.h $(srcdir)/parse.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
|
||||
@ -976,7 +977,8 @@ check_iolog_plugin.i: $(srcdir)/regress/iolog_plugin/check_iolog_plugin.c \
|
||||
$(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)/logging.h $(srcdir)/parse.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
|
||||
@ -986,12 +988,14 @@ check_iolog_plugin.plog: check_iolog_plugin.i
|
||||
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 $(top_builddir)/config.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 $(top_builddir)/config.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 $@
|
||||
@ -1589,13 +1593,13 @@ 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 \
|
||||
$(top_builddir)/config.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 \
|
||||
$(top_builddir)/config.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 $@
|
||||
@ -2431,8 +2435,9 @@ sudoreplay.o: $(srcdir)/sudoreplay.c $(incdir)/compat/getopt.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)/logging.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(srcdir)/iolog_files.h $(srcdir)/iolog_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 \
|
||||
@ -2440,8 +2445,9 @@ sudoreplay.i: $(srcdir)/sudoreplay.c $(incdir)/compat/getopt.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)/logging.h \
|
||||
$(top_builddir)/config.h $(top_builddir)/pathnames.h
|
||||
$(srcdir)/iolog_files.h $(srcdir)/iolog_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 $@
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2009-2018 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
* 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
|
||||
@ -48,41 +48,4 @@ union io_fd {
|
||||
void *v;
|
||||
};
|
||||
|
||||
/*
|
||||
* Info present in the I/O log file
|
||||
*/
|
||||
struct log_info {
|
||||
char *cwd;
|
||||
char *user;
|
||||
char *runas_user;
|
||||
char *runas_group;
|
||||
char *tty;
|
||||
char *cmd;
|
||||
time_t tstamp;
|
||||
int rows;
|
||||
int cols;
|
||||
};
|
||||
|
||||
struct timing_closure {
|
||||
const char *decimal;
|
||||
struct timespec *max_delay;
|
||||
union io_fd fd;
|
||||
int event;
|
||||
union {
|
||||
struct {
|
||||
int rows;
|
||||
int cols;
|
||||
} winsize;
|
||||
size_t nbytes; // XXX
|
||||
int signo;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* iolog_util.c */
|
||||
bool parse_timing(const char *buf, struct timespec *delay, struct timing_closure *timing);
|
||||
char *parse_delay(const char *cp, struct timespec *delay, const char *decimal_point);
|
||||
struct log_info *parse_logfile(const char *logfile);
|
||||
void free_log_info(struct log_info *li);
|
||||
void adjust_delay(struct timespec *delay, struct timespec *max_delay, double scale_factor);
|
||||
|
||||
#endif /* SUDOERS_IOLOG_H */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2009-2018 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
* 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
|
||||
@ -56,18 +56,18 @@
|
||||
#include "sudo_fatal.h"
|
||||
#include "sudo_debug.h"
|
||||
#include "sudo_util.h"
|
||||
#include "iolog.h"
|
||||
#include "iolog_util.h"
|
||||
|
||||
static int timing_event_adj;
|
||||
|
||||
struct log_info *
|
||||
struct iolog_info *
|
||||
parse_logfile(const char *logfile)
|
||||
{
|
||||
FILE *fp;
|
||||
char *buf = NULL, *cp, *ep;
|
||||
const char *errstr;
|
||||
size_t bufsize = 0, cwdsize = 0, cmdsize = 0;
|
||||
struct log_info *li = NULL;
|
||||
struct iolog_info *li = NULL;
|
||||
debug_decl(parse_logfile, SUDO_DEBUG_UTIL)
|
||||
|
||||
fp = fopen(logfile, "r");
|
||||
@ -96,8 +96,8 @@ parse_logfile(const char *logfile)
|
||||
li->cmd[strcspn(li->cmd, "\n")] = '\0';
|
||||
|
||||
/*
|
||||
* Crack the log line (rows and cols not present in old versions).
|
||||
* timestamp:user:runas_user:runas_group:tty:rows:cols
|
||||
* Crack the log line (lines and cols not present in old versions).
|
||||
* timestamp:user:runas_user:runas_group:tty:lines:cols
|
||||
* XXX - probably better to use strtok and switch on the state.
|
||||
*/
|
||||
buf[strcspn(buf, "\n")] = '\0';
|
||||
@ -115,7 +115,7 @@ parse_logfile(const char *logfile)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* user */
|
||||
/* submit user */
|
||||
cp = ep + 1;
|
||||
if ((ep = strchr(cp, ':')) == NULL) {
|
||||
sudo_warn(U_("%s: user field is missing"), logfile);
|
||||
@ -144,14 +144,14 @@ parse_logfile(const char *logfile)
|
||||
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
}
|
||||
|
||||
/* tty, followed by optional rows + columns */
|
||||
/* tty, followed by optional lines + cols */
|
||||
cp = ep + 1;
|
||||
if ((ep = strchr(cp, ':')) == NULL) {
|
||||
/* just the tty */
|
||||
if ((li->tty = strdup(cp)) == NULL)
|
||||
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
} else {
|
||||
/* tty followed by rows + columns */
|
||||
/* tty followed by lines + cols */
|
||||
if ((li->tty = strndup(cp, (size_t)(ep - cp))) == NULL)
|
||||
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
cp = ep + 1;
|
||||
@ -160,10 +160,10 @@ parse_logfile(const char *logfile)
|
||||
if ((ep = strchr(cp, ':')) != NULL) {
|
||||
*ep = '\0';
|
||||
}
|
||||
li->rows = sudo_strtonum(cp, 1, INT_MAX, &errstr);
|
||||
li->lines = sudo_strtonum(cp, 1, INT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"%s: tty rows %s: %s", logfile, cp, errstr);
|
||||
"%s: tty lines %s: %s", logfile, cp, errstr);
|
||||
}
|
||||
if (ep != NULL) {
|
||||
cp = ep + 1;
|
||||
@ -182,7 +182,7 @@ bad:
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
free(buf);
|
||||
free_log_info(li);
|
||||
free_iolog_info(li);
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
@ -298,15 +298,14 @@ parse_delay(const char *cp, struct timespec *delay, const char *decimal_point)
|
||||
/*
|
||||
* Parse a timing line, which is formatted as:
|
||||
* IO_EVENT_TTYOUT sleep_time num_bytes
|
||||
* IO_EVENT_WINSIZE sleep_time rows cols
|
||||
* IO_EVENT_WINSIZE sleep_time lines cols
|
||||
* IO_EVENT_SUSPEND sleep_time signo
|
||||
* Where type is IO_EVENT_*, sleep_time is the number of seconds to sleep
|
||||
* before writing the data and num_bytes is the number of bytes to output.
|
||||
* Returns true on success and false on failure.
|
||||
*/
|
||||
bool
|
||||
parse_timing(const char *buf, struct timespec *delay,
|
||||
struct timing_closure *timing)
|
||||
parse_timing(const char *line, struct timing_closure *timing)
|
||||
{
|
||||
unsigned long ulval;
|
||||
char *cp, *ep;
|
||||
@ -316,8 +315,8 @@ parse_timing(const char *buf, struct timespec *delay,
|
||||
timing->fd.v = NULL;
|
||||
|
||||
/* Parse event type. */
|
||||
ulval = strtoul(buf, &ep, 10);
|
||||
if (ep == buf || !isspace((unsigned char) *ep))
|
||||
ulval = strtoul(line, &ep, 10);
|
||||
if (ep == line || !isspace((unsigned char) *ep))
|
||||
goto bad;
|
||||
if (ulval >= IO_EVENT_COUNT)
|
||||
goto bad;
|
||||
@ -330,7 +329,7 @@ parse_timing(const char *buf, struct timespec *delay,
|
||||
continue;
|
||||
|
||||
/* Parse delay, returns the next field or NULL on error. */
|
||||
if ((cp = parse_delay(cp, delay, timing->decimal)) == NULL)
|
||||
if ((cp = parse_delay(cp, &timing->delay, timing->decimal)) == NULL)
|
||||
goto bad;
|
||||
|
||||
switch (timing->event) {
|
||||
@ -345,7 +344,7 @@ parse_timing(const char *buf, struct timespec *delay,
|
||||
goto bad;
|
||||
if (ulval > INT_MAX)
|
||||
goto bad;
|
||||
timing->u.winsize.rows = (int)ulval;
|
||||
timing->u.winsize.lines = (int)ulval;
|
||||
for (cp = ep + 1; isspace((unsigned char) *cp); cp++)
|
||||
continue;
|
||||
|
||||
@ -374,7 +373,7 @@ bad:
|
||||
}
|
||||
|
||||
void
|
||||
free_log_info(struct log_info *li)
|
||||
free_iolog_info(struct iolog_info *li)
|
||||
{
|
||||
if (li != NULL) {
|
||||
free(li->cwd);
|
||||
|
61
plugins/sudoers/iolog_util.h
Normal file
61
plugins/sudoers/iolog_util.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 */
|
@ -37,7 +37,7 @@
|
||||
#include "sudoers.h"
|
||||
#include "def_data.c" /* for iolog_path.c */
|
||||
#include "sudo_plugin.h"
|
||||
#include "iolog.h"
|
||||
#include "iolog_util.h"
|
||||
|
||||
extern struct io_plugin sudoers_io;
|
||||
|
||||
@ -85,7 +85,7 @@ bool
|
||||
validate_iolog_info(const char *logfile)
|
||||
{
|
||||
time_t now;
|
||||
struct log_info *info;
|
||||
struct iolog_info *info;
|
||||
|
||||
time(&now);
|
||||
|
||||
@ -123,8 +123,8 @@ validate_iolog_info(const char *logfile)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info->rows != 24) {
|
||||
sudo_warnx("bad rows: want 24 got %d", info->rows);
|
||||
if (info->lines != 24) {
|
||||
sudo_warnx("bad lines: want 24 got %d", info->lines);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ validate_iolog_info(const char *logfile)
|
||||
return false;
|
||||
}
|
||||
|
||||
free_log_info(info);
|
||||
free_iolog_info(info);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -149,14 +149,13 @@ validate_timing(FILE *fp, int recno, int type, unsigned int p1, unsigned int p2)
|
||||
{
|
||||
struct timing_closure timing;
|
||||
char buf[LINE_MAX];
|
||||
struct timespec delay;
|
||||
|
||||
if (!fgets(buf, sizeof(buf), fp)) {
|
||||
sudo_warn("unable to read timing file");
|
||||
return false;
|
||||
}
|
||||
buf[strcspn(buf, "\n")] = '\0';
|
||||
if (!parse_timing(buf, &delay, &timing)) {
|
||||
if (!parse_timing(buf, &timing)) {
|
||||
sudo_warnx("invalid timing file line: %s", buf);
|
||||
return false;
|
||||
}
|
||||
@ -166,9 +165,9 @@ validate_timing(FILE *fp, int recno, int type, unsigned int p1, unsigned int p2)
|
||||
return false;
|
||||
}
|
||||
if (type == IO_EVENT_WINSIZE) {
|
||||
if (timing.u.winsize.rows != (int)p1) {
|
||||
sudo_warnx("record %d: want %u rows, got %u", recno, p1,
|
||||
timing.u.winsize.rows);
|
||||
if (timing.u.winsize.lines != (int)p1) {
|
||||
sudo_warnx("record %d: want %u lines, got %u", recno, p1,
|
||||
timing.u.winsize.lines);
|
||||
return false;
|
||||
}
|
||||
if (timing.u.winsize.cols != (int)p2) {
|
||||
@ -183,9 +182,9 @@ validate_timing(FILE *fp, int recno, int type, unsigned int p1, unsigned int p2)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (delay.tv_sec != 0 || delay.tv_nsec > 10000000) {
|
||||
if (timing.delay.tv_sec != 0 || timing.delay.tv_nsec > 10000000) {
|
||||
sudo_warnx("record %d: got excessive delay %lld.%09ld", recno,
|
||||
(long long)delay.tv_sec, delay.tv_nsec);
|
||||
(long long)timing.delay.tv_sec, timing.delay.tv_nsec);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "sudo_compat.h"
|
||||
#include "sudo_util.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "iolog.h"
|
||||
#include "iolog_util.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_util");
|
||||
initprogname(argc > 0 ? argv[0] : "check_iolog_reader");
|
||||
|
||||
test_parse_delay(&tests, &errors);
|
||||
|
||||
test_adjust_delay(&tests, &errors);
|
||||
|
||||
if (tests != 0) {
|
||||
printf("check_iolog_util: %d test%s run, %d errors, %d%% success rate\n",
|
||||
printf("check_iolog_reader: %d test%s run, %d errors, %d%% success rate\n",
|
||||
tests, tests == 1 ? "" : "s", errors,
|
||||
(tests - errors) * 100 / tests);
|
||||
}
|
||||
|
@ -64,7 +64,7 @@
|
||||
#include "sudo_compat.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "logging.h"
|
||||
#include "iolog.h"
|
||||
#include "iolog_util.h"
|
||||
#include "iolog_files.h"
|
||||
#include "sudo_queue.h"
|
||||
#include "sudo_plugin.h"
|
||||
@ -89,6 +89,7 @@ struct replay_closure {
|
||||
struct sudo_event *sigquit_ev;
|
||||
struct sudo_event *sigterm_ev;
|
||||
struct sudo_event *sigtstp_ev;
|
||||
struct timespec *max_delay;
|
||||
struct timing_closure timing;
|
||||
bool interactive;
|
||||
bool suspend_wait;
|
||||
@ -141,7 +142,7 @@ static const char *session_dir = _PATH_SUDO_IO_LOGDIR;
|
||||
|
||||
static bool terminal_can_resize, terminal_was_resized;
|
||||
|
||||
static int terminal_rows, terminal_cols;
|
||||
static int terminal_lines, terminal_cols;
|
||||
|
||||
static int ttyfd = -1;
|
||||
|
||||
@ -174,7 +175,7 @@ static void sudoreplay_cleanup(void);
|
||||
static void usage(int);
|
||||
static void write_output(int fd, int what, void *v);
|
||||
static void restore_terminal_size(void);
|
||||
static void setup_terminal(struct log_info *li, bool interactive, bool resize);
|
||||
static void setup_terminal(struct iolog_info *li, bool interactive, bool resize);
|
||||
|
||||
#define VALID_ID(s) (isalnum((unsigned char)(s)[0]) && \
|
||||
isalnum((unsigned char)(s)[1]) && isalnum((unsigned char)(s)[2]) && \
|
||||
@ -200,7 +201,7 @@ main(int argc, char *argv[])
|
||||
bool interactive = true, suspend_wait = false, resize = true;
|
||||
const char *decimal, *id, *user = NULL, *pattern = NULL, *tty = NULL;
|
||||
char *cp, *ep, path[PATH_MAX];
|
||||
struct log_info *li;
|
||||
struct iolog_info *li;
|
||||
struct timespec max_delay_storage, *max_delay = NULL;
|
||||
double dval;
|
||||
debug_decl(main, SUDO_DEBUG_MAIN)
|
||||
@ -353,7 +354,7 @@ main(int argc, char *argv[])
|
||||
putchar('\n');
|
||||
|
||||
/* Done with parsed log file. */
|
||||
free_log_info(li);
|
||||
free_iolog_info(li);
|
||||
li = NULL;
|
||||
|
||||
/* Replay session corresponding to io_log_files[]. */
|
||||
@ -551,7 +552,7 @@ done:
|
||||
* Get the terminal size using vt100 terminal escapes.
|
||||
*/
|
||||
static bool
|
||||
xterm_get_size(int *new_rows, int *new_cols)
|
||||
xterm_get_size(int *new_lines, int *new_cols)
|
||||
{
|
||||
struct sudo_event_base *evbase;
|
||||
struct getsize_closure gc;
|
||||
@ -569,7 +570,7 @@ xterm_get_size(int *new_rows, int *new_cols)
|
||||
|
||||
/*
|
||||
* Callback info for reading back the size with a 10 second timeout.
|
||||
* We expect two numbers (rows and cols).
|
||||
* We expect two numbers (lines and cols).
|
||||
*/
|
||||
gc.state = INITIAL|READCHAR;
|
||||
gc.nums_depth = 0;
|
||||
@ -594,7 +595,7 @@ xterm_get_size(int *new_rows, int *new_cols)
|
||||
if (gc.state == GOTSIZE) {
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||
"terminal size %d x %x", gc.nums[0], gc.nums[1]);
|
||||
*new_rows = gc.nums[0];
|
||||
*new_lines = gc.nums[0];
|
||||
*new_cols = gc.nums[1];
|
||||
ret = true;
|
||||
}
|
||||
@ -607,21 +608,21 @@ done:
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the size of the text area to rows and cols.
|
||||
* Set the size of the text area to lines and cols.
|
||||
* Depending on the terminal implementation, the window itself may
|
||||
* or may not shrink to a smaller size.
|
||||
*/
|
||||
static bool
|
||||
xterm_set_size(int rows, int cols)
|
||||
xterm_set_size(int lines, int cols)
|
||||
{
|
||||
const char setsize_fmt[] = "\033[8;%d;%dt";
|
||||
int len, new_rows, new_cols;
|
||||
int len, new_lines, new_cols;
|
||||
bool ret = false;
|
||||
char buf[1024];
|
||||
debug_decl(xterm_set_size, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* XXX - save cursor and position restore after resizing */
|
||||
len = snprintf(buf, sizeof(buf), setsize_fmt, rows, cols);
|
||||
len = snprintf(buf, sizeof(buf), setsize_fmt, lines, cols);
|
||||
if (len < 0 || len >= ssizeof(buf)) {
|
||||
/* not possible due to size of buf */
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
@ -634,9 +635,9 @@ xterm_set_size(int rows, int cols)
|
||||
goto done;
|
||||
}
|
||||
/* XXX - keyboard input will interfere with this */
|
||||
if (!xterm_get_size(&new_rows, &new_cols))
|
||||
if (!xterm_get_size(&new_lines, &new_cols))
|
||||
goto done;
|
||||
if (rows == new_rows && cols == new_cols)
|
||||
if (lines == new_lines && cols == new_cols)
|
||||
ret = true;
|
||||
|
||||
done:
|
||||
@ -644,7 +645,7 @@ done:
|
||||
}
|
||||
|
||||
static void
|
||||
setup_terminal(struct log_info *li, bool interactive, bool resize)
|
||||
setup_terminal(struct iolog_info *li, bool interactive, bool resize)
|
||||
{
|
||||
const char *term;
|
||||
debug_decl(check_terminal, SUDO_DEBUG_UTIL)
|
||||
@ -662,7 +663,7 @@ setup_terminal(struct log_info *li, bool interactive, bool resize)
|
||||
}
|
||||
|
||||
/* Find terminal size if the session has size info. */
|
||||
if (li->rows == 0 && li->cols == 0) {
|
||||
if (li->lines == 0 && li->cols == 0) {
|
||||
/* no tty size info, hope for the best... */
|
||||
debug_return;
|
||||
}
|
||||
@ -675,7 +676,7 @@ setup_terminal(struct log_info *li, bool interactive, bool resize)
|
||||
for (tn = compatible_terms; tn->name != NULL; tn++) {
|
||||
if (strncmp(term, tn->name, tn->len) == 0) {
|
||||
/* xterm-like terminals can resize themselves. */
|
||||
if (xterm_get_size(&terminal_rows, &terminal_cols))
|
||||
if (xterm_get_size(&terminal_lines, &terminal_cols))
|
||||
terminal_can_resize = true;
|
||||
break;
|
||||
}
|
||||
@ -685,20 +686,20 @@ setup_terminal(struct log_info *li, bool interactive, bool resize)
|
||||
|
||||
if (!terminal_can_resize) {
|
||||
/* either not xterm or not interactive */
|
||||
sudo_get_ttysize(&terminal_rows, &terminal_cols);
|
||||
sudo_get_ttysize(&terminal_lines, &terminal_cols);
|
||||
}
|
||||
|
||||
if (li->rows == terminal_rows && li->cols == terminal_cols) {
|
||||
if (li->lines == terminal_lines && li->cols == terminal_cols) {
|
||||
/* nothing to change */
|
||||
debug_return;
|
||||
}
|
||||
|
||||
if (terminal_can_resize) {
|
||||
/* session terminal size is different, try to resize ours */
|
||||
if (xterm_set_size(li->rows, li->cols)) {
|
||||
if (xterm_set_size(li->lines, li->cols)) {
|
||||
/* success */
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||
"resized terminal to %d x %x", li->rows, li->cols);
|
||||
"resized terminal to %d x %x", li->lines, li->cols);
|
||||
terminal_was_resized = true;
|
||||
debug_return;
|
||||
}
|
||||
@ -706,20 +707,20 @@ setup_terminal(struct log_info *li, bool interactive, bool resize)
|
||||
terminal_can_resize = false;
|
||||
}
|
||||
|
||||
if (li->rows > terminal_rows || li->cols > terminal_cols) {
|
||||
if (li->lines > terminal_lines || li->cols > terminal_cols) {
|
||||
fputs(_("Warning: your terminal is too small to properly replay the log.\n"), stdout);
|
||||
printf(_("Log geometry is %d x %d, your terminal's geometry is %d x %d."), li->rows, li->cols, terminal_rows, terminal_cols);
|
||||
printf(_("Log geometry is %d x %d, your terminal's geometry is %d x %d."), li->lines, li->cols, terminal_lines, terminal_cols);
|
||||
}
|
||||
debug_return;
|
||||
}
|
||||
|
||||
static void
|
||||
resize_terminal(int rows, int cols)
|
||||
resize_terminal(int lines, int cols)
|
||||
{
|
||||
debug_decl(resize_terminal, SUDO_DEBUG_UTIL)
|
||||
|
||||
if (terminal_can_resize) {
|
||||
if (xterm_set_size(rows, cols))
|
||||
if (xterm_set_size(lines, cols))
|
||||
terminal_was_resized = true;
|
||||
else
|
||||
terminal_can_resize = false;
|
||||
@ -740,7 +741,7 @@ restore_terminal_size(void)
|
||||
stdout);
|
||||
fflush(stdout);
|
||||
(void)getchar();
|
||||
xterm_set_size(terminal_rows, terminal_cols);
|
||||
xterm_set_size(terminal_lines, terminal_cols);
|
||||
putchar('\r');
|
||||
putchar('\n');
|
||||
}
|
||||
@ -756,36 +757,36 @@ restore_terminal_size(void)
|
||||
static int
|
||||
read_timing_record(struct replay_closure *closure)
|
||||
{
|
||||
struct timespec timeout;
|
||||
char buf[LINE_MAX];
|
||||
struct timing_closure *timing = &closure->timing;
|
||||
char line[LINE_MAX];
|
||||
debug_decl(read_timing_record, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* Read next record from timing file. */
|
||||
if (io_log_gets(io_log_files[IOFD_TIMING].fd, buf, sizeof(buf)) == NULL) {
|
||||
if (io_log_gets(io_log_files[IOFD_TIMING].fd, line, sizeof(line)) == NULL) {
|
||||
/* EOF or error reading timing file, we are done. */
|
||||
debug_return_int(io_log_eof(io_log_files[IOFD_TIMING].fd) ? 1 : -1);
|
||||
}
|
||||
|
||||
/* Parse timing file record. */
|
||||
buf[strcspn(buf, "\n")] = '\0';
|
||||
if (!parse_timing(buf, &timeout, &closure->timing))
|
||||
sudo_fatalx(U_("invalid timing file line: %s"), buf);
|
||||
line[strcspn(line, "\n")] = '\0';
|
||||
if (!parse_timing(line, timing))
|
||||
sudo_fatalx(U_("invalid timing file line: %s"), line);
|
||||
|
||||
/* Record number bytes to read. */
|
||||
/* XXX - remove timing->nbytes? */
|
||||
if (closure->timing.event != IO_EVENT_WINSIZE &&
|
||||
closure->timing.event != IO_EVENT_SUSPEND) {
|
||||
if (timing->event != IO_EVENT_WINSIZE &&
|
||||
timing->event != IO_EVENT_SUSPEND) {
|
||||
closure->iobuf.len = 0;
|
||||
closure->iobuf.off = 0;
|
||||
closure->iobuf.lastc = '\0';
|
||||
closure->iobuf.toread = closure->timing.u.nbytes;
|
||||
closure->iobuf.toread = timing->u.nbytes;
|
||||
}
|
||||
|
||||
/* Adjust delay using speed factor and max_delay. */
|
||||
adjust_delay(&timeout, closure->timing.max_delay, speed_factor);
|
||||
adjust_delay(&timing->delay, closure->max_delay, speed_factor);
|
||||
|
||||
/* Schedule the delay event. */
|
||||
if (sudo_ev_add(closure->evbase, closure->delay_ev, &timeout, false) == -1)
|
||||
if (sudo_ev_add(closure->evbase, closure->delay_ev, &timing->delay, false) == -1)
|
||||
sudo_fatal(U_("unable to add event to queue"));
|
||||
|
||||
debug_return_int(0);
|
||||
@ -868,7 +869,7 @@ delay_cb(int fd, int what, void *v)
|
||||
|
||||
switch (timing->event) {
|
||||
case IO_EVENT_WINSIZE:
|
||||
resize_terminal(timing->u.winsize.rows, timing->u.winsize.cols);
|
||||
resize_terminal(timing->u.winsize.lines, timing->u.winsize.cols);
|
||||
break;
|
||||
case IO_EVENT_STDIN:
|
||||
if (io_log_files[IOFD_STDIN].enabled)
|
||||
@ -960,7 +961,7 @@ replay_closure_alloc(struct timespec *max_delay, const char *decimal,
|
||||
|
||||
closure->interactive = interactive;
|
||||
closure->suspend_wait = suspend_wait;
|
||||
closure->timing.max_delay = max_delay;
|
||||
closure->max_delay = max_delay;
|
||||
closure->timing.decimal = decimal;
|
||||
|
||||
/*
|
||||
@ -1297,7 +1298,7 @@ parse_expr(struct search_node_list *head, char *argv[], bool sub_expr)
|
||||
}
|
||||
|
||||
static bool
|
||||
match_expr(struct search_node_list *head, struct log_info *log, bool last_match)
|
||||
match_expr(struct search_node_list *head, struct iolog_info *log, bool last_match)
|
||||
{
|
||||
struct search_node *sn;
|
||||
bool res = false, matched = last_match;
|
||||
@ -1357,7 +1358,7 @@ list_session(char *logfile, regex_t *re, const char *user, const char *tty)
|
||||
{
|
||||
char idbuf[7], *idstr, *cp;
|
||||
const char *timestr;
|
||||
struct log_info *li;
|
||||
struct iolog_info *li;
|
||||
int ret = -1;
|
||||
debug_decl(list_session, SUDO_DEBUG_UTIL)
|
||||
|
||||
@ -1384,7 +1385,7 @@ list_session(char *logfile, regex_t *re, const char *user, const char *tty)
|
||||
cp[strlen(cp) - 4] = '\0';
|
||||
idstr = cp;
|
||||
}
|
||||
/* XXX - print rows + cols? */
|
||||
/* XXX - print lines + cols? */
|
||||
timestr = get_timestr(li->tstamp, 1);
|
||||
printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ",
|
||||
timestr ? timestr : "invalid date",
|
||||
@ -1396,7 +1397,7 @@ list_session(char *logfile, regex_t *re, const char *user, const char *tty)
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
free_log_info(li);
|
||||
free_iolog_info(li);
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user