summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2017-11-21 16:12:18 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2017-11-21 16:12:18 +0000
commit5abe508bfef8372472d66adf69cf08e07125820c (patch)
tree4fc1feeb088d2fc1a3a1d02d20240d05a606c1bb /src
downloadskabus-5abe508bfef8372472d66adf69cf08e07125820c.tar.xz
Initial commit
Diffstat (limited to 'src')
-rw-r--r--src/include/skabus/skabus.h15
-rw-r--r--src/misc/deps-exe/skabus-dyntee1
-rw-r--r--src/misc/deps-exe/skabus-dyntee-client1
-rw-r--r--src/misc/deps-exe/skabus-dynteed2
-rw-r--r--src/misc/skabus-dyntee-client.c39
-rw-r--r--src/misc/skabus-dyntee.c149
-rw-r--r--src/misc/skabus-dynteed.c305
7 files changed, 512 insertions, 0 deletions
diff --git a/src/include/skabus/skabus.h b/src/include/skabus/skabus.h
new file mode 100644
index 0000000..51b161f
--- /dev/null
+++ b/src/include/skabus/skabus.h
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#ifndef SKABUS_H
+#define SKABUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
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 <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/webipc.h>
+
+#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 <unistd.h>
+#include <limits.h>
+#include <skalibs/types.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+#include <execline/config.h>
+#include <s6/config.h>
+#include <skabus/config.h>
+
+#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, &ltimeout)) 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 <skalibs/nonposix.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/socket.h> /* shutdown */
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/types.h>
+#include <skalibs/siovec.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/error.h>
+#include <skalibs/bufalloc.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/tai.h>
+#include <skalibs/getpeereid.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/sig.h>
+#include <skalibs/iopause.h>
+#include <skalibs/selfpipe.h>
+#include <skalibs/cdb.h>
+#include <s6/accessrules.h>
+
+#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, &params) : s6_accessrules_uidgid_cdb(uid, gid, &cdbmap, &params)) != S6_ACCESSRULES_ALLOW)
+ return 0 ;
+ s6_accessrules_params_free(&params) ;
+ 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 ;
+}