diff options
Diffstat (limited to 'lib/eventlog/regress')
23 files changed, 1450 insertions, 0 deletions
diff --git a/lib/eventlog/regress/eventlog_store/store_json_test.c b/lib/eventlog/regress/eventlog_store/store_json_test.c new file mode 100644 index 0000000..5c8f6fe --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/store_json_test.c @@ -0,0 +1,199 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2020, 2023 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 <limits.h> +#include <unistd.h> + +#define SUDO_ERROR_WRAP 0 + +#include <sudo_compat.h> +#include <sudo_eventlog.h> +#include <sudo_fatal.h> +#include <sudo_util.h> + +#include <parse_json.h> + +sudo_dso_public int main(int argc, char *argv[]); + +sudo_noreturn static void +usage(void) +{ + fprintf(stderr, "usage: %s [-cv] input_file ...\n", + getprogname()); + exit(EXIT_FAILURE); +} + +static bool +compare(FILE *fp, const char *infile, struct json_container *jsonc) +{ + const char *cp; + unsigned int lineno = 0; + size_t linesize = 0; + char *line = NULL; + ssize_t len; + + cp = sudo_json_get_buf(jsonc); + + while ((len = getdelim(&line, &linesize, '\n', fp)) != -1) { + lineno++; + + /* skip open/close brace, not present in formatted output */ + if (lineno == 1 && strcmp(line, "{\n") == 0) + continue; + if (*cp == '\0' && strcmp(line, "}\n") == 0) + continue; + + /* Ignore newlines in output to make comparison easier. */ + if (*cp == '\n') + cp++; + if (line[len - 1] == '\n') + len--; + + if (strncmp(line, cp, (size_t)len) != 0) { + fprintf(stderr, "%s: mismatch on line %u\n", infile, lineno); + fprintf(stderr, "expected: %s", line); + fprintf(stderr, "got : %.*s\n", (int)len, cp); + return false; + } + cp += len; + } + free(line); + + return true; +} + +int +main(int argc, char *argv[]) +{ + int ch, i, ntests = 0, errors = 0; + bool cat = false; + + initprogname(argc > 0 ? argv[0] : "store_json_test"); + + while ((ch = getopt(argc, argv, "cv")) != -1) { + switch (ch) { + case 'c': + cat = true; + break; + case 'v': + /* ignored */ + break; + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc < 1) + usage(); + + for (i = 0; i < argc; i++) { + struct eventlog_json_object *root; + struct eventlog *evlog = NULL; + struct json_container jsonc; + const char *infile = argv[i]; + const char *outfile = argv[i]; + const char *cp; + char pathbuf[PATH_MAX]; + FILE *infp = NULL; + FILE *outfp = NULL; + + ntests++; + + if (!sudo_json_init(&jsonc, 4, false, true, true)) { + errors++; + continue; + } + + /* Parse input file. */ + if ((infp = fopen(infile, "r")) == NULL) { + sudo_warn("%s", argv[i]); + errors++; + continue; + } + root = eventlog_json_read(infp, infile); + if (root == NULL) { + errors++; + goto next; + } + + /* Convert JSON to event log. */ + evlog = calloc(1, sizeof(*evlog)); + if (evlog == NULL) { + sudo_warnx("%s: %s", __func__, "unable to allocate memory"); + errors++; + goto next; + } + if (!eventlog_json_parse(root, evlog)) { + errors++; + goto next; + } + + /* Format event log as JSON. */ + if (!eventlog_store_json(&jsonc, evlog)) { + errors++; + goto next; + } + + /* Check for a .out.ok file in the same location as the .in file. */ + cp = strrchr(infile, '.'); + if (cp != NULL && strcmp(cp, ".in") == 0) { + snprintf(pathbuf, sizeof(pathbuf), "%.*s.out.ok", + (int)(cp - infile), infile); + if ((outfp = fopen(pathbuf, "r")) != NULL) + outfile = pathbuf; + } + if (outfp == NULL) + outfp = infp; + + /* Compare output to expected output. */ + rewind(outfp); + if (!compare(outfp, outfile, &jsonc)) + errors++; + + /* Write the formatted output to stdout for -c (cat) */ + if (cat) { + fprintf(stdout, "{%s\n}\n", sudo_json_get_buf(&jsonc)); + fflush(stdout); + } + +next: + eventlog_free(evlog); + eventlog_json_free(root); + sudo_json_free(&jsonc); + if (infp != NULL) + fclose(infp); + if (outfp != NULL && outfp != infp) + fclose(outfp); + } + + if (ntests != 0) { + printf("%s: %d test%s run, %d errors, %d%% success rate\n", + getprogname(), ntests, ntests == 1 ? "" : "s", errors, + (ntests - errors) * 100 / ntests); + } + + return errors; +} diff --git a/lib/eventlog/regress/eventlog_store/store_sudo_test.c b/lib/eventlog/regress/eventlog_store/store_sudo_test.c new file mode 100644 index 0000000..f873cd5 --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/store_sudo_test.c @@ -0,0 +1,209 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2020, 2023 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 <limits.h> +#include <unistd.h> + +#define SUDO_ERROR_WRAP 0 + +#include <sudo_compat.h> +#include <sudo_eventlog.h> +#include <sudo_fatal.h> +#include <sudo_lbuf.h> +#include <sudo_util.h> + +sudo_dso_public int main(int argc, char *argv[]); + +sudo_noreturn static void +usage(void) +{ + fprintf(stderr, "usage: %s [-cv] input_file ...\n", + getprogname()); + exit(EXIT_FAILURE); +} + +static bool +compare(FILE *fp, const char *infile, const char *output) +{ + static size_t linesize = 0; + static char *line = NULL; + int i; + + /* Expect two log lines, one for accept, one for exit. */ + for (i = 0; i < 2; i++) { + ssize_t output_len = (ssize_t)strcspn(output, "\n"); + ssize_t len = getdelim(&line, &linesize, '\n', fp); + if (len == -1) { + sudo_warn("getdelim"); + return false; + } + if (line[len - 1] == '\n') + len--; + + if (len != output_len || strncmp(line, output, (size_t)len) != 0) { + fprintf(stderr, "%s: %s mismatch\n", infile, i ? "exit" : "accept"); + fprintf(stderr, "expected: %.*s\n", (int)len, line); + fprintf(stderr, "got : %.*s\n", (int)output_len, output); + return false; + } + if (i == 0) { + /* Skip past newline in accept record output. */ + output += output_len; + if (output[0] != '\n' || output[1] == '\0') { + sudo_warnx("missing exit record"); + return false; + } + output++; + } + } + + return true; +} + +int +main(int argc, char *argv[]) +{ + int ch, i, ntests = 0, errors = 0; + struct sudo_lbuf lbuf; + bool cat = false; + + initprogname(argc > 0 ? argv[0] : "store_sudo_test"); + + while ((ch = getopt(argc, argv, "v")) != -1) { + switch (ch) { + case 'c': + cat = true; + break; + case 'v': + /* ignored */ + break; + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc < 1) + usage(); + + sudo_lbuf_init(&lbuf, NULL, 0, NULL, 0); + for (i = 0; i < argc; i++) { + struct eventlog_json_object *root; + struct eventlog *evlog = NULL; + const char *infile = argv[i]; + const char *outfile = argv[i]; + char pathbuf[PATH_MAX]; + FILE *infp = NULL; + FILE *outfp = NULL; + size_t len; + + ntests++; + + /* Parse input file. */ + if ((infp = fopen(infile, "r")) == NULL) { + sudo_warn("%s", argv[i]); + errors++; + continue; + } + root = eventlog_json_read(infp, infile); + if (root == NULL) { + errors++; + goto next; + } + + /* Convert JSON to event log. */ + evlog = calloc(1, sizeof(*evlog)); + if (evlog == NULL) { + sudo_warnx("%s: %s", __func__, "unable to allocate memory"); + errors++; + goto next; + } + if (!eventlog_json_parse(root, evlog)) { + errors++; + goto next; + } + + /* Format event log in sudo log format. */ + if (!eventlog_store_sudo(EVLOG_ACCEPT, evlog, &lbuf)) { + errors++; + goto next; + } + sudo_lbuf_append(&lbuf, "\n"); + if (!eventlog_store_sudo(EVLOG_EXIT, evlog, &lbuf)) { + errors++; + goto next; + } + sudo_lbuf_append(&lbuf, "\n"); + + /* Write the formatted output to stdout for -c (cat) */ + if (cat) { + puts(lbuf.buf); + fflush(stdout); + } + + /* Check for a .out.ok file in the same location as the .in file. */ + len = strlen(infile); + if (len < sizeof(".json.in")) { + sudo_warnx("%s must end in .json.in", infile); + errors++; + goto next; + } + len -= sizeof(".json.in") - 1; + if (strcmp(&infile[len], ".json.in") != 0) { + sudo_warnx("%s must end in .json.in", infile); + errors++; + goto next; + } + snprintf(pathbuf, sizeof(pathbuf), "%.*s.sudo.out.ok", + (int)len, infile); + if ((outfp = fopen(pathbuf, "r")) == NULL) { + sudo_warn("%s", pathbuf); + errors++; + goto next; + } + + /* Compare output to expected output. */ + if (!compare(outfp, outfile, lbuf.buf)) + errors++; + +next: + lbuf.len = 0; + eventlog_json_free(root); + eventlog_free(evlog); + if (infp != NULL) + fclose(infp); + if (outfp != NULL && outfp != infp) + fclose(outfp); + } + sudo_lbuf_destroy(&lbuf); + + if (ntests != 0) { + printf("%s: %d test%s run, %d errors, %d%% success rate\n", + getprogname(), ntests, ntests == 1 ? "" : "s", errors, + (ntests - errors) * 100 / ntests); + } + + return errors; +} diff --git a/lib/eventlog/regress/eventlog_store/test1.json.in b/lib/eventlog/regress/eventlog_store/test1.json.in new file mode 100644 index 0000000..0e73df9 --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test1.json.in @@ -0,0 +1,52 @@ +{ + "uuid": "94109a6eb8-9bed-41ba-0ff1-79926f3947", + "server_time": { + "seconds": 1677638673, + "nanoseconds": 98769807, + "iso8601": "20230301024433Z", + "localtime": "Tue Feb 28 19:44:33 MST 2023" + }, + "submit_time": { + "seconds": 1677638673, + "nanoseconds": 93789768, + "iso8601": "20230301024433Z", + "localtime": "Tue Feb 28 19:44:33 MST 2023" + }, + "peeraddr": "172.30.200.2", + "iolog_path": "/var/log/sudo-logsrvd/millert/00/03/FI", + "iolog_file": "00/03/FI", + "columns": 80, + "command": "/usr/bin/ci", + "lines": 24, + "runargv": [ + "ci", + "-u", + "aliases\n" + ], + "runenv": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=tmux", + "LANG=en_US.UTF-8", + "MAIL=/var/mail/root", + "LOGNAME=root", + "USER=root", + "HOME=/root", + "SHELL=/bin/bash", + "SUDO_COMMAND=/usr/bin/ci -u aliases", + "SUDO_USER=millert", + "SUDO_UID=8036", + "SUDO_GID=20" + ], + "runenv_override": [ + "KRB5CCNAME=bogus", + "LD_LIBRARY_PATH=/opt/sudo/libexec" + ], + "runuid": 0, + "runuser": "root", + "source": "/etc/sudoers:89:24", + "submitcwd": "/etc/mail", + "submithost": "xerxes.sudo.ws", + "submituser": "millert", + "ttyname": "/dev/ttypb", + "exit_value": 1 +} diff --git a/lib/eventlog/regress/eventlog_store/test1.json.out.ok b/lib/eventlog/regress/eventlog_store/test1.json.out.ok new file mode 100644 index 0000000..2ddc8c5 --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test1.json.out.ok @@ -0,0 +1,31 @@ +{ + "submituser": "millert", + "command": "/usr/bin/ci", + "runuser": "root", + "source": "/etc/sudoers:89:24", + "ttyname": "/dev/ttypb", + "submithost": "xerxes.sudo.ws", + "submitcwd": "/etc/mail", + "runuid": 0, + "columns": 80, + "lines": 24, + "runargv": [ + "ci", + "-u", + "aliases\n" + ], + "runenv": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=tmux", + "LANG=en_US.UTF-8", + "MAIL=/var/mail/root", + "LOGNAME=root", + "USER=root", + "HOME=/root", + "SHELL=/bin/bash", + "SUDO_COMMAND=/usr/bin/ci -u aliases", + "SUDO_USER=millert", + "SUDO_UID=8036", + "SUDO_GID=20" + ] +} diff --git a/lib/eventlog/regress/eventlog_store/test1.sudo.out.ok b/lib/eventlog/regress/eventlog_store/test1.sudo.out.ok new file mode 100644 index 0000000..17c344e --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test1.sudo.out.ok @@ -0,0 +1,2 @@ +HOST=xerxes.sudo.ws ; TTY=ttypb ; CWD=/etc/mail ; USER=root ; TSID=0003FI ; ENV=KRB5CCNAME=bogus LD_LIBRARY_PATH=/opt/sudo/libexec ; COMMAND=/usr/bin/ci -u aliases#012 +HOST=xerxes.sudo.ws ; TTY=ttypb ; CWD=/etc/mail ; USER=root ; TSID=0003FI ; ENV=KRB5CCNAME=bogus LD_LIBRARY_PATH=/opt/sudo/libexec ; COMMAND=/usr/bin/ci -u aliases#012 ; EXIT=1 diff --git a/lib/eventlog/regress/eventlog_store/test2.json.in b/lib/eventlog/regress/eventlog_store/test2.json.in new file mode 100644 index 0000000..6af3a31 --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test2.json.in @@ -0,0 +1,48 @@ +{ + "uuid": "a17521dd52-1b7f-4ca1-5086-6957336362", + "server_time": { + "seconds": 1671070212, + "nanoseconds": 246006550, + "iso8601": "20221215021012Z", + "localtime": "Wed Dec 14 19:10:12 MST 2022" + }, + "submit_time": { + "seconds": 1671070212, + "nanoseconds": 243017337, + "iso8601": "20221215021012Z", + "localtime": "Wed Dec 14 19:10:12 MST 2022" + }, + "peeraddr": "172.30.200.2", + "iolog_path": "/var/log/sudo-logsrvd/millert/00/03/5Q", + "iolog_file": "00/03/5Q", + "columns": 80, + "command": "/usr/bin/id", + "lines": 24, + "runargv": [ + "id" + ], + "runenv": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=tmux", + "LANG=en_US.UTF-8", + "MAIL=/var/mail/root", + "LOGNAME=root", + "USER=root", + "HOME=/root", + "SHELL=/bin/bash", + "SUDO_COMMAND=/usr/bin/id", + "SUDO_USER=millert", + "SUDO_UID=8036", + "SUDO_GID=20" + ], + "runenv_override": [ + "KRB5CCNAME=bogus" + ], + "runuid": 0, + "runuser": "root", + "source": "sudoRole %wheel", + "submitcwd": "/usr/src/local/millert/sudo/trunk", + "submithost": "xerxes.sudo.ws", + "submituser": "millert", + "ttyname": "/dev/ttyp0" +} diff --git a/lib/eventlog/regress/eventlog_store/test2.json.out.ok b/lib/eventlog/regress/eventlog_store/test2.json.out.ok new file mode 100644 index 0000000..e26290c --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test2.json.out.ok @@ -0,0 +1,29 @@ +{ + "submituser": "millert", + "command": "/usr/bin/id", + "runuser": "root", + "source": "sudoRole %wheel", + "ttyname": "/dev/ttyp0", + "submithost": "xerxes.sudo.ws", + "submitcwd": "/usr/src/local/millert/sudo/trunk", + "runuid": 0, + "columns": 80, + "lines": 24, + "runargv": [ + "id" + ], + "runenv": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=tmux", + "LANG=en_US.UTF-8", + "MAIL=/var/mail/root", + "LOGNAME=root", + "USER=root", + "HOME=/root", + "SHELL=/bin/bash", + "SUDO_COMMAND=/usr/bin/id", + "SUDO_USER=millert", + "SUDO_UID=8036", + "SUDO_GID=20" + ] +} diff --git a/lib/eventlog/regress/eventlog_store/test2.sudo.out.ok b/lib/eventlog/regress/eventlog_store/test2.sudo.out.ok new file mode 100644 index 0000000..51faf04 --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test2.sudo.out.ok @@ -0,0 +1,2 @@ +HOST=xerxes.sudo.ws ; TTY=ttyp0 ; CWD=/usr/src/local/millert/sudo/trunk ; USER=root ; TSID=00035Q ; ENV=KRB5CCNAME=bogus ; COMMAND=/usr/bin/id +HOST=xerxes.sudo.ws ; TTY=ttyp0 ; CWD=/usr/src/local/millert/sudo/trunk ; USER=root ; TSID=00035Q ; ENV=KRB5CCNAME=bogus ; COMMAND=/usr/bin/id ; EXIT=0 diff --git a/lib/eventlog/regress/eventlog_store/test3.json.in b/lib/eventlog/regress/eventlog_store/test3.json.in new file mode 100644 index 0000000..184333f --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test3.json.in @@ -0,0 +1,49 @@ +{ + "uuid": "54e6806305-0f50-44bf-fe6a-c8fa7a65ac", + "server_time": { + "seconds": 1678475729, + "nanoseconds": 286796437, + "iso8601": "20230310191529Z", + "localtime": "Fri Mar 10 12:15:29 MST 2023" + }, + "submit_time": { + "seconds": 1633116433, + "nanoseconds": 682537651, + "iso8601": "20211001192713Z", + "localtime": "Fri Oct 1 13:27:13 MDT 2021" + }, + "peeraddr": "172.30.200.50", + "iolog_path": "/var/log/sudo-logsrvd/millert/00/00/5H", + "iolog_file": "00/00/5H", + "columns": 80, + "command": "/usr/bin/find", + "lines": 24, + "runargv": [ + "find", + "build/out/sudoers/" + ], + "runenv": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=tmux", + "LANG=en_US.UTF-8", + "MAIL=/var/mail/root", + "LOGNAME=root", + "USER=root", + "HOME=/root", + "SHELL=/bin/bash", + "SUDO_COMMAND=/usr/bin/find build/out/sudoers/", + "SUDO_USER=millert", + "SUDO_UID=8036", + "SUDO_GID=20" + ], + "runuid": 0, + "runuser": "root", + "source": "/etc/sudoers:89:24", + "submitcwd": "/home/millert/sudo/oss-fuzz", + "submithost": "linux-build", + "submituser": "millert", + "ttyname": "/dev/pts/1", + "exit_value": 131, + "signal": "QUIT", + "dumped_core": true +} diff --git a/lib/eventlog/regress/eventlog_store/test3.json.out.ok b/lib/eventlog/regress/eventlog_store/test3.json.out.ok new file mode 100644 index 0000000..967a75c --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test3.json.out.ok @@ -0,0 +1,30 @@ +{ + "submituser": "millert", + "command": "/usr/bin/find", + "runuser": "root", + "source": "/etc/sudoers:89:24", + "ttyname": "/dev/pts/1", + "submithost": "linux-build", + "submitcwd": "/home/millert/sudo/oss-fuzz", + "runuid": 0, + "columns": 80, + "lines": 24, + "runargv": [ + "find", + "build/out/sudoers/" + ], + "runenv": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=tmux", + "LANG=en_US.UTF-8", + "MAIL=/var/mail/root", + "LOGNAME=root", + "USER=root", + "HOME=/root", + "SHELL=/bin/bash", + "SUDO_COMMAND=/usr/bin/find build/out/sudoers/", + "SUDO_USER=millert", + "SUDO_UID=8036", + "SUDO_GID=20" + ] +} diff --git a/lib/eventlog/regress/eventlog_store/test3.sudo.out.ok b/lib/eventlog/regress/eventlog_store/test3.sudo.out.ok new file mode 100644 index 0000000..5f7fee2 --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test3.sudo.out.ok @@ -0,0 +1,2 @@ +HOST=linux-build ; TTY=pts/1 ; CWD=/home/millert/sudo/oss-fuzz ; USER=root ; TSID=00005H ; COMMAND=/usr/bin/find build/out/sudoers/ +HOST=linux-build ; TTY=pts/1 ; CWD=/home/millert/sudo/oss-fuzz ; USER=root ; TSID=00005H ; COMMAND=/usr/bin/find build/out/sudoers/ ; SIGNAL=QUIT ; EXIT=131 diff --git a/lib/eventlog/regress/eventlog_store/test4.json.in b/lib/eventlog/regress/eventlog_store/test4.json.in new file mode 100644 index 0000000..8836a44 --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test4.json.in @@ -0,0 +1,47 @@ +{ + "uuid": "0bf9f26a7c-5e8b-4f82-f6c1-24a49a254c", + "server_time": { + "seconds": 1677638637, + "nanoseconds": 369091862, + "iso8601": "20230301024357Z", + "localtime": "Tue Feb 28 19:43:57 MST 2023" + }, + "submit_time": { + "seconds": 1677638637, + "nanoseconds": 364571747, + "iso8601": "20230301024357Z", + "localtime": "Tue Feb 28 19:43:57 MST 2023" + }, + "peeraddr": "172.30.200.2", + "iolog_path": "/var/log/sudo-logsrvd/millert/00/03/FG", + "iolog_file": "00/03/FG", + "columns": 80, + "command": "/usr/bin/vi", + "lines": 24, + "runargv": [ + "vi", + "aliases" + ], + "runenv": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=tmux", + "LANG=en_US.UTF-8", + "MAIL=/var/mail/root", + "LOGNAME=root", + "USER=root", + "HOME=/root", + "SHELL=/bin/bash", + "SUDO_COMMAND=/usr/bin/vi aliases", + "SUDO_USER=millert", + "SUDO_UID=8036", + "SUDO_GID=20", + "KRB5CCNAME=bogus" + ], + "runuid": 0, + "runuser": "root", + "source": "/etc/sudoers:89:24", + "submitcwd": "/etc/mail", + "submithost": "xerxes.sudo.ws", + "submituser": "millert", + "ttyname": "/dev/ttypb" +} diff --git a/lib/eventlog/regress/eventlog_store/test4.json.out.ok b/lib/eventlog/regress/eventlog_store/test4.json.out.ok new file mode 100644 index 0000000..2f15940 --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test4.json.out.ok @@ -0,0 +1,31 @@ +{ + "submituser": "millert", + "command": "/usr/bin/vi", + "runuser": "root", + "source": "/etc/sudoers:89:24", + "ttyname": "/dev/ttypb", + "submithost": "xerxes.sudo.ws", + "submitcwd": "/etc/mail", + "runuid": 0, + "columns": 80, + "lines": 24, + "runargv": [ + "vi", + "aliases" + ], + "runenv": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=tmux", + "LANG=en_US.UTF-8", + "MAIL=/var/mail/root", + "LOGNAME=root", + "USER=root", + "HOME=/root", + "SHELL=/bin/bash", + "SUDO_COMMAND=/usr/bin/vi aliases", + "SUDO_USER=millert", + "SUDO_UID=8036", + "SUDO_GID=20", + "KRB5CCNAME=bogus" + ] +} diff --git a/lib/eventlog/regress/eventlog_store/test4.sudo.out.ok b/lib/eventlog/regress/eventlog_store/test4.sudo.out.ok new file mode 100644 index 0000000..c1589d0 --- /dev/null +++ b/lib/eventlog/regress/eventlog_store/test4.sudo.out.ok @@ -0,0 +1,2 @@ +HOST=xerxes.sudo.ws ; TTY=ttypb ; CWD=/etc/mail ; USER=root ; TSID=0003FG ; COMMAND=/usr/bin/vi aliases +HOST=xerxes.sudo.ws ; TTY=ttypb ; CWD=/etc/mail ; USER=root ; TSID=0003FG ; COMMAND=/usr/bin/vi aliases ; EXIT=0 diff --git a/lib/eventlog/regress/logwrap/check_wrap.c b/lib/eventlog/regress/logwrap/check_wrap.c new file mode 100644 index 0000000..15134f0 --- /dev/null +++ b/lib/eventlog/regress/logwrap/check_wrap.c @@ -0,0 +1,124 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2011-2013 Todd C. Miller <Todd.Miller@sudo.ws> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <unistd.h> + +#define SUDO_ERROR_WRAP 0 + +#include <sudo_compat.h> +#include <sudo_eventlog.h> +#include <sudo_fatal.h> +#include <sudo_plugin.h> +#include <sudo_util.h> + +sudo_dso_public int main(int argc, char *argv[]); + +sudo_noreturn static void +usage(void) +{ + fprintf(stderr, "usage: %s [-v] inputfile\n", getprogname()); + exit(EXIT_FAILURE); +} + +int +main(int argc, char *argv[]) +{ + int ch, lineno = 0, which = 0; + char *line, lines[2][2048]; + const char *infile; + unsigned int len; + FILE *fp; + + initprogname(argc > 0 ? argv[0] : "check_wrap"); + + while ((ch = getopt(argc, argv, "v")) != -1) { + switch (ch) { + case 'v': + /* ignored */ + break; + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + infile = argv[0]; + + fp = fopen(infile, "r"); + if (fp == NULL) + sudo_fatalx("unable to open %s", infile); + + /* + * Each test record consists of a log entry on one line and a list of + * line lengths to test it with on the next. E.g. + * + * Jun 30 14:49:51 : millert : TTY=ttypn ; PWD=/usr/src/local/millert/hg/sudo/trunk/plugins/sudoers ; USER=root ; TSID=0004LD ; COMMAND=/usr/local/sbin/visudo + * 60-80,40 + */ + while ((line = fgets(lines[which], sizeof(lines[which]), fp)) != NULL) { + char *cp, *last; + + line[strcspn(line, "\n")] = '\0'; + + /* If we read the 2nd line, parse list of line lengths and check. */ + if (which) { + lineno++; + for (cp = strtok_r(lines[1], ",", &last); cp != NULL; cp = strtok_r(NULL, ",", &last)) { + unsigned int maxlen; + const char *errstr; + char *dash; + + /* May be either a number or a range. */ + dash = strchr(cp, '-'); + if (dash != NULL) { + *dash = '\0'; + len = (unsigned int)sudo_strtonum(cp, 0, INT_MAX, &errstr); + if (errstr == NULL) + maxlen = (unsigned int)sudo_strtonum(dash + 1, 0, INT_MAX, &errstr); + } else { + len = maxlen = (unsigned int)sudo_strtonum(cp, 0, INT_MAX, &errstr); + } + if (errstr != NULL) { + sudo_fatalx("%s: invalid length on line %d", infile, lineno); + } + while (len <= maxlen) { + if (len == 0) { + puts("# word wrap disabled"); + } else { + printf("# word wrap at %u characters\n", len); + } + eventlog_writeln(stdout, lines[0], strlen(lines[0]), len); + len++; + } + } + } + which = !which; + } + + return EXIT_SUCCESS; +} diff --git a/lib/eventlog/regress/logwrap/check_wrap.in b/lib/eventlog/regress/logwrap/check_wrap.in new file mode 100644 index 0000000..e8e7081 --- /dev/null +++ b/lib/eventlog/regress/logwrap/check_wrap.in @@ -0,0 +1,4 @@ +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list users +0,60-80,120,140 +Jun 26 18:00:06 : millert : TTY=ttypm ; PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +0,60-80,120,140 diff --git a/lib/eventlog/regress/logwrap/check_wrap.out.ok b/lib/eventlog/regress/logwrap/check_wrap.out.ok new file mode 100644 index 0000000..55e9da8 --- /dev/null +++ b/lib/eventlog/regress/logwrap/check_wrap.out.ok @@ -0,0 +1,179 @@ +# word wrap disabled +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list users +# word wrap at 60 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 + ; PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 61 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 + ; PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 62 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 63 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 64 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 65 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 66 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 67 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool + list users +# word wrap at 68 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool + list users +# word wrap at 69 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool + list users +# word wrap at 70 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool + list users +# word wrap at 71 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool + list users +# word wrap at 72 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 73 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 74 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 75 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 76 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 77 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 78 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list users +# word wrap at 79 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list users +# word wrap at 80 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list users +# word wrap at 120 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 140 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list users +# word wrap disabled +Jun 26 18:00:06 : millert : TTY=ttypm ; PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 60 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 61 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 62 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 63 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 64 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 65 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 66 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 67 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 68 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 69 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 70 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT + ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 71 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT + ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 72 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 73 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 74 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 75 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 76 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 77 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 78 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 79 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 80 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; PWD=/usr/src/local/millert/hg/sudo/build + ; USER=root ; TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 120 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 140 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; COMMAND=/bin/rm + /root/.bash_profile diff --git a/lib/eventlog/regress/parse_json/check_parse_json.c b/lib/eventlog/regress/parse_json/check_parse_json.c new file mode 100644 index 0000000..496fac9 --- /dev/null +++ b/lib/eventlog/regress/parse_json/check_parse_json.c @@ -0,0 +1,270 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2020 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 <limits.h> +#include <unistd.h> + +#define SUDO_ERROR_WRAP 0 + +#include <sudo_compat.h> +#include <sudo_eventlog.h> +#include <sudo_fatal.h> +#include <sudo_util.h> + +#include <parse_json.h> + +sudo_dso_public int main(int argc, char *argv[]); + +static bool +json_print_object(struct json_container *jsonc, struct eventlog_json_object *object) +{ + struct json_item *item; + struct json_value json_value; + bool ret = false; + + TAILQ_FOREACH(item, &object->items, entries) { + switch (item->type) { + case JSON_STRING: + json_value.type = JSON_STRING; + json_value.u.string = item->u.string; + if (!sudo_json_add_value(jsonc, item->name, &json_value)) + goto oom; + break; + case JSON_NUMBER: + json_value.type = JSON_NUMBER; + json_value.u.number = item->u.number; + if (!sudo_json_add_value(jsonc, item->name, &json_value)) + goto oom; + break; + case JSON_OBJECT: + if (!sudo_json_open_object(jsonc, item->name)) + goto oom; + if (!json_print_object(jsonc, &item->u.child)) + goto done; + if (!sudo_json_close_object(jsonc)) + goto oom; + break; + case JSON_ARRAY: + if (!sudo_json_open_array(jsonc, item->name)) + goto oom; + if (!json_print_object(jsonc, &item->u.child)) + goto done; + if (!sudo_json_close_array(jsonc)) + goto oom; + break; + case JSON_BOOL: + json_value.type = JSON_BOOL; + json_value.u.boolean = item->u.boolean; + if (!sudo_json_add_value(jsonc, item->name, &json_value)) + goto oom; + break; + case JSON_NULL: + json_value.type = JSON_NULL; + if (!sudo_json_add_value(jsonc, item->name, &json_value)) + goto oom; + break; + default: + sudo_warnx("unsupported JSON type %d", item->type); + goto done; + } + } + + ret = true; + goto done; + +oom: + sudo_warnx("%s: %s", __func__, "unable to allocate memory"); +done: + return ret; +} + +static bool +json_format(struct json_container *jsonc, struct eventlog_json_object *object) +{ + struct json_item *item; + bool ret = false; + + /* First object holds all the actual data. */ + item = TAILQ_FIRST(&object->items); + if (item->type != JSON_OBJECT) { + sudo_warnx("expected JSON_OBJECT, got %d", item->type); + goto done; + } + object = &item->u.child; + + if (!json_print_object(jsonc, object)) + goto done; + + ret = true; + +done: + return ret; +} + +sudo_noreturn static void +usage(void) +{ + fprintf(stderr, "usage: %s [-cv] input_file ...\n", + getprogname()); + exit(EXIT_FAILURE); +} + +static bool +compare(FILE *fp, const char *infile, struct json_container *jsonc) +{ + const char *cp; + unsigned int lineno = 0; + size_t linesize = 0; + char *line = NULL; + ssize_t len; + + cp = sudo_json_get_buf(jsonc); + + while ((len = getdelim(&line, &linesize, '\n', fp)) != -1) { + lineno++; + + /* skip open/close brace, not present in formatted output */ + if (lineno == 1 && strcmp(line, "{\n") == 0) + continue; + if (*cp == '\0' && strcmp(line, "}\n") == 0) + continue; + + /* Ignore newlines in output to make comparison easier. */ + if (*cp == '\n') + cp++; + if (line[len - 1] == '\n') + len--; + + if (strncmp(line, cp, (size_t)len) != 0) { + fprintf(stderr, "%s: mismatch on line %u\n", infile, lineno); + fprintf(stderr, "expected: %s", line); + fprintf(stderr, "got : %.*s\n", (int)len, cp); + return false; + } + cp += len; + } + free(line); + + return true; +} + +int +main(int argc, char *argv[]) +{ + int ch, i, ntests = 0, errors = 0; + bool cat = false; + + initprogname(argc > 0 ? argv[0] : "check_parse_json"); + + while ((ch = getopt(argc, argv, "cv")) != -1) { + switch (ch) { + case 'c': + cat = true; + break; + case 'v': + /* ignored */ + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc < 1) + usage(); + + for (i = 0; i < argc; i++) { + struct eventlog_json_object *root; + struct json_container jsonc; + const char *infile = argv[i]; + const char *outfile = argv[i]; + const char *cp; + char pathbuf[PATH_MAX]; + FILE *infp = NULL; + FILE *outfp = NULL; + + ntests++; + + if (!sudo_json_init(&jsonc, 4, false, true, true)) { + errors++; + continue; + } + + /* Parse input file. */ + if ((infp = fopen(infile, "r")) == NULL) { + sudo_warn("%s", argv[i]); + errors++; + continue; + } + root = eventlog_json_read(infp, infile); + if (root == NULL) { + errors++; + goto next; + } + + /* Format as pretty-printed JSON */ + if (!json_format(&jsonc, root)) { + errors++; + goto next; + } + + /* Check for a .out.ok file in the same location as the .in file. */ + cp = strrchr(infile, '.'); + if (cp != NULL && strcmp(cp, ".in") == 0) { + snprintf(pathbuf, sizeof(pathbuf), "%.*s.out.ok", + (int)(cp - infile), infile); + if ((outfp = fopen(pathbuf, "r")) != NULL) + outfile = pathbuf; + } + if (outfp == NULL) + outfp = infp; + + /* Compare output to expected output. */ + rewind(outfp); + if (!compare(outfp, outfile, &jsonc)) + errors++; + + /* Write the formatted output to stdout for -c (cat) */ + if (cat) { + fprintf(stdout, "{%s\n}\n", sudo_json_get_buf(&jsonc)); + fflush(stdout); + } + +next: + eventlog_json_free(root); + sudo_json_free(&jsonc); + if (infp != NULL) + fclose(infp); + if (outfp != NULL && outfp != infp) + fclose(outfp); + } + + if (ntests != 0) { + printf("%s: %d test%s run, %d errors, %d%% success rate\n", + getprogname(), ntests, ntests == 1 ? "" : "s", errors, + (ntests - errors) * 100 / ntests); + } + + return errors; +} diff --git a/lib/eventlog/regress/parse_json/test1.in b/lib/eventlog/regress/parse_json/test1.in new file mode 100644 index 0000000..8ad3689 --- /dev/null +++ b/lib/eventlog/regress/parse_json/test1.in @@ -0,0 +1,34 @@ +{ + "timestamp": { + "seconds": 1584993067, + "nanoseconds": 880288287 + }, + "columns": 80, + "command": "/usr/bin/make", + "lines": 24, + "runargv": [ + "make", + "test" + ], + "runenv": [ + "LANG=en_US.UTF-8", + "PATH=/bin:/sbin:/usr/games:/usr/bin:/usr/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin", + "TERM=vt100", + "MAIL=/var/mail/root", + "LOGNAME=root", + "USER=root", + "HOME=/root", + "SHELL=/bin/ksh", + "SUDO_COMMAND=/usr/bin/make test", + "SUDO_USER=millert", + "SUDO_UID=8036", + "SUDO_GID=20", + "A__z=\"*SHLVL" + ], + "runuid": 0, + "runuser": "root", + "submitcwd": "/home/test", + "submithost": "sudo.ws", + "submituser": "millert", + "ttyname": "/dev/console" +} diff --git a/lib/eventlog/regress/parse_json/test2.in b/lib/eventlog/regress/parse_json/test2.in new file mode 100644 index 0000000..df7170f --- /dev/null +++ b/lib/eventlog/regress/parse_json/test2.in @@ -0,0 +1,28 @@ +{ + "timestamp": { "seconds": 1584993067, "nanoseconds": 880288287 }, + "columns": 80, + "command": "/usr/bin/make", + "lines": 24, + "runargv": [ "make", "test" ], + "runenv": [ + "LANG=en_US.UTF-8", + "PATH=/bin:/sbin:/usr/games:/usr/bin:/usr/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin", + "TERM=vt100", + "MAIL=/var/mail/root", + "LOGNAME=root", + "USER=root", + "HOME=/root", + "SHELL=/bin/ksh", + "SUDO_COMMAND=/usr/bin/make test", + "SUDO_USER=millert", + "SUDO_UID=8036", + "SUDO_GID=20", + "A__z=\"*SHLVL" + ], + "runuid": 0, + "runuser": "root", + "submitcwd": "/home/test", + "submithost": "sudo.ws", + "submituser": "millert", + "ttyname": "/dev/console" +} diff --git a/lib/eventlog/regress/parse_json/test2.out.ok b/lib/eventlog/regress/parse_json/test2.out.ok new file mode 100644 index 0000000..8ad3689 --- /dev/null +++ b/lib/eventlog/regress/parse_json/test2.out.ok @@ -0,0 +1,34 @@ +{ + "timestamp": { + "seconds": 1584993067, + "nanoseconds": 880288287 + }, + "columns": 80, + "command": "/usr/bin/make", + "lines": 24, + "runargv": [ + "make", + "test" + ], + "runenv": [ + "LANG=en_US.UTF-8", + "PATH=/bin:/sbin:/usr/games:/usr/bin:/usr/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin", + "TERM=vt100", + "MAIL=/var/mail/root", + "LOGNAME=root", + "USER=root", + "HOME=/root", + "SHELL=/bin/ksh", + "SUDO_COMMAND=/usr/bin/make test", + "SUDO_USER=millert", + "SUDO_UID=8036", + "SUDO_GID=20", + "A__z=\"*SHLVL" + ], + "runuid": 0, + "runuser": "root", + "submitcwd": "/home/test", + "submithost": "sudo.ws", + "submituser": "millert", + "ttyname": "/dev/console" +} diff --git a/lib/eventlog/regress/parse_json/test3.in b/lib/eventlog/regress/parse_json/test3.in new file mode 100644 index 0000000..6f243e3 --- /dev/null +++ b/lib/eventlog/regress/parse_json/test3.in @@ -0,0 +1,22 @@ +{ + "true": false, + "false": true, + "number": 1234567890, + "null": null, + "string": "non\u0073ense", + "scope": { + "a": "b", + "bah": null + }, + "array1": [ + "foo", + "bar", + [ + 123, + null, + false, + "fizz", + "buzz" + ] + ] +} diff --git a/lib/eventlog/regress/parse_json/test3.out.ok b/lib/eventlog/regress/parse_json/test3.out.ok new file mode 100644 index 0000000..ea2df89 --- /dev/null +++ b/lib/eventlog/regress/parse_json/test3.out.ok @@ -0,0 +1,22 @@ +{ + "true": false, + "false": true, + "number": 1234567890, + "null": null, + "string": "nonsense", + "scope": { + "a": "b", + "bah": null + }, + "array1": [ + "foo", + "bar", + [ + 123, + null, + false, + "fizz", + "buzz" + ] + ] +} |