chiark / gitweb /
util: modernize readlink_malloc() a bit
[elogind.git] / src / shared / util.c
index 945f1525a266d73e70b4b188d3aac2da0bf27792..9be11f5605c829fa7016bffd07fe36e88ac1e6dc 100644 (file)
@@ -761,28 +761,31 @@ char *strappend(const char *s, const char *suffix) {
         return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
 }
 
-int readlink_malloc(const char *p, char **r) {
+int readlink_malloc(const char *p, char **ret) {
         size_t l = 100;
+        int r;
 
         assert(p);
-        assert(r);
+        assert(ret);
 
         for (;;) {
                 char *c;
                 ssize_t n;
 
-                if (!(c = new(char, l)))
+                c = new(char, l);
+                if (!c)
                         return -ENOMEM;
 
-                if ((n = readlink(p, c, l-1)) < 0) {
-                        int ret = -errno;
+                n = readlink(p, c, l-1);
+                if (n < 0) {
+                        r = -errno;
                         free(c);
-                        return ret;
+                        return r;
                 }
 
                 if ((size_t) n < l-1) {
                         c[n] = 0;
-                        *r = c;
+                        *ret = c;
                         return 0;
                 }
 
@@ -2255,25 +2258,37 @@ char* dirname_malloc(const char *path) {
         return dir;
 }
 
-void random_bytes(void *p, size_t n) {
-        static bool srand_called = false;
+int dev_urandom(void *p, size_t n) {
         _cleanup_close_ int fd;
         ssize_t k;
-        uint8_t *q;
 
         fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
         if (fd < 0)
-                goto fallback;
+                return errno == ENOENT ? -ENOSYS : -errno;
 
         k = loop_read(fd, p, n, true);
-        if (k < 0 || (size_t) k != n)
-                goto fallback;
+        if (k < 0)
+                return (int) k;
+        if ((size_t) k != n)
+                return -EIO;
 
-        return;
+        return 0;
+}
 
-fallback:
+void random_bytes(void *p, size_t n) {
+        static bool srand_called = false;
+        uint8_t *q;
+        int r;
+
+        r = dev_urandom(p, n);
+        if (r >= 0)
+                return;
+
+        /* If some idiot made /dev/urandom unavailable to us, he'll
+         * get a PRNG instead. */
 
         if (!srand_called) {
+                unsigned x = 0;
 
 #ifdef HAVE_SYS_AUXV_H
                 /* The kernel provides us with a bit of entropy in
@@ -2285,16 +2300,16 @@ fallback:
 
                 auxv = (void*) getauxval(AT_RANDOM);
                 if (auxv)
-                        srand(*(unsigned*) auxv);
-                else
+                        x ^= *(unsigned*) auxv;
 #endif
-                        srand(time(NULL) + gettid());
 
+                x ^= (unsigned) now(CLOCK_REALTIME);
+                x ^= (unsigned) gettid();
+
+                srand(x);
                 srand_called = true;
         }
 
-        /* If some idiot made /dev/urandom unavailable to us, he'll
-         * get a PRNG instead. */
         for (q = p; q < (uint8_t*) p + n; q ++)
                 *q = rand();
 }
@@ -2325,7 +2340,7 @@ void rename_process(const char name[8]) {
                         if (!saved_argv[i])
                                 break;
 
-                        memset(saved_argv[i], 0, strlen(saved_argv[i]));
+                        memzero(saved_argv[i], strlen(saved_argv[i]));
                 }
         }
 }
@@ -3823,12 +3838,13 @@ char* hostname_cleanup(char *s, bool lowercase) {
 }
 
 int pipe_eof(int fd) {
-        int r;
         struct pollfd pollfd = {
                 .fd = fd,
                 .events = POLLIN|POLLHUP,
         };
 
+        int r;
+
         r = poll(&pollfd, 1, 0);
         if (r < 0)
                 return -errno;
@@ -3880,7 +3896,7 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
         t[k] = '.';
         stpcpy(stpcpy(t+k+1, fn), "XXXXXX");
 
-        fd = mkostemp(t, O_WRONLY|O_CLOEXEC);
+        fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
         if (fd < 0) {
                 free(t);
                 return -errno;
@@ -5779,7 +5795,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need) {
                 return NULL;
 
         if (*allocated > prev)
-                memset(&q[prev], 0, *allocated - prev);
+                memzero(&q[prev], *allocated - prev);
 
         return q;
 }
@@ -5825,20 +5841,6 @@ bool id128_is_valid(const char *s) {
         return true;
 }
 
-void parse_user_at_host(char *arg, char **user, char **host) {
-        assert(arg);
-        assert(user);
-        assert(host);
-
-        *host = strchr(arg, '@');
-        if (*host == NULL)
-                *host = arg;
-        else {
-                *host[0]++ = '\0';
-                *user = arg;
-        }
-}
-
 int split_pair(const char *s, const char *sep, char **l, char **r) {
         char *x, *a, *b;
 
@@ -6080,68 +6082,60 @@ int getpeersec(int fd, char **ret) {
         return 0;
 }
 
-int writev_safe(int fd, const struct iovec *w, int j) {
-        for (int i = 0; i < j; i++) {
-                size_t written = 0;
-
-                while (written < w[i].iov_len) {
-                        ssize_t r;
-
-                        r = write(fd, (char*) w[i].iov_base + written, w[i].iov_len - written);
-                        if (r < 0 && errno != -EINTR)
-                                return -errno;
-
-                        written += r;
-                }
-        }
-
-        return 0;
-}
-
+/* This is much like like mkostemp() but is subject to umask(). */
 int mkostemp_safe(char *pattern, int flags) {
-        char *s = pattern + strlen(pattern) - 6;
-        uint64_t tries = TMP_MAX;
-        int randfd, fd, i;
-
-        assert(streq(s, "XXXXXX"));
-
-        randfd = open("/dev/urandom", O_RDONLY);
-        if (randfd < 0)
-                return -ENOSYS;
+        _cleanup_umask_ mode_t u;
+        int fd;
 
-        while (tries--) {
-                fd = read(randfd, s, 6);
-                if (fd == 0)
-                        return -ENOSYS;
+        assert(pattern);
 
-                for (i = 0; i < 6; i++)
-                        s[i] = ALPHANUMERICAL[(unsigned) s[i] % strlen(ALPHANUMERICAL)];
+        u = umask(077);
 
-                fd = open(pattern, flags|O_EXCL|O_CREAT, S_IRUSR|S_IWUSR);
-                if (fd >= 0)
-                        return fd;
-                if (!IN_SET(errno, EEXIST, EINTR))
-                        return -errno;
-        }
+        fd = mkostemp(pattern, flags);
+        if (fd < 0)
+                return -errno;
 
-        return -EEXIST;
+        return fd;
 }
 
 int open_tmpfile(const char *path, int flags) {
-        int fd;
         char *p;
+        int fd;
+
+        assert(path);
 
 #ifdef O_TMPFILE
+        /* Try O_TMPFILE first, if it is supported */
         fd = open(path, flags|O_TMPFILE, S_IRUSR|S_IWUSR);
         if (fd >= 0)
                 return fd;
 #endif
+
+        /* Fall back to unguessable name + unlinking */
         p = strappenda(path, "/systemd-tmp-XXXXXX");
 
-        fd = mkostemp_safe(p, O_RDWR|O_CLOEXEC);
+        fd = mkostemp_safe(p, flags);
         if (fd < 0)
                 return fd;
 
         unlink(p);
         return fd;
 }
+
+int fd_warn_permissions(const char *path, int fd) {
+        struct stat st;
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (st.st_mode & 0111)
+                log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
+
+        if (st.st_mode & 0002)
+                log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
+
+        if (getpid() == 1 && (st.st_mode & 0044) != 0044)
+                log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
+
+        return 0;
+}