From: Todd C. Miller Date: Wed, 8 Sep 2004 15:48:23 +0000 (+0000) Subject: Use timespec throughout. X-Git-Tag: SUDO_1_6_8p1~26 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0f056c0d5f76f2be1dd29e0ab958ef10e2a3d95c;p=sudo Use timespec throughout. --- diff --git a/check.c b/check.c index 826d952d7..83bd15b11 100644 --- a/check.c +++ b/check.c @@ -149,11 +149,9 @@ update_timestamp(timestampdir, timestampfile) char *timestampdir; char *timestampfile; { - time_t now = time(NULL); - if (timestamp_uid != 0) set_perms(PERM_TIMESTAMP); - if (touch(-1, timestampfile ? timestampfile : timestampdir, now, 0) == -1) { + if (touch(-1, timestampfile ? timestampfile : timestampdir, NULL) == -1) { if (timestampfile) { int fd = open(timestampfile, O_WRONLY|O_CREAT|O_TRUNC, 0600); @@ -498,6 +496,7 @@ timestamp_status(timestampdir, timestampfile, user, make_dirs) if (def_timestamp_timeout < 0 && sb.st_mtime != 0) status = TS_CURRENT; else { + /* XXX - should use timespec here */ now = time(NULL); if (def_timestamp_timeout && now - sb.st_mtime < 60 * def_timestamp_timeout) { @@ -532,15 +531,14 @@ void remove_timestamp(remove) int remove; { - char *timestampdir; - char *timestampfile; - char *ts; + struct timespec ts; + char *timestampdir, *timestampfile, *path; int status; build_timestamp(×tampdir, ×tampfile); status = timestamp_status(timestampdir, timestampfile, user_name, FALSE); if (status == TS_OLD || status == TS_CURRENT) { - ts = timestampfile ? timestampfile : timestampdir; + path = timestampfile ? timestampfile : timestampdir; if (remove) { if (timestampfile) status = unlink(timestampfile); @@ -548,12 +546,14 @@ remove_timestamp(remove) status = rmdir(timestampdir); if (status == -1 && errno != ENOENT) { log_error(NO_EXIT, "can't remove %s (%s), will reset to Epoch", - ts, strerror(errno)); + path, strerror(errno)); remove = FALSE; } + } else { + timespecclear(&ts); + if (touch(-1, path, &ts) == -1) + err(1, "can't reset %s to Epoch", path); } - if (!remove && touch(-1, ts, 0, 0) == -1) - err(1, "can't reset %s to Epoch", ts); } free(timestampdir); diff --git a/compat.h b/compat.h index 471feef2a..6f0f8ba3f 100644 --- a/compat.h +++ b/compat.h @@ -239,4 +239,22 @@ struct timespec { }; #endif /* !HAVE_TIMESPEC */ +#ifndef timespecclear +# define timespecclear(ts) (ts)->tv_sec = (ts)->tv_nsec = 0 +#endif +#ifndef timespecisset +# define timespecisset(ts) ((ts)->tv_sec || (ts)->tv_nsec) +#endif +#ifndef timespecsub +# define timespecsub(minuend, subrahend, difference) \ + do { \ + (difference)->tv_sec = (minuend)->tv_sec - (subrahend)->tv_sec; \ + (difference)->tv_nsec = (minuend)->tv_nsec - (subrahend)->tv_nsec; \ + if ((difference)->tv_nsec < 0) { \ + (difference)->tv_nsec += 1000000000L; \ + (difference)->tv_sec--; \ + } \ + } while (0) +#endif + #endif /* _SUDO_COMPAT_H */ diff --git a/fileops.c b/fileops.c index fd8407efe..f36a7400f 100644 --- a/fileops.c +++ b/fileops.c @@ -43,24 +43,25 @@ static const char rcsid[] = "$Sudo$"; * Update the access and modify times on an fd or file. */ int -touch(fd, path, sec, nsec) +touch(fd, path, tsp) int fd; char *path; - time_t sec; - long nsec; + struct timespec *tsp; { struct timeval times[2]; - times[0].tv_sec = times[1].tv_sec = sec; - times[0].tv_usec = times[1].tv_usec = nsec; + if (tsp != NULL) { + times[0].tv_sec = times[1].tv_sec = tsp->tv_sec; + times[0].tv_usec = times[1].tv_usec = tsp->tv_nsec / 1000; + } #if defined(HAVE_FUTIME) || defined(HAVE_FUTIMES) if (fd != -1) - return(futimes(fd, times)); + return(futimes(fd, tsp ? times : NULL)); else #endif if (path != NULL) - return(utimes(path, times)); + return(utimes(path, tsp ? times : NULL)); else return(-1); } diff --git a/sudo.h b/sudo.h index b404129de..ff2491229 100644 --- a/sudo.h +++ b/sudo.h @@ -229,13 +229,14 @@ void dump_defaults __P((void)); void dump_auth_methods __P((void)); void init_envtables __P((void)); int lock_file __P((int, int)); -int touch __P((int, char *, time_t, long)); +int touch __P((int, char *, struct timespec *)); int user_is_exempt __P((void)); void set_fqdn __P((void)); int set_runaspw __P((char *)); char *sudo_getepw __P((const struct passwd *)); int pam_prep_user __P((struct passwd *)); void zero_bytes __P((volatile VOID *, size_t)); +int gettime __P((struct timespec *)); YY_DECL; /* Only provide extern declarations outside of sudo.c. */ diff --git a/sudo_edit.c b/sudo_edit.c index a1893565e..8f98bcf55 100644 --- a/sudo_edit.c +++ b/sudo_edit.c @@ -76,6 +76,7 @@ int sudo_edit(argc, argv) int i, ac, ofd, nargc, rval; sigaction_t sa; struct stat sb; + struct timespec ts1, ts2; struct tempfile { char *tfile; char *ofile; @@ -162,11 +163,12 @@ int sudo_edit(argc, argv) * file's mtime. It is better than nothing and we only use the info * to determine whether or not a file has been modified. */ - if (touch(tf[i].tfd, NULL, tf[i].ots.tv_sec, tf[i].ots.tv_nsec) == -1) { + if (touch(tf[i].tfd, NULL, &tf[i].ots) == -1) { if (fstat(tf[i].tfd, &sb) == 0) { tf[i].ots.tv_sec = mtim_getsec(sb); tf[i].ots.tv_nsec = mtim_getnsec(sb); } + /* XXX - else error? */ } #endif } @@ -213,8 +215,10 @@ int sudo_edit(argc, argv) (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL); /* - * Fork and exec the editor as with the invoking user's creds. + * Fork and exec the editor as with the invoking user's creds, + * keeping track of the time spent in the editor. */ + gettime(&ts1); kidpid = fork(); if (kidpid == -1) { warn("fork"); @@ -252,6 +256,7 @@ int sudo_edit(argc, argv) break; } } while (pid != -1 || errno == EINTR); + gettime(&ts2); if (pid == -1 || !WIFEXITED(i)) rval = 1; else @@ -270,10 +275,17 @@ int sudo_edit(argc, argv) if (tf[i].osize == sb.st_size && tf[i].ots.tv_sec == mtim_getsec(sb) && tf[i].ots.tv_nsec == mtim_getnsec(sb)) { - warnx("%s unchanged", tf[i].ofile); - unlink(tf[i].tfile); - close(tf[i].tfd); - continue; + /* + * If mtime and size match but the user spent no measurable + * time in the editor we can't tell if the file was changed. + */ + timespecsub(&ts1, &ts2, &ts2); + if (timespecisset(&ts2)) { + warnx("%s unchanged", tf[i].ofile); + unlink(tf[i].tfile); + close(tf[i].tfd); + continue; + } } } #endif diff --git a/visudo.c b/visudo.c index cef880ee7..b555ae968 100644 --- a/visudo.c +++ b/visudo.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifndef __TANDEM # include #endif @@ -130,8 +131,10 @@ main(argc, argv) int stmp_fd; /* stmp file descriptor */ int n; /* length parameter */ int ch; /* getopt char */ - time_t now; /* time now */ - struct stat stmp_sb, sudoers_sb; /* to check for changes */ + struct timespec ts1, ts2; /* time before and after edit */ + struct timespec sudoers_mtim; /* starting mtime of sudoers file */ + off_t sudoers_size; /* starting size of sudoers file */ + struct stat sb; /* stat buffer */ /* Warn about aliases that are used before being defined. */ pedantic = 1; @@ -192,11 +195,14 @@ main(argc, argv) if (!lock_file(sudoers_fd, SUDO_TLOCK)) errx(1, "sudoers file busy, try again later"); #ifdef HAVE_FSTAT - if (fstat(sudoers_fd, &sudoers_sb) == -1) + if (fstat(sudoers_fd, &sb) == -1) #else - if (stat(sudoers, &sudoers_sb) == -1) + if (stat(sudoers, &sb) == -1) #endif err(1, "can't stat %s", sudoers); + sudoers_size = sb.st_size; + sudoers_mtim.tv_sec = mtim_getsec(sb); + sudoers_mtim.tv_nsec = mtim_getnsec(sb); /* * Open sudoers temp file. @@ -209,7 +215,7 @@ main(argc, argv) setup_signals(); /* Copy sudoers -> stmp and reset the mtime */ - if (sudoers_sb.st_size) { + if (sudoers_size) { while ((n = read(sudoers_fd, buf, sizeof(buf))) > 0) if (write(stmp_fd, buf, n) != n) err(1, "write error"); @@ -220,7 +226,7 @@ main(argc, argv) write(stmp_fd, buf, 1); } - (void) touch(stmp_fd, stmp, sudoers_sb.st_mtime, 0); + (void) touch(stmp_fd, stmp, &sudoers_mtim); (void) close(stmp_fd); /* Parse sudoers to pull in editor and env_editor conf values. */ @@ -354,17 +360,18 @@ main(argc, argv) * XPG4 specifies that vi's exit value is a function of the * number of errors during editing (?!?!). */ - now = time(NULL); + gettime(&ts1); if (run_command(Editor, av) != -1) { + gettime(&ts2); /* * Sanity checks. */ - if (stat(stmp, &stmp_sb) < 0) { + if (stat(stmp, &sb) < 0) { warnx("cannot stat temporary file (%s), %s unchanged", stmp, sudoers); Exit(-1); } - if (stmp_sb.st_size == 0) { + if (sb.st_size == 0) { warnx("zero length temporary file (%s), %s unchanged", stmp, sudoers); Exit(-1); @@ -412,7 +419,7 @@ main(argc, argv) switch (whatnow()) { case 'Q' : parse_error = FALSE; /* ignore parse error */ break; - case 'x' : if (sudoers_sb.st_size == 0) + case 'x' : if (sudoers_size == 0) unlink(sudoers); Exit(0); break; @@ -423,10 +430,18 @@ main(argc, argv) /* * If the user didn't change the temp file, just unlink it. */ - if (sudoers_sb.st_mtime != now && sudoers_sb.st_mtime == stmp_sb.st_mtime && - sudoers_sb.st_size == stmp_sb.st_size) { - warnx("sudoers file unchanged"); - Exit(0); + if (sudoers_size == sb.st_size && + sudoers_mtim.tv_sec == mtim_getsec(sb) && + sudoers_mtim.tv_nsec == mtim_getnsec(sb)) { + /* + * If mtime and size match but the user spent no measurable + * time in the editor we can't tell if the file was changed. + */ + timespecsub(&ts1, &ts2, &ts2); + if (timespecisset(&ts2)) { + warnx("sudoers file unchanged"); + Exit(0); + } } /*