diff --git a/include/sudo_iolog.h b/include/sudo_iolog.h index d801b724f..4baba9019 100644 --- a/include/sudo_iolog.h +++ b/include/sudo_iolog.h @@ -109,7 +109,7 @@ bool expand_iolog_path(const char *inpath, char *path, size_t pathlen, const str bool iolog_parse_timing(const char *line, struct timing_closure *timing); char *iolog_parse_delay(const char *cp, struct timespec *delay, const char *decimal_point); int iolog_read_timing_record(struct iolog_file *iol, struct timing_closure *timing); -struct iolog_info *iolog_parse_loginfo(FILE *fp, const char *iolog_dir); +struct iolog_info *iolog_parse_loginfo(int dfd, const char *iolog_dir); void iolog_adjust_delay(struct timespec *delay, struct timespec *max_delay, double scale_factor); void iolog_free_loginfo(struct iolog_info *li); diff --git a/lib/iolog/iolog_util.c b/lib/iolog/iolog_util.c index c16cb0d3a..c731ee12b 100644 --- a/lib/iolog/iolog_util.c +++ b/lib/iolog/iolog_util.c @@ -61,14 +61,32 @@ static int timing_event_adj; struct iolog_info * -iolog_parse_loginfo(FILE *fp, const char *logfile) +iolog_parse_loginfo(int dfd, const char *iolog_dir) { char *buf = NULL, *cp, *ep; const char *errstr; size_t bufsize = 0, cwdsize = 0, cmdsize = 0; struct iolog_info *li = NULL; + FILE *fp = NULL; + int fd = -1; debug_decl(iolog_parse_loginfo, SUDO_DEBUG_UTIL); + if (dfd == -1) { + if ((dfd = open(iolog_dir, O_RDONLY)) == -1) { + sudo_warn("%s", iolog_dir); + goto bad; + } + fd = openat(dfd, "log", O_RDONLY, 0); + close(dfd); + } else { + fd = openat(dfd, "log", O_RDONLY, 0); + } + if (fd == -1 || (fp = fdopen(fd, "r")) == NULL) { + sudo_warn("%s/log", iolog_dir); + goto bad; + } + fd = -1; + /* * Info file has three lines: * 1) a log info line @@ -80,9 +98,11 @@ iolog_parse_loginfo(FILE *fp, const char *logfile) if (getdelim(&buf, &bufsize, '\n', fp) == -1 || getdelim(&li->cwd, &cwdsize, '\n', fp) == -1 || getdelim(&li->cmd, &cmdsize, '\n', fp) == -1) { - sudo_warn(U_("%s: invalid log file"), logfile); + sudo_warn(U_("%s: invalid log file"), iolog_dir); goto bad; } + fclose(fp); + fp = NULL; /* Strip the newline from the cwd and command. */ li->cwd[strcspn(li->cwd, "\n")] = '\0'; @@ -98,20 +118,20 @@ iolog_parse_loginfo(FILE *fp, const char *logfile) /* timestamp */ if ((ep = strchr(cp, ':')) == NULL) { - sudo_warn(U_("%s: time stamp field is missing"), logfile); + sudo_warn(U_("%s: time stamp field is missing"), iolog_dir); goto bad; } *ep = '\0'; li->tstamp = sudo_strtonum(cp, 0, TIME_T_MAX, &errstr); if (errstr != NULL) { - sudo_warn(U_("%s: time stamp %s: %s"), logfile, cp, errstr); + sudo_warn(U_("%s: time stamp %s: %s"), iolog_dir, cp, errstr); goto bad; } /* submit user */ cp = ep + 1; if ((ep = strchr(cp, ':')) == NULL) { - sudo_warn(U_("%s: user field is missing"), logfile); + sudo_warn(U_("%s: user field is missing"), iolog_dir); goto bad; } if ((li->user = strndup(cp, (size_t)(ep - cp))) == NULL) @@ -120,7 +140,7 @@ iolog_parse_loginfo(FILE *fp, const char *logfile) /* runas user */ cp = ep + 1; if ((ep = strchr(cp, ':')) == NULL) { - sudo_warn(U_("%s: runas user field is missing"), logfile); + sudo_warn(U_("%s: runas user field is missing"), iolog_dir); goto bad; } if ((li->runas_user = strndup(cp, (size_t)(ep - cp))) == NULL) @@ -129,7 +149,7 @@ iolog_parse_loginfo(FILE *fp, const char *logfile) /* runas group */ cp = ep + 1; if ((ep = strchr(cp, ':')) == NULL) { - sudo_warn(U_("%s: runas group field is missing"), logfile); + sudo_warn(U_("%s: runas group field is missing"), iolog_dir); goto bad; } if (cp != ep) { @@ -156,14 +176,14 @@ iolog_parse_loginfo(FILE *fp, const char *logfile) li->lines = sudo_strtonum(cp, 1, INT_MAX, &errstr); if (errstr != NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "%s: tty lines %s: %s", logfile, cp, errstr); + "%s: tty lines %s: %s", iolog_dir, cp, errstr); } if (ep != NULL) { cp = ep + 1; li->cols = sudo_strtonum(cp, 1, INT_MAX, &errstr); if (errstr != NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "%s: tty cols %s: %s", logfile, cp, errstr); + "%s: tty cols %s: %s", iolog_dir, cp, errstr); } } } @@ -171,6 +191,10 @@ iolog_parse_loginfo(FILE *fp, const char *logfile) debug_return_ptr(li); bad: + if (fd != -1) + close(fd); + if (fp != NULL) + fclose(fp); free(buf); iolog_free_loginfo(li); debug_return_ptr(NULL); diff --git a/logsrvd/sendlog.c b/logsrvd/sendlog.c index 7c94a74aa..7433df678 100644 --- a/logsrvd/sendlog.c +++ b/logsrvd/sendlog.c @@ -1487,8 +1487,7 @@ main(int argc, char *argv[]) struct timespec elapsed = { 0, 0 }; const char *iolog_id = NULL; const char *open_mode = "r"; - int ch, sock, iolog_dir_fd, fd; - FILE *fp; + int ch, sock, iolog_dir_fd; debug_decl_vars(main, SUDO_DEBUG_MAIN); #if defined(SUDO_DEVEL) && defined(__OpenBSD__) @@ -1582,12 +1581,7 @@ main(int argc, char *argv[]) } /* Parse I/O log info file. */ - fd = openat(iolog_dir_fd, "log", O_RDONLY, 0); - if (fd == -1 || (fp = fdopen(fd, "r")) == NULL) { - sudo_warn("%s/log", iolog_dir); - goto bad; - } - if ((log_info = iolog_parse_loginfo(fp, iolog_dir)) == NULL) + if ((log_info = iolog_parse_loginfo(iolog_dir_fd, iolog_dir)) == NULL) goto bad; if ((evbase = sudo_ev_base_alloc()) == NULL) diff --git a/plugins/sudoers/regress/iolog_plugin/check_iolog_plugin.c b/plugins/sudoers/regress/iolog_plugin/check_iolog_plugin.c index 42f1035ec..79437ef90 100644 --- a/plugins/sudoers/regress/iolog_plugin/check_iolog_plugin.c +++ b/plugins/sudoers/regress/iolog_plugin/check_iolog_plugin.c @@ -82,22 +82,15 @@ sudo_printf_int(int msg_type, const char *fmt, ...) } bool -validate_iolog_info(const char *logfile) +validate_iolog_info(const char *log_dir) { struct iolog_info *info; time_t now; - FILE *fp; time(&now); /* Parse log file. */ - if ((fp = fopen(logfile, "r")) == NULL) { - sudo_warn("%s", logfile); - return false; - } - info = iolog_parse_loginfo(fp, logfile); - fclose(fp); - if (info == NULL) + if ((info = iolog_parse_loginfo(-1, log_dir)) == NULL) return false; if (strcmp(info->cwd, "/") != 0) { @@ -262,8 +255,7 @@ test_endpoints(int *ntests, int *nerrors, const char *iolog_dir, char *envp[]) /* Validate I/O log info file. */ (*ntests)++; - snprintf(iolog_path, sizeof(iolog_path), "%s/log", iolog_dir); - if (!validate_iolog_info(iolog_path)) + if (!validate_iolog_info(iolog_dir)) (*nerrors)++; /* Test log_ttyout endpoint. */ diff --git a/plugins/sudoers/sudoreplay.c b/plugins/sudoers/sudoreplay.c index 62ecd1ad1..f688b0997 100644 --- a/plugins/sudoers/sudoreplay.c +++ b/plugins/sudoers/sudoreplay.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 2009-2019 Todd C. Miller + * Copyright (c) 2009-2020 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -207,7 +207,7 @@ __dso_public int main(int argc, char *argv[]); int main(int argc, char *argv[]) { - int ch, fd, i, iolog_dir_fd, len, exitcode = EXIT_FAILURE; + int ch, i, iolog_dir_fd, len, exitcode = EXIT_FAILURE; bool def_filter = true, listonly = false; bool interactive = true, suspend_wait = false, resize = true; const char *decimal, *id, *user = NULL, *pattern = NULL, *tty = NULL; @@ -215,7 +215,6 @@ main(int argc, char *argv[]) struct iolog_info *li; struct timespec max_delay_storage, *max_delay = NULL; double dval; - FILE *fp; debug_decl(main, SUDO_DEBUG_MAIN); #if defined(SUDO_DEVEL) && defined(__OpenBSD__) @@ -363,12 +362,8 @@ main(int argc, char *argv[]) } /* Parse log file. */ - fd = openat(iolog_dir_fd, "log", O_RDONLY, 0); - if (fd == -1 || (fp = fdopen(fd, "r")) == NULL) - sudo_fatal(U_("unable to open %s/%s"), iolog_dir, "log"); - if ((li = iolog_parse_loginfo(fp, iolog_dir)) == NULL) + if ((li = iolog_parse_loginfo(iolog_dir_fd, iolog_dir)) == NULL) goto done; - fclose(fp); printf(_("Replaying sudo session: %s"), li->cmd); /* Setup terminal if appropriate. */ @@ -1306,28 +1301,23 @@ match_expr(struct search_node_list *head, struct iolog_info *log, bool last_matc } static int -list_session(char *logfile, regex_t *re, const char *user, const char *tty) +list_session(char *log_dir, regex_t *re, const char *user, const char *tty) { char idbuf[7], *idstr, *cp; struct iolog_info *li = NULL; const char *timestr; int ret = -1; - FILE *fp; debug_decl(list_session, SUDO_DEBUG_UTIL); - if ((fp = fopen(logfile, "r")) == NULL) { - sudo_warn("%s", logfile); - goto done; - } - if ((li = iolog_parse_loginfo(fp, logfile)) == NULL) + if ((li = iolog_parse_loginfo(-1, log_dir)) == NULL) goto done; /* Match on search expression if there is one. */ if (!STAILQ_EMPTY(&search_expr) && !match_expr(&search_expr, li, true)) goto done; - /* Convert from /var/log/sudo-sessions/00/00/01/log to 000001 */ - cp = logfile + strlen(session_dir) + 1; + /* Convert from /var/log/sudo-sessions/00/00/01 to 000001 */ + cp = log_dir + strlen(session_dir) + 1; if (IS_IDLOG(cp)) { idbuf[0] = cp[0]; idbuf[1] = cp[1]; @@ -1338,8 +1328,7 @@ list_session(char *logfile, regex_t *re, const char *user, const char *tty) idbuf[6] = '\0'; idstr = idbuf; } else { - /* Not an id, just use the iolog_file portion. */ - cp[strlen(cp) - 4] = '\0'; + /* Not an id, use as-is. */ idstr = cp; } /* XXX - print lines + cols? */ @@ -1354,8 +1343,6 @@ list_session(char *logfile, regex_t *re, const char *user, const char *tty) ret = 0; done: - if (fp != NULL) - fclose(fp); iolog_free_loginfo(li); debug_return_int(ret); } @@ -1445,9 +1432,10 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty) /* Check for dir with a log file. */ if (lstat(pathbuf, &sb) == 0 && S_ISREG(sb.st_mode)) { + pathbuf[sdlen + len - 4] = '\0'; list_session(pathbuf, re, user, tty); } else { - /* Strip off "/log" and recurse if a dir. */ + /* Strip off "/log" and recurse if a non-log dir. */ pathbuf[sdlen + len - 4] = '\0'; if (checked_type || (lstat(pathbuf, &sb) == 0 && S_ISDIR(sb.st_mode)))