Use timespec throughout.
This commit is contained in:
20
check.c
20
check.c
@@ -149,11 +149,9 @@ update_timestamp(timestampdir, timestampfile)
|
|||||||
char *timestampdir;
|
char *timestampdir;
|
||||||
char *timestampfile;
|
char *timestampfile;
|
||||||
{
|
{
|
||||||
time_t now = time(NULL);
|
|
||||||
|
|
||||||
if (timestamp_uid != 0)
|
if (timestamp_uid != 0)
|
||||||
set_perms(PERM_TIMESTAMP);
|
set_perms(PERM_TIMESTAMP);
|
||||||
if (touch(-1, timestampfile ? timestampfile : timestampdir, now, 0) == -1) {
|
if (touch(-1, timestampfile ? timestampfile : timestampdir, NULL) == -1) {
|
||||||
if (timestampfile) {
|
if (timestampfile) {
|
||||||
int fd = open(timestampfile, O_WRONLY|O_CREAT|O_TRUNC, 0600);
|
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)
|
if (def_timestamp_timeout < 0 && sb.st_mtime != 0)
|
||||||
status = TS_CURRENT;
|
status = TS_CURRENT;
|
||||||
else {
|
else {
|
||||||
|
/* XXX - should use timespec here */
|
||||||
now = time(NULL);
|
now = time(NULL);
|
||||||
if (def_timestamp_timeout &&
|
if (def_timestamp_timeout &&
|
||||||
now - sb.st_mtime < 60 * def_timestamp_timeout) {
|
now - sb.st_mtime < 60 * def_timestamp_timeout) {
|
||||||
@@ -532,15 +531,14 @@ void
|
|||||||
remove_timestamp(remove)
|
remove_timestamp(remove)
|
||||||
int remove;
|
int remove;
|
||||||
{
|
{
|
||||||
char *timestampdir;
|
struct timespec ts;
|
||||||
char *timestampfile;
|
char *timestampdir, *timestampfile, *path;
|
||||||
char *ts;
|
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
build_timestamp(×tampdir, ×tampfile);
|
build_timestamp(×tampdir, ×tampfile);
|
||||||
status = timestamp_status(timestampdir, timestampfile, user_name, FALSE);
|
status = timestamp_status(timestampdir, timestampfile, user_name, FALSE);
|
||||||
if (status == TS_OLD || status == TS_CURRENT) {
|
if (status == TS_OLD || status == TS_CURRENT) {
|
||||||
ts = timestampfile ? timestampfile : timestampdir;
|
path = timestampfile ? timestampfile : timestampdir;
|
||||||
if (remove) {
|
if (remove) {
|
||||||
if (timestampfile)
|
if (timestampfile)
|
||||||
status = unlink(timestampfile);
|
status = unlink(timestampfile);
|
||||||
@@ -548,12 +546,14 @@ remove_timestamp(remove)
|
|||||||
status = rmdir(timestampdir);
|
status = rmdir(timestampdir);
|
||||||
if (status == -1 && errno != ENOENT) {
|
if (status == -1 && errno != ENOENT) {
|
||||||
log_error(NO_EXIT, "can't remove %s (%s), will reset to Epoch",
|
log_error(NO_EXIT, "can't remove %s (%s), will reset to Epoch",
|
||||||
ts, strerror(errno));
|
path, strerror(errno));
|
||||||
remove = FALSE;
|
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);
|
free(timestampdir);
|
||||||
|
18
compat.h
18
compat.h
@@ -239,4 +239,22 @@ struct timespec {
|
|||||||
};
|
};
|
||||||
#endif /* !HAVE_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 */
|
#endif /* _SUDO_COMPAT_H */
|
||||||
|
15
fileops.c
15
fileops.c
@@ -43,24 +43,25 @@ static const char rcsid[] = "$Sudo$";
|
|||||||
* Update the access and modify times on an fd or file.
|
* Update the access and modify times on an fd or file.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
touch(fd, path, sec, nsec)
|
touch(fd, path, tsp)
|
||||||
int fd;
|
int fd;
|
||||||
char *path;
|
char *path;
|
||||||
time_t sec;
|
struct timespec *tsp;
|
||||||
long nsec;
|
|
||||||
{
|
{
|
||||||
struct timeval times[2];
|
struct timeval times[2];
|
||||||
|
|
||||||
times[0].tv_sec = times[1].tv_sec = sec;
|
if (tsp != NULL) {
|
||||||
times[0].tv_usec = times[1].tv_usec = nsec;
|
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 defined(HAVE_FUTIME) || defined(HAVE_FUTIMES)
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
return(futimes(fd, times));
|
return(futimes(fd, tsp ? times : NULL));
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
if (path != NULL)
|
if (path != NULL)
|
||||||
return(utimes(path, times));
|
return(utimes(path, tsp ? times : NULL));
|
||||||
else
|
else
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
3
sudo.h
3
sudo.h
@@ -229,13 +229,14 @@ void dump_defaults __P((void));
|
|||||||
void dump_auth_methods __P((void));
|
void dump_auth_methods __P((void));
|
||||||
void init_envtables __P((void));
|
void init_envtables __P((void));
|
||||||
int lock_file __P((int, int));
|
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));
|
int user_is_exempt __P((void));
|
||||||
void set_fqdn __P((void));
|
void set_fqdn __P((void));
|
||||||
int set_runaspw __P((char *));
|
int set_runaspw __P((char *));
|
||||||
char *sudo_getepw __P((const struct passwd *));
|
char *sudo_getepw __P((const struct passwd *));
|
||||||
int pam_prep_user __P((struct passwd *));
|
int pam_prep_user __P((struct passwd *));
|
||||||
void zero_bytes __P((volatile VOID *, size_t));
|
void zero_bytes __P((volatile VOID *, size_t));
|
||||||
|
int gettime __P((struct timespec *));
|
||||||
YY_DECL;
|
YY_DECL;
|
||||||
|
|
||||||
/* Only provide extern declarations outside of sudo.c. */
|
/* Only provide extern declarations outside of sudo.c. */
|
||||||
|
24
sudo_edit.c
24
sudo_edit.c
@@ -76,6 +76,7 @@ int sudo_edit(argc, argv)
|
|||||||
int i, ac, ofd, nargc, rval;
|
int i, ac, ofd, nargc, rval;
|
||||||
sigaction_t sa;
|
sigaction_t sa;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
struct timespec ts1, ts2;
|
||||||
struct tempfile {
|
struct tempfile {
|
||||||
char *tfile;
|
char *tfile;
|
||||||
char *ofile;
|
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
|
* file's mtime. It is better than nothing and we only use the info
|
||||||
* to determine whether or not a file has been modified.
|
* 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) {
|
if (fstat(tf[i].tfd, &sb) == 0) {
|
||||||
tf[i].ots.tv_sec = mtim_getsec(sb);
|
tf[i].ots.tv_sec = mtim_getsec(sb);
|
||||||
tf[i].ots.tv_nsec = mtim_getnsec(sb);
|
tf[i].ots.tv_nsec = mtim_getnsec(sb);
|
||||||
}
|
}
|
||||||
|
/* XXX - else error? */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -213,8 +215,10 @@ int sudo_edit(argc, argv)
|
|||||||
(void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
|
(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();
|
kidpid = fork();
|
||||||
if (kidpid == -1) {
|
if (kidpid == -1) {
|
||||||
warn("fork");
|
warn("fork");
|
||||||
@@ -252,6 +256,7 @@ int sudo_edit(argc, argv)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (pid != -1 || errno == EINTR);
|
} while (pid != -1 || errno == EINTR);
|
||||||
|
gettime(&ts2);
|
||||||
if (pid == -1 || !WIFEXITED(i))
|
if (pid == -1 || !WIFEXITED(i))
|
||||||
rval = 1;
|
rval = 1;
|
||||||
else
|
else
|
||||||
@@ -270,10 +275,17 @@ int sudo_edit(argc, argv)
|
|||||||
if (tf[i].osize == sb.st_size &&
|
if (tf[i].osize == sb.st_size &&
|
||||||
tf[i].ots.tv_sec == mtim_getsec(sb) &&
|
tf[i].ots.tv_sec == mtim_getsec(sb) &&
|
||||||
tf[i].ots.tv_nsec == mtim_getnsec(sb)) {
|
tf[i].ots.tv_nsec == mtim_getnsec(sb)) {
|
||||||
warnx("%s unchanged", tf[i].ofile);
|
/*
|
||||||
unlink(tf[i].tfile);
|
* If mtime and size match but the user spent no measurable
|
||||||
close(tf[i].tfd);
|
* time in the editor we can't tell if the file was changed.
|
||||||
continue;
|
*/
|
||||||
|
timespecsub(&ts1, &ts2, &ts2);
|
||||||
|
if (timespecisset(&ts2)) {
|
||||||
|
warnx("%s unchanged", tf[i].ofile);
|
||||||
|
unlink(tf[i].tfile);
|
||||||
|
close(tf[i].tfd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
43
visudo.c
43
visudo.c
@@ -33,6 +33,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#ifndef __TANDEM
|
#ifndef __TANDEM
|
||||||
# include <sys/file.h>
|
# include <sys/file.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -130,8 +131,10 @@ main(argc, argv)
|
|||||||
int stmp_fd; /* stmp file descriptor */
|
int stmp_fd; /* stmp file descriptor */
|
||||||
int n; /* length parameter */
|
int n; /* length parameter */
|
||||||
int ch; /* getopt char */
|
int ch; /* getopt char */
|
||||||
time_t now; /* time now */
|
struct timespec ts1, ts2; /* time before and after edit */
|
||||||
struct stat stmp_sb, sudoers_sb; /* to check for changes */
|
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. */
|
/* Warn about aliases that are used before being defined. */
|
||||||
pedantic = 1;
|
pedantic = 1;
|
||||||
@@ -192,11 +195,14 @@ main(argc, argv)
|
|||||||
if (!lock_file(sudoers_fd, SUDO_TLOCK))
|
if (!lock_file(sudoers_fd, SUDO_TLOCK))
|
||||||
errx(1, "sudoers file busy, try again later");
|
errx(1, "sudoers file busy, try again later");
|
||||||
#ifdef HAVE_FSTAT
|
#ifdef HAVE_FSTAT
|
||||||
if (fstat(sudoers_fd, &sudoers_sb) == -1)
|
if (fstat(sudoers_fd, &sb) == -1)
|
||||||
#else
|
#else
|
||||||
if (stat(sudoers, &sudoers_sb) == -1)
|
if (stat(sudoers, &sb) == -1)
|
||||||
#endif
|
#endif
|
||||||
err(1, "can't stat %s", sudoers);
|
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.
|
* Open sudoers temp file.
|
||||||
@@ -209,7 +215,7 @@ main(argc, argv)
|
|||||||
setup_signals();
|
setup_signals();
|
||||||
|
|
||||||
/* Copy sudoers -> stmp and reset the mtime */
|
/* Copy sudoers -> stmp and reset the mtime */
|
||||||
if (sudoers_sb.st_size) {
|
if (sudoers_size) {
|
||||||
while ((n = read(sudoers_fd, buf, sizeof(buf))) > 0)
|
while ((n = read(sudoers_fd, buf, sizeof(buf))) > 0)
|
||||||
if (write(stmp_fd, buf, n) != n)
|
if (write(stmp_fd, buf, n) != n)
|
||||||
err(1, "write error");
|
err(1, "write error");
|
||||||
@@ -220,7 +226,7 @@ main(argc, argv)
|
|||||||
write(stmp_fd, buf, 1);
|
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);
|
(void) close(stmp_fd);
|
||||||
|
|
||||||
/* Parse sudoers to pull in editor and env_editor conf values. */
|
/* 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
|
* XPG4 specifies that vi's exit value is a function of the
|
||||||
* number of errors during editing (?!?!).
|
* number of errors during editing (?!?!).
|
||||||
*/
|
*/
|
||||||
now = time(NULL);
|
gettime(&ts1);
|
||||||
if (run_command(Editor, av) != -1) {
|
if (run_command(Editor, av) != -1) {
|
||||||
|
gettime(&ts2);
|
||||||
/*
|
/*
|
||||||
* Sanity checks.
|
* Sanity checks.
|
||||||
*/
|
*/
|
||||||
if (stat(stmp, &stmp_sb) < 0) {
|
if (stat(stmp, &sb) < 0) {
|
||||||
warnx("cannot stat temporary file (%s), %s unchanged",
|
warnx("cannot stat temporary file (%s), %s unchanged",
|
||||||
stmp, sudoers);
|
stmp, sudoers);
|
||||||
Exit(-1);
|
Exit(-1);
|
||||||
}
|
}
|
||||||
if (stmp_sb.st_size == 0) {
|
if (sb.st_size == 0) {
|
||||||
warnx("zero length temporary file (%s), %s unchanged",
|
warnx("zero length temporary file (%s), %s unchanged",
|
||||||
stmp, sudoers);
|
stmp, sudoers);
|
||||||
Exit(-1);
|
Exit(-1);
|
||||||
@@ -412,7 +419,7 @@ main(argc, argv)
|
|||||||
switch (whatnow()) {
|
switch (whatnow()) {
|
||||||
case 'Q' : parse_error = FALSE; /* ignore parse error */
|
case 'Q' : parse_error = FALSE; /* ignore parse error */
|
||||||
break;
|
break;
|
||||||
case 'x' : if (sudoers_sb.st_size == 0)
|
case 'x' : if (sudoers_size == 0)
|
||||||
unlink(sudoers);
|
unlink(sudoers);
|
||||||
Exit(0);
|
Exit(0);
|
||||||
break;
|
break;
|
||||||
@@ -423,10 +430,18 @@ main(argc, argv)
|
|||||||
/*
|
/*
|
||||||
* If the user didn't change the temp file, just unlink it.
|
* 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 &&
|
if (sudoers_size == sb.st_size &&
|
||||||
sudoers_sb.st_size == stmp_sb.st_size) {
|
sudoers_mtim.tv_sec == mtim_getsec(sb) &&
|
||||||
warnx("sudoers file unchanged");
|
sudoers_mtim.tv_nsec == mtim_getnsec(sb)) {
|
||||||
Exit(0);
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user