]> git.armaanb.net Git - opendoas.git/blobdiff - persist_timestamp.c
persist_timestamp: persist_check was only used internally, make it static
[opendoas.git] / persist_timestamp.c
index c8f4bb5ddd70f4242e3c3b5d86c86163cc4b775c..19e27aa34d459eaaf893ae37a050212626dbd111 100644 (file)
 #include "includes.h"
 
 #ifndef TIMESTAMP_DIR
-# define TIMESTAMP_DIR "/tmp/doas"
+#      define TIMESTAMP_DIR "/tmp/doas"
 #endif
-#ifndef TMPFS_MAGIC
-# define TMPFS_MAGIC 0x01021994
+
+#if defined(TIMESTAMP_TMPFS) && defined(__linux__)
+#      ifndef TMPFS_MAGIC
+#              define TMPFS_MAGIC 0x01021994
+#      endif
 #endif
 
 #define        timespecisset(tsp)              ((tsp)->tv_sec || (tsp)->tv_nsec)
@@ -49,7 +52,7 @@ static int
 ttynr()
 {
        char buf[1024];
-       char *p, *p1, *saveptr;
+       char *p, *saveptr;
        const char *errstr;
        int fd, n;
 
@@ -62,14 +65,14 @@ ttynr()
                if (n == -1) {
                        if (errno == EAGAIN || errno == EINTR)
                                continue;
-                       else
-                               break;
+                       break;
                }
                p += n;
                if (p >= buf + sizeof buf)
                        break;
        }
        close(fd);
+
        /* error if it contains NULL bytes */
        if (n != 0 || memchr(buf, '\0', p - buf))
                return -1;
@@ -81,14 +84,13 @@ ttynr()
         */
        if ((p = strrchr(buf, ')')) == NULL)
                return -1;
-       for ((p1 = strtok_r(p, " ", &saveptr)), n = 0; p1;
-           (p1 = strtok_r(NULL, " ", &saveptr)), n++)
-               if (n == 5)
-                       break;
-       if (p1 == NULL || n != 5)
+       for ((p = strtok_r(p, " ", &saveptr)), n = 0; p && n < 5;
+           (p = strtok_r(NULL, " ", &saveptr)), n++)
+               ;
+       if (p == NULL || n != 5)
                return -1;
 
-       n = strtonum(p1, INT_MIN, INT_MAX, &errstr);
+       n = strtonum(p, INT_MIN, INT_MAX, &errstr);
        if (errstr)
                return -1;
 
@@ -98,75 +100,106 @@ ttynr()
 #error "ttynr not implemented"
 #endif
 
-static char pathbuf[PATH_MAX];
-
-static int
-tspath(const char **path)
+static const char *
+tsname()
 {
+       static char buf[128];
        int tty;
-       pid_t ppid;
-       if (*pathbuf == '\0') {
-               if ((tty = ttynr()) == -1)
-                       errx(1, "failed to get tty number");
-               ppid = getppid();
-               if (snprintf(pathbuf, sizeof pathbuf, "%s/.%d_%d",
-                   TIMESTAMP_DIR, tty, ppid) == -1)
-                       return -1;
-       }
-       *path = pathbuf;
-       return 0;
+       pid_t ppid, sid;
+       if ((tty = ttynr()) == -1)
+               errx(1, "failed to get tty number");
+       ppid = getppid();
+       if ((sid = getsid(0)) == -1)
+               err(1, "getsid");
+       if (snprintf(buf, sizeof buf, ".%d_%d_%d", tty, ppid, sid) == -1)
+               return NULL;
+       return buf;
 }
 
 static int
