summaryrefslogtreecommitdiffstats
path: root/lib/iolog/regress/iolog_filter/check_iolog_filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/iolog/regress/iolog_filter/check_iolog_filter.c')
-rw-r--r--lib/iolog/regress/iolog_filter/check_iolog_filter.c203
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;
+}