doas

https://man.openbsd.org/doas.1
git clone anongit@rnpnr.xyz:doas.git
Log | Files | Refs | Feed

persist.c (2609B)


      1 #include <errno.h>
      2 #include <fcntl.h>
      3 #include <limits.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <sys/stat.h>
      8 #include <sys/types.h>
      9 #include <time.h>
     10 #include <unistd.h>
     11 
     12 #include "doas.h"
     13 
     14 #define PERSIST_DIR "/run/doas"
     15 #define PERSIST_TIMEOUT 5 * 60
     16 
     17 static int
     18 ttyid(dev_t *tty)
     19 {
     20 	int fd, i;
     21 	char buf[BUFSIZ], *p;
     22 	ssize_t n;
     23 
     24 	fd = open("/proc/self/stat", O_RDONLY);
     25 	if (fd == -1)
     26 		return -1;
     27 	n = read(fd, buf, sizeof(buf) - 1);
     28 	if (n >= 0)
     29 		buf[n] = '\0';
     30 	/* check that we read the whole file */
     31 	n = read(fd, buf, 1);
     32 	close(fd);
     33 	if (n != 0)
     34 		return -1;
     35 	p = strrchr(buf, ')');
     36 	if (!p)
     37 		return -1;
     38 	++p;
     39 	/* ttr_nr is the 5th field after executable name, so skip the next 4 */
     40 	for (i = 0; i < 4; ++i) {
     41 		p = strchr(++p, ' ');
     42 		if (!p)
     43 			return -1;
     44 	}
     45 	*tty = strtol(p, &p, 10);
     46 	if (*p != ' ')
     47 		return -1;
     48 	return 0;
     49 }
     50 
     51 static int
     52 persistpath(char *buf, size_t len)
     53 {
     54 	dev_t tty;
     55 	int n;
     56 
     57 	if (ttyid(&tty) < 0)
     58 		return -1;
     59 	n = snprintf(buf, len, PERSIST_DIR "/%ju-%ju", (uintmax_t)getuid(), (uintmax_t)tty);
     60 	if (n < 0 || n >= (int)len)
     61 		return -1;
     62 	return 0;
     63 }
     64 
     65 int
     66 openpersist(int *valid)
     67 {
     68 	char path[256];
     69 	struct stat st;
     70 	struct timespec ts;
     71 	int fd;
     72 
     73 	if (stat(PERSIST_DIR, &st) < 0) {
     74 		if (errno != ENOENT)
     75 			return -1;
     76 		if (mkdir(PERSIST_DIR, 0700) < 0)
     77 			return -1;
     78 	} else if (st.st_uid != 0 || st.st_mode != (S_IFDIR | 0700)) {
     79 		return -1;
     80 	}
     81 	if (persistpath(path, sizeof(path)) < 0)
     82 		return -1;
     83 	fd = open(path, O_RDONLY);
     84 	if (fd == -1) {
     85 		char tmp[256];
     86 		struct timespec ts[2] = { { .tv_nsec = UTIME_OMIT }, { 0 } };
     87 		int n;
     88 
     89 		n = snprintf(tmp, sizeof(tmp), PERSIST_DIR "/.tmp-%d", getpid());
     90 		if (n < 0 || n >= (int)sizeof(tmp))
     91 			return -1;
     92 		fd = open(tmp, O_RDONLY | O_CREAT | O_EXCL, 0);
     93 		if (fd == -1)
     94 			return -1;
     95 		if (futimens(fd, ts) < 0 || rename(tmp, path) < 0) {
     96 			close(fd);
     97 			unlink(tmp);
     98 			return -1;
     99 		}
    100 		*valid = 0;
    101 	} else {
    102 		*valid = clock_gettime(CLOCK_BOOTTIME, &ts) == 0 &&
    103 		         fstat(fd, &st) == 0 &&
    104 		         (ts.tv_sec < st.st_mtim.tv_sec ||
    105 		          (ts.tv_sec == st.st_mtim.tv_sec && ts.tv_nsec < st.st_mtim.tv_nsec)) &&
    106 		         st.st_mtime - ts.tv_sec <= PERSIST_TIMEOUT;
    107 	}
    108 	return fd;
    109 }
    110 
    111 int
    112 setpersist(int fd)
    113 {
    114 	struct timespec times[2];
    115 
    116 	if (clock_gettime(CLOCK_BOOTTIME, &times[1]) < 0)
    117 		return -1;
    118 	times[0].tv_nsec = UTIME_OMIT;
    119 	times[1].tv_sec += PERSIST_TIMEOUT;
    120 	return futimens(fd, times);
    121 }
    122 
    123 int
    124 clearpersist(void)
    125 {
    126 	char path[256];
    127 
    128 	if (persistpath(path, sizeof(path)) < 0)
    129 		return -1;
    130 	if (unlink(path) < 0 && errno != ENOENT)
    131 		return -1;
    132 	return 0;
    133 }