X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=3482b9b743b8e1cc7861dcf8c746807cc7dcd6eb;hb=112cfb181453e38d3ef4a74fba23abbb53392002;hp=945f1525a266d73e70b4b188d3aac2da0bf27792;hpb=7d5dd5e0cf2f0f2af39d72b1ee65651731bf0129;p=elogind.git diff --git a/src/shared/util.c b/src/shared/util.c index 945f1525a..3482b9b74 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -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; @@ -5597,7 +5613,7 @@ static int search_and_fopen_internal(const char *path, const char *mode, char ** assert(mode); assert(_f); - if (!path_strv_canonicalize_uniq(search)) + if (!path_strv_canonicalize_absolute_uniq(search, NULL)) return -ENOMEM; STRV_FOREACH(i, search) { @@ -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; +}