-checktsdir(const char *path)
+checktsdir(int fd)
 {
-       char *dir, *buf;
        struct stat st;
+
+       if (fstat(fd, &st) == -1)
+               err(1, "fstatat");
+
+       if ((st.st_mode & S_IFMT) != S_IFDIR)
+               errx(0, "timestamp directory is not a directory");
+       if ((st.st_mode & (S_IWGRP|S_IRGRP|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH)) != 0)
+               errx(1, "timestamp directory permissions wrong");
+       if (st.st_uid != 0 || st.st_gid != 0)
+               errx(1, "timestamp directory is not owned by root");
+
+#if defined(TIMESTAMP_TMPFS) && defined(__linux__)
        struct statfs sf;
-       gid_t gid;
+       if (fstatfs(fd, &sf) == -1)
+               err(1, "statfs");
 
-       if (!(buf = strdup(path)))
-               err(1, "strdup");
-       dir = dirname(buf);
+       if (sf.f_type != TMPFS_MAGIC)
+               errx(1, "timestamp directory not on tmpfs");
+#endif
+
+       return 0;
+}
+
+static int
+opentsdir()
+{
+       gid_t gid;
+       int fd;
 
-check:
-       if (lstat(dir, &st) == -1) {
+reopen:
+       if ((fd = open(TIMESTAMP_DIR, O_RDONLY | O_DIRECTORY)) == -1) {
                if (errno == ENOENT) {
                        gid = getegid();
                        if (setegid(0) != 0)
                                err(1, "setegid");
-                       if (mkdir(dir, (S_IRUSR|S_IWUSR|S_IXUSR)) != 0)
+                       if (mkdir(TIMESTAMP_DIR, (S_IRUSR|S_IWUSR|S_IXUSR)) != 0)
                                err(1, "mkdir");
                        if (setegid(gid) != 0)
                                err(1, "setegid");
-                       goto check;
+                       goto reopen;
                } else {
-                       err(1, "stat");
+                       err(1, "failed to open timestamp directory: %s", TIMESTAMP_DIR);
                }
        }
 
-       if ((st.st_mode & S_IFMT) != S_IFDIR)
-               errx(1, "timestamp directory is not a directory");
+       if (checktsdir(fd) != 0)
+               return -1;
+
+       return fd;
+}
+
+static int
+checktsfile(int fd, size_t *tssize)
+{
+       struct stat st;
+       gid_t gid;
+
+       if (fstat(fd, &st) == -1)
+               err(1, "stat");
+       if ((st.st_mode & S_IFMT) != S_IFREG)
+               errx(1, "timestamp is not a regular file");
        if ((st.st_mode & (S_IWGRP|S_IRGRP|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH)) != 0)
-               errx(1, "timestamp directory permissions wrong");
-       if (st.st_uid != 0 || st.st_gid != 0)
-               errx(1, "timestamp directory is not owned by root");
-       if (statfs(dir, &sf) == -1)
-               err(1, "statfs");
-       if (sf.f_type != TMPFS_MAGIC)
-               errx(1, "timestamp directory not on tmpfs");
+               errx(1, "timestamp has wrong permissions");
+
+       gid = getegid();
+       if (st.st_uid != 0 || st.st_gid != gid)
+               errx(1, "timestamp has wrong owner");
+
+       *tssize = st.st_size;
 
-       free(buf);
        return 0;
 }
 
-int
-persist_check(int fd, int secs)
+static int
+validts(int fd, int secs)
 {
        struct timespec mono, real, ts_mono, ts_real, timeout;
 
        if (read(fd, &ts_mono, sizeof ts_mono) != sizeof ts_mono ||
-           read(fd, &ts_real, sizeof ts_real) != sizeof ts_mono)
+           read(fd, &ts_real, sizeof ts_real) != sizeof ts_real)
                err(1, "read");
        if (!timespecisset(&ts_mono) || !timespecisset(&ts_real))
                errx(1, "timespecisset");
@@ -217,58 +250,57 @@ persist_set(int fd, int secs)
 int
 persist_open(int *valid, int secs)
 {
-       struct stat st;
-       int fd;
-       gid_t gid;
-       const char *path;
+       int dirfd, fd;
+       const char *name;
 
-       if (tspath(&path) == -1)
-               errx(1, "failed to get timestamp path");
-       if (checktsdir(path))
-               errx(1, "checktsdir");
+       *valid = 0;
 
-       if ((fd = open(path, (O_RDWR), (S_IRUSR|S_IWUSR))) == -1)
+       if ((name = tsname()) == NULL)
+               errx(1, "failed to get timestamp name");
+       if ((dirfd = opentsdir()) == -1)
+               errx(1, "opentsdir");
+
+       if ((fd = openat(dirfd, name, (O_RDWR), (S_IRUSR|S_IWUSR))) == -1)
                if (errno != ENOENT)
-                       err(1, "open: %s", path);
+                       err(1, "open: %s", name);
 
        if (fd == -1) {
-               if ((fd = open(path, (O_RDWR|O_CREAT|O_EXCL), (S_IRUSR|S_IWUSR))) == -1)
-                       err(1, "open: %s", path);
-               *valid = 0;
-               return fd;
+               if ((fd = openat(dirfd, name, (O_RDWR|O_CREAT|O_EXCL), (S_IRUSR|S_IWUSR))) == -1)
+                       err(1, "open: %s", name);
        }
 
-       if (fstat(fd, &st) == -1)
-               err(1, "stat");
-       if ((st.st_mode & S_IFMT) != S_IFREG)
-               errx(1, "timestamp is not a file");
-       if ((st.st_mode & (S_IWGRP|S_IRGRP|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH)) != 0)
-               errx(1, "timestamp permissions wrong");
-
-       gid = getegid();
-       if (st.st_uid != 0 || st.st_gid != gid)
-               errx(1, "timestamp has wrong owner");
+       size_t tssize;
+       if (checktsfile(fd, &tssize) == -1)
+               err(1, "checktsfile");
 
-       if (st.st_size == 0) {
-               *valid = 0;
-               return fd;
-       }
-
-       if (st.st_size != sizeof(struct timespec) * 2)
+       /* The timestamp size is 0 if its a new file or a
+        * timestamp that was never set, its not valid but
+        * can be used to write the new timestamp.
+        * If the size does not match the expected size it
+        * is incomplete and should never be used
+        */
+       if (tssize == 0)
+               goto ret;
+       else if (tssize != sizeof(struct timespec) * 2)
                errx(1, "corrupt timestamp file");
 
-       *valid = persist_check(fd, secs) == 0;
-
+       *valid = validts(fd, secs) == 0;
+ret:
+       close(dirfd);
        return fd;
 }
 
 int
 persist_clear()
 {
-       const char *path;
-       if (tspath(&path) == -1)
-               errx(1, "failed to get timestamp path");
-       if (unlink(path) == -1 && errno != ENOENT)
+       const char *name;
+       int dirfd;
+       if ((name = tsname()) == NULL)
+               errx(1, "failed to get timestamp name");
+       if ((dirfd = opentsdir()) == -1)
+               errx(1, "opentsdir");
+       if (unlinkat(dirfd, name, 0) == -1 && errno != ENOENT)
                return -1;
+       close(dirfd);
        return 0;
 }