1/* This is a very simple SUID binary for creating an XDG_RUNTIME_DIR 2 * on systems using neither PAM nor elogind. The code is basically 3 * taken from dumb-runtime-dir and hence licensed under 0BSD. 4 * 5 * The tool creates a directory with RUNTIME_DIR_PREFIX and prints 6 * its path. The caller is responsible for setting XDG_RUNTIME_DIR 7 * accordingly. Contrary to the spec, the directory is never removed. */ 8 9#include <assert.h>10#include <err.h>11#include <errno.h>12#include <stddef.h>13#include <stdint.h>14#include <stdio.h>15#include <stdlib.h>16#include <unistd.h>1718#include <sys/stat.h>1920int21main(void) {22 uid_t gid = getgid();23 uid_t uid = getuid();2425 /* The following has been taken from dumb-runtime-dir and slightly modified.26 *27 * See: https://github.com/ifreund/dumb_runtime_dir/blob/v1.0.4/pam_dumb_runtime_dir.c#L51-L61 */2829 /* The bit size of uintmax_t will always be larger than the number of30 * bytes needed to print it. */31 char path[sizeof(RUNTIME_DIR_PREFIX) + sizeof(uintmax_t) * 8];32 /* Valid UIDs are always positive even if POSIX allows the uid_t type33 * itself to be signed. Therefore, we can convert to uintmax_t for34 * safe formatting. */35 int ret = snprintf(path, sizeof(path), RUNTIME_DIR_PREFIX"%ju", (uintmax_t)uid);36 assert(ret >= 0 && (size_t)ret < sizeof(path));3738 if (mkdir(path, 0700) < 0) {39 /* It's ok if the directory already exists, in that case we just40 * ensure the mode is correct before we chown(). */41 if (errno != EEXIST)42 err(EXIT_FAILURE, "mkdir failed");43 if (chmod(path, 0700) < 0)44 err(EXIT_FAILURE, "chmod failed");45 }4647 if (chown(path, uid, gid) < 0)48 err(EXIT_FAILURE, "chown failed");4950 printf("%s\n", path);51 return EXIT_SUCCESS;52}