diff options
| author | Laurent Bercot <ska-skaware@skarnet.org> | 2019-12-30 23:27:32 +0000 |
|---|---|---|
| committer | Laurent Bercot <ska-skaware@skarnet.org> | 2019-12-30 23:27:32 +0000 |
| commit | ed9dadb2778ab4ff7683622907e22ed8c561bfda (patch) | |
| tree | 59d4341aa2d885d6928e1e30ab6f5f57916c09ee /src/alias/s6-frontend-alias-chpst.c | |
| download | s6-frontend-ed9dadb2778ab4ff7683622907e22ed8c561bfda.tar.gz | |
Initial commit.
Diffstat (limited to 'src/alias/s6-frontend-alias-chpst.c')
| -rw-r--r-- | src/alias/s6-frontend-alias-chpst.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/src/alias/s6-frontend-alias-chpst.c b/src/alias/s6-frontend-alias-chpst.c new file mode 100644 index 0000000..860654e --- /dev/null +++ b/src/alias/s6-frontend-alias-chpst.c @@ -0,0 +1,347 @@ + /* ISC license. */ + +#include <string.h> +#include <stdint.h> +#include <stdlib.h> +#include <limits.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> + +#include <skalibs/uint64.h> +#include <skalibs/types.h> +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/env.h> +#include <skalibs/djbunix.h> + +#include <execline/config.h> + +#include <s6/config.h> + +#define USAGE "s6-frontend-alias-chpst [ -v ] [ -P ] [ -0 ] [ -1 ] [ -2 ] [ -u user ] [ -U user ] [ -b argv0 ] [ -e dir ] [ -n niceness ] [ -l lock | -L lock ] [ -m bytes ] [ -d bytes ] [ -o n ] [ -p n ] [ -f bytes ] [ -c bytes ] prog..." + +#define dienomem() strerr_diefu1sys(111, "stralloc_catb") +#define dieusage() strerr_dieusage(100, USAGE) + +static unsigned int verbosity = 0 ; + +static void printit (char const *const *argv) +{ + buffer_puts(buffer_2, PROG) ; + buffer_puts(buffer_2, ": info: executing the following command line:") ; + for (; *argv ; argv++) + { + buffer_puts(buffer_2, " ") ; + buffer_puts(buffer_2, *argv) ; + } + buffer_putsflush(buffer_2, "\n") ; +} + +static inline size_t parseuggnum (char const *s, uint32_t *flags, uid_t *uid, gid_t *gid, gid_t *tab) +{ + size_t n = 0 ; + size_t pos = uid_scan(s, uid) ; + if (!pos) dieusage() ; + if (!s[pos]) return 0 ; + if (s[pos] != ':') dieusage() ; + s += pos+1 ; + pos = gid_scan(s, gid) ; + if (!pos) dieusage() ; + *flags |= 32768 ; + if (!s[pos]) return 0 ; + if (s[pos] != ':') dieusage() ; + s += pos+1 ; + if (!gid_scanlist(tab, NGROUPS_MAX, s, &n)) dieusage() ; + return n ; +} + +static struct passwd *do_getpwnam (char const *s) +{ + struct passwd *pw = getpwnam(s) ; + if (!pw) + { + if (errno) strerr_diefu1sys(111, "read user database") ; + else strerr_dief2x(100, "user not found in user database: ", s) ; + } + return pw ; +} + +static struct group *do_getgrnam (char const *s) +{ + struct group *gr = getgrnam(s) ; + if (!gr) + { + if (errno) strerr_diefu1sys(111, "read group database") ; + else strerr_dief2x(100, "group not found in group database: ", s) ; + } + return gr ; +} + +static inline size_t parseuggsym (char const *s, uint32_t *flags, uid_t *uid, gid_t *gid, gid_t *tab) +{ + size_t n = 0 ; + struct passwd *pw ; + struct group *gr ; + size_t pos = str_chr(s, ':') ; + *flags |= 32768 ; + errno = 0 ; + if (!s[pos]) pw = do_getpwnam(s) ; + else + { + char tmp[pos+1] ; + memcpy(tmp, s, pos) ; + tmp[pos] = 0 ; + pw = do_getpwnam(tmp) ; + } + *uid = pw->pw_uid ; + if (!s[pos]) + { + *gid = pw->pw_gid ; + return 0 ; + } + s += pos+1 ; + pos = str_chr(s, ':') ; + errno = 0 ; + if (!s[pos]) gr = do_getgrnam(s) ; + else + { + char tmp[pos+1] ; + memcpy(tmp, s, pos) ; + tmp[pos] = 0 ; + gr = do_getgrnam(tmp) ; + } + *gid = gr->gr_gid ; + if (!s[pos]) return 0 ; + s += pos+1 ; + while (*s) + { + if (n >= NGROUPS_MAX) + strerr_dief1x(100, "too many supplementary groups listed for the -u option") ; + pos = str_chr(s, ':') ; + errno = 0 ; + if (!s[pos]) gr = do_getgrnam(s) ; + else + { + char tmp[pos+1] ; + memcpy(tmp, s, pos) ; + tmp[pos] = 0 ; + gr = do_getgrnam(tmp) ; + } + tab[n++] = gr->gr_gid ; + s += s[pos] ? pos+1 : pos ; + } + return n ; +} + +int main (int argc, char const *const *argv, char const *const *envp) +{ + static char const *valopt[6] = { "-m", "-d", "-o", "-p", "-f", "-c" } ; + genalloc envdirs = GENALLOC_ZERO ; /* char const * */ + stralloc newroot = STRALLOC_ZERO ; + unsigned int newargc = 0 ; + char const *argv0 = 0 ; + char const *lockfile = 0 ; + char const *envug = 0 ; + uint32_t flags = 0 ; + int niceval = 0 ; + char valfmt[6][UINT64_FMT] ; + char nicefmt[INT_FMT] ; + char uidfmt[UID_FMT] ; + char gidfmt[GID_FMT] ; + char gidlistfmt[GID_FMT * NGROUPS_MAX] ; + PROG = "s6-frontend-alias-chpst" ; + + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "vP012u:U:b:e:/:n:l:L:m:d:o:p:f:c:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'v' : verbosity++ ; break ; + case '0' : flags |= 1 ; newargc += 2 ; break ; + case '1' : flags |= 2 ; newargc += 2 ; break ; + case '2' : flags |= 4 ; newargc += 2 ; break ; + case 'P' : flags |= 8 ; newargc += 2 ; break ; + case 'b' : argv0 = l.arg ; newargc += 4 ; break ; + case 'u' : + { + size_t n ; + uid_t uid ; + gid_t gid ; + gid_t tab[NGROUPS_MAX] ; + newargc += 6 ; + flags |= 16384 ; flags &= ~32768 ; + n = l.arg[0] == ':' ? + parseuggnum(l.arg + 1, &flags, &uid, &gid, tab) : + parseuggsym(l.arg, &flags, &uid, &gid, tab) ; + uidfmt[uid_fmt(uidfmt, uid)] = 0 ; + if (flags & 32768) + { + newargc += 2 ; + gidfmt[gid_fmt(gidfmt, gid)] = 0 ; + } + gidlistfmt[gid_fmtlist(gidlistfmt, tab, n)] = 0 ; + break ; + } + case 'U' : + envug = l.arg ; + newargc += 3 ; + if (envug[0] == ':') { flags |= 4096 ; envug++ ; newargc++ ; } else flags &= ~4096 ; + if (strchr(envug, ':')) { flags |= 8192 ; newargc++ ; } else flags &= ~8192 ; + break ; + case 'e' : + if (!genalloc_append(char const *, &envdirs, &l.arg)) dienomem() ; + newargc += 3 ; + break ; + case '/' : + newroot.len = 0 ; + if (sarealpath(&newroot, l.arg) < 0 || !stralloc_0(&newroot)) dienomem() ; + newargc += 2 ; + break ; + case 'n' : + if (!int0_scan(l.arg, &niceval)) dieusage() ; + newargc += 3 ; + break ; + case 'l' : lockfile = l.arg ; flags &= ~16 ; newargc += 4 ; break ; + case 'L' : lockfile = l.arg ; flags |= 16 ; newargc += 4 ; break ; + case 'm' : + case 'd' : + case 'o' : + case 'p' : + case 'f' : + case 'c' : + { + uint64_t val ; + size_t pos = byte_chr("mdopfc", 6, opt) ; + if (!uint640_scan(l.arg, &val)) dieusage() ; + valfmt[pos][uint64_fmt(valfmt[pos], val)] = 0 ; + flags |= 32 | (1 << (6 + pos)) ; + newargc += 2 ; + break ; + } + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + } + + if (flags & 32) newargc += 2 ; + newargc += argc ; + + { + unsigned int m = 0 ; + char const *newargv[newargc + 1] ; + + if (niceval) + { + nicefmt[int_fmt(nicefmt, niceval)] = 0 ; + newargv[m++] = "nice" ; + newargv[m++] = "-n" ; + newargv[m++] = nicefmt ; + newargv[m++] = "--" ; + } + + if (flags & 8) + { + newargv[m++] = S6_EXTBINPREFIX "s6-setsid" ; + newargv[m++] = "--" ; + } + + if (genalloc_len(char const *, &envdirs)) + { + for (size_t i = 0 ; i < genalloc_len(char const *, &envdirs) ; i++) + { + newargv[m++] = S6_EXTBINPREFIX "s6-envdir" ; + newargv[m++] = "--" ; + newargv[m++] = genalloc_s(char const *, &envdirs)[i] ; + } + } + + if (lockfile) + { + newargv[m++] = S6_EXTBINPREFIX "s6-setlock" ; + newargv[m++] = flags & 16 ? "-n" : "-N" ; + newargv[m++] = "--" ; + newargv[m++] = lockfile ; + } + + if (flags & 16384) + { + newargv[m++] = S6_EXTBINPREFIX "s6-applyuidgid" ; + newargv[m++] = "-u" ; + newargv[m++] = uidfmt ; + if (flags & 32768) + { + newargv[m++] = "-g" ; + newargv[m++] = gidfmt ; + } + newargv[m++] = "-G" ; + newargv[m++] = gidlistfmt ; + newargv[m++] = "--" ; + } + + if (envug) + { + newargv[m++] = S6_EXTBINPREFIX "s6-envuidgid" ; + if (flags & 4096) newargv[m++] = "-n" ; + if (flags & 8192) newargv[m++] = "-B" ; + newargv[m++] = "--" ; + newargv[m++] = envug ; + } + + if (flags & 32) + { + newargv[m++] = S6_EXTBINPREFIX "s6-softlimit" ; + for (unsigned int i = 0 ; i < 6 ; i++) if (flags & (1 << (i + 6))) + { + newargv[m++] = valopt[i] ; + newargv[m++] = valfmt[i] ; + } + newargv[m++] = "--" ; + } + + if (flags & 1) + { + newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ; + newargv[m++] = "0" ; + } + + if (flags & 2) + { + newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ; + newargv[m++] = "1" ; + } + + if (flags & 4) + { + newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ; + newargv[m++] = "2" ; + } + + if (argv0) + { + newargv[m++] = EXECLINE_BINPREFIX "exec" ; + newargv[m++] = "-a" ; + newargv[m++] = argv0 ; + newargv[m++] = "--" ; + } + + if (newroot.s) + { + newargv[m++] = "chroot" ; + newargv[m++] = newroot.s ; + if (argv0) strerr_warnw1x("the -b option is ineffective when the -/ option is also given") ; + } + + for (int i = 0 ; i < argc+1 ; i++) newargv[m++] = argv[i] ; + if (verbosity) printit(newargv) ; + xpathexec0_run(newargv, envp) ; + } +} |
