From 5abe508bfef8372472d66adf69cf08e07125820c Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Tue, 21 Nov 2017 16:12:18 +0000 Subject: Initial commit --- src/misc/deps-exe/skabus-dyntee | 1 + src/misc/deps-exe/skabus-dyntee-client | 1 + src/misc/deps-exe/skabus-dynteed | 2 + src/misc/skabus-dyntee-client.c | 39 +++++ src/misc/skabus-dyntee.c | 149 ++++++++++++++++ src/misc/skabus-dynteed.c | 305 +++++++++++++++++++++++++++++++++ 6 files changed, 497 insertions(+) create mode 100644 src/misc/deps-exe/skabus-dyntee create mode 100644 src/misc/deps-exe/skabus-dyntee-client create mode 100644 src/misc/deps-exe/skabus-dynteed create mode 100644 src/misc/skabus-dyntee-client.c create mode 100644 src/misc/skabus-dyntee.c create mode 100644 src/misc/skabus-dynteed.c (limited to 'src/misc') diff --git a/src/misc/deps-exe/skabus-dyntee b/src/misc/deps-exe/skabus-dyntee new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/misc/deps-exe/skabus-dyntee @@ -0,0 +1 @@ +-lskarnet diff --git a/src/misc/deps-exe/skabus-dyntee-client b/src/misc/deps-exe/skabus-dyntee-client new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/misc/deps-exe/skabus-dyntee-client @@ -0,0 +1 @@ +-lskarnet diff --git a/src/misc/deps-exe/skabus-dynteed b/src/misc/deps-exe/skabus-dynteed new file mode 100644 index 0000000..83cec1e --- /dev/null +++ b/src/misc/deps-exe/skabus-dynteed @@ -0,0 +1,2 @@ +-ls6 +-lskarnet diff --git a/src/misc/skabus-dyntee-client.c b/src/misc/skabus-dyntee-client.c new file mode 100644 index 0000000..b73980d --- /dev/null +++ b/src/misc/skabus-dyntee-client.c @@ -0,0 +1,39 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include +#include + +#define USAGE "skabus-dyntee-client path prog..." +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv, char const *const *envp) +{ + PROG = "skabus-dyntee-client" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "", &l) ; + if (opt == -1) break ; + switch (opt) + { + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (argc < 2) dieusage() ; + } + + { + int fd = ipc_stream_b() ; + if (fd < 0) strerr_diefu1sys(111, "create socket") ; + if (!ipc_connect(fd, argv[0])) strerr_diefu2sys(111, "connect to ", argv[0]) ; + if (shutdown(fd, SHUT_WR) < 0) strerr_diefu1sys(111, "shutdown socket for writing") ; + if (fd_move(0, fd) < 0) strerr_diefu1sys(111, "move socket fd to stdin") ; + } + xpathexec_run(argv[1], argv+1, envp) ; +} diff --git a/src/misc/skabus-dyntee.c b/src/misc/skabus-dyntee.c new file mode 100644 index 0000000..f0832c4 --- /dev/null +++ b/src/misc/skabus-dyntee.c @@ -0,0 +1,149 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USAGE "skabus-dyntee [ -d | -D ] [ -1 ] [ -c maxconn ] [ -b backlog ] [ -G gid,gid,... ] [ -g gid ] [ -u uid ] [ -U ] [ -t timeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ] socketpath" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv, char const *const *envp) +{ + int flag1 = 0 ; + int flagU = 0 ; + int flagreuse = 1 ; + uid_t uid = 0 ; + gid_t gid = 0 ; + gid_t gids[NGROUPS_MAX] ; + size_t gidn = (size_t)-1 ; + unsigned int maxconn = 0 ; + unsigned int backlog = (unsigned int)-1 ; + unsigned int timeout = 0 ; + unsigned int ltimeout = 0 ; + char const *rulesdir = 0 ; + char const *rulesfile = 0 ; + PROG = "skabus-dyntee" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "Dd1Uc:b:u:g:G:t:T:i:x:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'D' : flagreuse = 0 ; break ; + case 'd' : flagreuse = 1 ; break ; + case '1' : flag1 = 1 ; break ; + case 'c' : if (!uint0_scan(l.arg, &maxconn)) dieusage() ; if (!maxconn) maxconn = 1 ; break ; + case 'b' : if (!uint0_scan(l.arg, &backlog)) dieusage() ; break ; + case 'u' : if (!uid0_scan(l.arg, &uid)) dieusage() ; break ; + case 'g' : if (!gid0_scan(l.arg, &gid)) dieusage() ; break ; + case 'G' : if (!gid_scanlist(gids, NGROUPS_MAX, l.arg, &gidn) && *l.arg) dieusage() ; break ; + case 'U' : flagU = 1 ; uid = 0 ; gid = 0 ; gidn = (unsigned int)-1 ; break ; + case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ; + case 'T' : if (!uint0_scan(l.arg, <imeout)) dieusage() ; break ; + case 'i' : rulesdir = l.arg ; rulesfile = 0 ; break ; + case 'x' : rulesfile = l.arg ; rulesdir = 0 ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (!argc) dieusage() ; + } + + { + size_t pos = 0 ; + unsigned int m = 0 ; + int fdin = dup(0) ; + char const *newargv[31] ; + char fmt[UINT_FMT * 5 + UID_FMT + GID_FMT * (1 + NGROUPS_MAX)] ; + if (fdin < 0) strerr_diefu1sys(111, "dup(0)") ; + if (fdin < 3) strerr_dief1x(100, "invalid standard file descriptors") ; + pos += uint_fmt(fmt + pos, fdin) ; + fmt[pos++] = 0 ; + newargv[m++] = S6_EXTBINPREFIX "s6-ipcserver-socketbinder" ; + if (!flagreuse) newargv[m++] = "-D" ; + if (backlog != (unsigned int)-1) + { + newargv[m++] = "-b" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, backlog) ; + fmt[pos++] = 0 ; + } + newargv[m++] = "--" ; + newargv[m++] = argv[0] ; + if (flagU || uid || gid || gidn != (size_t)-1) + { + newargv[m++] = S6_EXTBINPREFIX "s6-applyuidgid" ; + if (flagU) newargv[m++] = "-Uz" ; + if (uid) + { + newargv[m++] = "-u" ; + newargv[m++] = fmt + pos ; + pos += uid_fmt(fmt + pos, uid) ; + fmt[pos++] = 0 ; + } + if (gid) + { + newargv[m++] = "-g" ; + newargv[m++] = fmt + pos ; + pos += gid_fmt(fmt + pos, gid) ; + fmt[pos++] = 0 ; + } + if (gidn != (size_t)-1) + { + newargv[m++] = "-G" ; + newargv[m++] = fmt + pos ; + pos += gid_fmtlist(fmt + pos, gids, gidn) ; + fmt[pos++] = 0 ; + } + newargv[m++] = "--" ; + } + newargv[m++] = EXECLINE_EXTBINPREFIX "fdswap" ; + newargv[m++] = "0" ; + newargv[m++] = fmt ; + newargv[m++] = SKABUS_BINPREFIX "skabus-dynteed" ; + newargv[m++] = "-d" ; + newargv[m++] = fmt ; + if (flag1) newargv[m++] = "-1" ; + if (maxconn) + { + newargv[m++] = "-c" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, maxconn) ; + fmt[pos++] = 0 ; + } + if (timeout) + { + newargv[m++] = "-t" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, timeout) ; + fmt[pos++] = 0 ; + } + if (ltimeout) + { + newargv[m++] = "-T" ; + newargv[m++] = fmt + pos ; + pos += uint_fmt(fmt + pos, ltimeout) ; + fmt[pos++] = 0 ; + } + if (rulesdir) + { + newargv[m++] = "-i" ; + newargv[m++] = rulesdir ; + } + else if (rulesfile) + { + newargv[m++] = "-x" ; + newargv[m++] = rulesfile ; + } + newargv[m++] = 0 ; + xpathexec_run(newargv[0], newargv, envp) ; + } +} diff --git a/src/misc/skabus-dynteed.c b/src/misc/skabus-dynteed.c new file mode 100644 index 0000000..8b0e292 --- /dev/null +++ b/src/misc/skabus-dynteed.c @@ -0,0 +1,305 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include /* shutdown */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USAGE "skabus-dynteed [ -d fdsocket ] [ -c maxconn ] [ -1 ] [ -t timeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ]" +#define dieusage() strerr_dieusage(100, USAGE) ; +#define dienomem() strerr_diefu1sys(111, "stralloc_catb") ; +#define die() strerr_dief1sys(101, "unexpected error") ; + +#define SKABUS_DYNTEE_MAX 1000 + +static int cont = 1 ; +static tain_t lameduckdeadline ; + +static unsigned int rulestype = 0 ; +static char const *rules = 0 ; +static int cdbfd = -1 ; +static struct cdb cdbmap = CDB_ZERO ; + +typedef struct client_s client_t, *client_t_ref ; +struct client_s +{ + unsigned int xindex ; + tain_t deadline ; + bufalloc ba ; +} ; + +static void client_free (client_t *c) +{ + fd_close(bufalloc_fd(&c->ba)) ; + bufalloc_free(&c->ba) ; +} + +static void handle_signals (void) +{ + for (;;) switch (selfpipe_read()) + { + case -1 : strerr_diefu1sys(111, "selfpipe_read()") ; + case 0 : return ; + case SIGTERM : + { + if (cont) + { + cont = 0 ; + tain_add_g(&lameduckdeadline, &lameduckdeadline) ; + } + break ; + } + case SIGHUP : + { + int fd ; + struct cdb c = CDB_ZERO ; + if (rulestype != 2) break ; + fd = open_readb(rules) ; + if (fd < 0) break ; + if (cdb_init(&c, fd) < 0) + { + fd_close(fd) ; + break ; + } + cdb_free(&cdbmap) ; + fd_close(cdbfd) ; + cdbfd = fd ; + cdbmap = c ; + } + break ; + default : break ; + } +} + +static inline int new_connection (int fd) +{ + s6_accessrules_params_t params = S6_ACCESSRULES_PARAMS_ZERO ; + uid_t uid ; + gid_t gid ; + if (!rulestype) return 1 ; + if (getpeereid(fd, &uid, &gid) < 0) + { + strerr_warnwu1sys("getpeereid") ; + return 0 ; + } + if ((rulestype == 1 ? s6_accessrules_uidgid_fs(uid, gid, rules, ¶ms) : s6_accessrules_uidgid_cdb(uid, gid, &cdbmap, ¶ms)) != S6_ACCESSRULES_ALLOW) + return 0 ; + s6_accessrules_params_free(¶ms) ; + return 1 ; +} + +int main (int argc, char const *const *argv, char const *const *envp) +{ + tain_t readtto ; + int spfd ; + int flag1 = 0 ; + unsigned int maxconn = 40 ; + unsigned int fdsocket = 3 ; + PROG = "skabus-dynteed" ; + + { + subgetopt_t l = SUBGETOPT_ZERO ; + unsigned int t = 0, T = 0 ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "d:1c:i:x:t:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'd' : if (!uint0_scan(l.arg, &fdsocket)) dieusage() ; break ; + case '1' : flag1 = 1 ; break ; + case 'i' : rules = l.arg ; rulestype = 1 ; break ; + case 'x' : rules = l.arg ; rulestype = 2 ; break ; + case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; + case 'T' : if (!uint0_scan(l.arg, &T)) dieusage() ; break ; + case 'c' : if (!uint0_scan(l.arg, &maxconn)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (t) tain_from_millisecs(&readtto, t) ; + else readtto = tain_infinite_relative ; + if (T) tain_from_millisecs(&lameduckdeadline, T) ; + else lameduckdeadline = tain_infinite_relative ; + } + if (maxconn > SKABUS_DYNTEE_MAX) maxconn = SKABUS_DYNTEE_MAX ; + if (!maxconn) maxconn = 1 ; + { + struct stat st ; + if (fstat(fdsocket, &st) < 0) strerr_diefu1sys(111, "fstat socket descriptor") ; + if (!S_ISSOCK(st.st_mode)) strerr_dief1x(100, "descriptor is not a socket") ; + } + if (flag1) + { + if (fcntl(1, F_GETFD) < 0) + strerr_dief1sys(100, "called with option -1 but stdout said") ; + } + else close(1) ; + if (ndelay_on(0) < 0) strerr_diefu1sys(111, "set stdin non-blocking") ; + spfd = selfpipe_init() ; + if (spfd < 0) strerr_diefu1sys(111, "selfpipe_init") ; + if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; + { + sigset_t set ; + sigemptyset(&set) ; + sigaddset(&set, SIGTERM) ; + sigaddset(&set, SIGHUP) ; + if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ; + } + + if (rulestype == 2) + { + cdbfd = open_readb(rules) ; + if (cdbfd < 0) strerr_diefu3sys(111, "open ", rules, " for reading") ; + if (cdb_init(&cdbmap, cdbfd) < 0) + strerr_diefu2sys(111, "cdb_init ", rules) ; + } + + { + unsigned int numconn = 0 ; + client_t clients[maxconn] ; + + if (flag1) + { + fd_write(1, "\n", 1) ; + fd_close(1) ; + } + tain_now_g() ; + + for (;;) + { + tain_t deadline ; + int r = 2 ; + iopause_fd x[2 + cont + numconn] ; + x[0].fd = spfd ; + x[0].events = IOPAUSE_READ ; + x[1].fd = fdsocket ; + x[1].events = (cont && (numconn < maxconn)) ? IOPAUSE_READ : 0 ; + if (cont) + { + tain_add_g(&deadline, &tain_infinite_relative) ; + x[2].fd = 0 ; + x[2].events = IOPAUSE_READ ; + r++ ; + } + else deadline = lameduckdeadline ; + for (unsigned int i = 0 ; i < numconn ; i++) if (bufalloc_len(&clients[i].ba)) + { + if (tain_less(&clients[i].deadline, &deadline)) deadline = clients[i].deadline ; + x[r].fd = bufalloc_fd(&clients[i].ba) ; + x[r].events = IOPAUSE_WRITE ; + clients[i].xindex = r++ ; + } + + r = iopause_g(x, r, &deadline) ; + if (r < 0) strerr_diefu1sys(111, "iopause") ; + + if (!r) + { + for (unsigned int i = 0 ; i < numconn ; i++) + { + if (bufalloc_len(&clients[i].ba) && !tain_future(&clients[i].deadline)) + { + client_free(clients + i) ; + clients[i--] = clients[--numconn] ; + } + } + if (!(cont || (numconn && tain_future(&lameduckdeadline)))) break ; + continue ; + } + + if (x[0].revents & IOPAUSE_READ) handle_signals() ; + + for (unsigned int i = 0 ; i < numconn ; i++) + { + if (x[clients[i].xindex].revents & (IOPAUSE_WRITE | IOPAUSE_EXCEPT)) + { + if (!bufalloc_flush(&clients[i].ba) && !error_isagain(errno)) + { + client_free(clients + i) ; + clients[i--] = clients[--numconn] ; + } + } + } + + if (cont && x[1].revents & IOPAUSE_READ) + { + int fd = ipc_accept_nb(fdsocket, 0, 0, 0) ; + if (fd < 0) + { + if (!error_isagain(errno)) strerr_diefu1sys(111, "accept") ; + } + else if (!new_connection(fd)) fd_close(fd) ; + else if (shutdown(fd, SHUT_RD) < 0) + { + fd_close(fd) ; + strerr_warnwu1sys("shutdown client connection for reading - aborting it") ; + } + else + { + bufalloc_init(&clients[numconn].ba, &fd_write, fd) ; + tain_copynow(&clients[numconn].deadline) ; + numconn++ ; + } + } + + if (cont && x[2].revents & IOPAUSE_READ) + { + ssize_t r = sanitize_read(buffer_fill(buffer_0)) ; + if (r < 0) + { + fd_close(0) ; + cont = 0 ; + tain_add_g(&lameduckdeadline, &lameduckdeadline) ; + if (errno != EPIPE) strerr_warnwu1sys("read from stdin") ; + } + if (r > 0) + { + struct iovec v[2] ; + buffer_rpeek(buffer_0, v) ; + for (unsigned int i = 0 ; i < numconn ; i++) + { + if (!bufalloc_putv(&clients[i].ba, v, 2)) dienomem() ; + if (!tain_future(&clients[i].deadline)) tain_add_g(&clients[i].deadline, &readtto) ; + } + buffer_rseek(buffer_0, siovec_len(v, 2)) ; + } + } + + if (!cont) + { + for (unsigned int i = 0 ; i < numconn ; i++) + { + if (!bufalloc_len(&clients[i].ba)) + { + client_free(clients + i) ; + clients[i--] = clients[--numconn] ; + } + } + if (!numconn) break ; + } + } + } + return 0 ; +} -- cgit v1.2.3