diff options
Diffstat (limited to 'lib/iolog/regress/iolog_filter/check_iolog_filter.c')
-rw-r--r-- | lib/iolog/regress/iolog_filter/check_iolog_filter.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/lib/iolog/regress/iolog_filter/check_iolog_filter.c b/lib/iolog/regress/iolog_filter/check_iolog_filter.c new file mode 100644 index 0000000..d24f12f --- /dev/null +++ b/lib/iolog/regress/iolog_filter/check_iolog_filter.c @@ -0,0 +1,203 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2022 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. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> + +#define SUDO_ERROR_WRAP 0 + +#include "sudo_compat.h" +#include "sudo_util.h" +#include "sudo_fatal.h" + +#include "sudo_iolog.h" + +sudo_dso_public int main(int argc, char *argv[]); + +int +main(int argc, char *argv[]) +{ + int dfd = -1, ttyin_fd = -1, ttyout_fd = -1, ttyin_ok_fd = -1; + int ch, i, ntests = 0, errors = 0; + void *passprompt_regex = NULL; + + initprogname(argc > 0 ? argv[0] : "check_iolog_filter"); + + while ((ch = getopt(argc, argv, "v")) != -1) { + switch (ch) { + case 'v': + /* ignore */ + break; + default: + fprintf(stderr, "usage: %s [-v] iolog_dir ...\n", getprogname()); + return EXIT_FAILURE; + } + } + argc -= optind; + argv += optind; + + passprompt_regex = iolog_pwfilt_alloc(); + if (passprompt_regex == NULL) + sudo_fatalx("unable to allocate memory"); + if (!iolog_pwfilt_add(passprompt_regex, "(?i)password[: ]*")) + exit(1); + + for (i = 0; i < argc; i++) { + struct iolog_file iolog_timing = { true }; + struct timing_closure timing; + const char *logdir = argv[i]; + char tbuf[8192], fbuf[8192]; + ssize_t nread; + + ntests++; + + /* I/O logs consist of multiple files in a directory. */ + dfd = open(logdir, O_RDONLY); + if (dfd == -1) { + sudo_warn("%s", logdir); + errors++; + continue; + } + + if (!iolog_open(&iolog_timing, dfd, IOFD_TIMING, "r")) { + sudo_warn("timing"); + errors++; + goto next; + } + + ttyout_fd = openat(dfd, "ttyout", O_RDONLY, 0644); + if (ttyout_fd == -1) { + sudo_warn("ttyout"); + errors++; + goto next; + } + + ttyin_fd = openat(dfd, "ttyin", O_RDONLY, 0644); + if (ttyin_fd == -1) { + sudo_warn("ttyin"); + errors++; + goto next; + } + + ttyin_ok_fd = openat(dfd, "ttyin.filtered", O_RDONLY, 0644); + if (ttyin_ok_fd == -1) { + sudo_warn("ttyin.filtered"); + errors++; + goto next; + } + + memset(&timing, 0, sizeof(timing)); + timing.decimal = "."; + for (;;) { + char *newbuf = NULL; + const char *name; + int fd; + + if (iolog_read_timing_record(&iolog_timing, &timing) != 0) + break; + + switch (timing.event) { + case IO_EVENT_TTYOUT: + fd = ttyout_fd; + name = "ttyout"; + break; + case IO_EVENT_TTYIN: + fd = ttyin_fd; + name = "ttyin"; + break; + default: + continue; + } + + if (timing.u.nbytes > sizeof(tbuf)) { + sudo_warn("buffer too small, %zu > %zu", timing.u.nbytes, + sizeof(tbuf)); + errors++; + continue; + } + + nread = read(fd, tbuf, timing.u.nbytes); + if ((size_t)nread != timing.u.nbytes) { + if (nread == -1) + sudo_warn("%s/%s", argv[i], name); + else + sudo_warnx("%s/%s: short read", argv[i], name); + errors++; + continue; + } + + /* Apply filter. */ + if (!iolog_pwfilt_run(passprompt_regex, timing.event, tbuf, + timing.u.nbytes, &newbuf)) { + errors++; + continue; + } + + if (timing.event == IO_EVENT_TTYIN) { + nread = read(ttyin_ok_fd, fbuf, timing.u.nbytes); + if (nread == -1) { + if (nread == -1) + sudo_warn("%s/ttyin.filtered", argv[i]); + else + sudo_warnx("%s/ttyin.filtered: short read", argv[i]); + errors++; + free(newbuf); + break; + } + if (memcmp(fbuf, newbuf ? newbuf : tbuf, timing.u.nbytes) != 0) { + sudo_warnx("%s: ttyin mismatch at byte %lld", argv[i], + (long long)lseek(fd, 0, SEEK_CUR)); + errors++; + free(newbuf); + break; + } + } + + free(newbuf); + } +next: + if (ttyin_fd != -1) { + close(ttyin_fd); + ttyin_fd = -1; + } + if (ttyin_ok_fd != -1) { + close(ttyin_ok_fd); + ttyin_ok_fd = -1; + } + if (dfd != -1) { + close(dfd); + dfd = -1; + } + if (iolog_timing.enabled) + iolog_close(&iolog_timing, NULL); + } + iolog_pwfilt_free(passprompt_regex); + + if (ntests != 0) { + printf("iolog_filter: %d test%s run, %d errors, %d%% success rate\n", + ntests, ntests == 1 ? "" : "s", errors, + (ntests - errors) * 100 / ntests); + } + + return errors; +} |