]> granicus.if.org Git - sudo/commitdiff
Use timespec throughout.
authorTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 8 Sep 2004 15:48:23 +0000 (15:48 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 8 Sep 2004 15:48:23 +0000 (15:48 +0000)
check.c
compat.h
fileops.c
sudo.h
sudo_edit.c
visudo.c

diff --git a/check.c b/check.c
index 826d952d7c5728f9769916f62d0db608304ffeb1..83bd15b116af68b5d7eb905f6693dc7445c105d8 100644 (file)
--- 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(&timestampdir, &timestampfile);
     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);
index 471feef2a82d218ab65479ac7dbfa6ec93073894..6f0f8ba3ffbb33c99989a60ae364b77def7b6b10 100644 (file)
--- 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 */
index fd8407efe0b599d250c003d0f5936b06e3ede199..f36a7400fa229a398109ea4dc296de723ae5c332 100644 (file)
--- 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 b404129de64522bc275096ab3e85dbedbd0dbae1..ff2491229d25e0f99a04ed693667d44c96cb4c73 100644 (file)
--- 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. */
index a1893565e49238eef76ebaa164924e99b86139b4..8f98bcf5590a1dbbe1cb39ca47d81fb577f7e6c4 100644 (file)
@@ -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
index cef880ee789c2e669c4ce991baff7c64d3d3fcdc..b555ae968ac326e0ecedcdb5e500f88cb212132f 100644 (file)
--- a/visudo.c
+++ b/visudo.c
@@ -33,6 +33,7 @@
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #ifndef __TANDEM
 # include <sys/file.h>
 #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);
+       }
     }
 
     /*