diff options
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | gmid.c | 53 | ||||
-rw-r--r-- | gmid.h | 17 | ||||
-rw-r--r-- | sandbox.c | 71 |
6 files changed, 105 insertions, 47 deletions
@@ -1,5 +1,7 @@ 2021-01-15 Omar Polo <op@omarpolo.com> + * sandbox.c (sandbox): sandbox on OpenBSD (pledge/unveil, as before) and on FreeBSD (capsicum) too + * sample.conf: added sample configuration * gmid.c (main): changed behaviour: daemon off by default @@ -14,8 +14,9 @@ lex.yy.c: lex.l y.tab.c y.tab.c: parse.y ${YACC} -b y -d parse.y -gmid: gmid.o iri.o utf8.o lex.yy.o y.tab.o - ${CC} gmid.o iri.o utf8.o lex.yy.o y.tab.o -o gmid ${LDFLAGS} +OBJS = gmid.o iri.o utf8.o lex.yy.o y.tab.o sandbox.o +gmid: ${OBJS} + ${CC} ${OBJS} -o gmid ${LDFLAGS} TAGS: gmid.c iri.c utf8.c -etags gmid.c iri.c utf8.c || true @@ -22,6 +22,7 @@ CGI scripts are enabled, while the given directory is unveiled with - (very) low memory footprint - small codebase, easily hackable - virtual hosts + - sandboxed on OpenBSD and FreeBSD ## Drawbacks @@ -30,6 +31,9 @@ CGI scripts are enabled, while the given directory is unveiled with connection per-second you'd probably want to run multiple gmid instances behind relayd/haproxy or a different server. + - the sandbox on FreeBSD is **NOT** activated if CGI scripts are + enabled: CGI script cannot be used with the way `capsicum(4)` works + ## Building @@ -29,11 +29,6 @@ #include "gmid.h" -#define LOGE(c, fmt, ...) logs(LOG_ERR, c, fmt, __VA_ARGS__) -#define LOGN(c, fmt, ...) logs(LOG_NOTICE, c, fmt, __VA_ARGS__) -#define LOGI(c, fmt, ...) logs(LOG_INFO, c, fmt, __VA_ARGS__) -#define LOGD(c, fmt, ...) logs(LOG_DEBUG, c, fmt, __VA_ARGS__) - struct vhost hosts[HOSTSLEN]; int connected_clients; @@ -90,8 +85,7 @@ fatal(const char *fmt, ...) exit(1); } -__attribute__ ((format (printf, 3, 4))) -static inline void +void logs(int priority, struct client *c, const char *fmt, ...) { @@ -103,13 +97,18 @@ logs(int priority, struct client *c, va_start(ap, fmt); - len = sizeof(c->addr); - ec = getnameinfo((struct sockaddr*)&c->addr, len, - hbuf, sizeof(hbuf), - sbuf, sizeof(sbuf), - NI_NUMERICHOST | NI_NUMERICSERV); - if (ec != 0) - fatal("getnameinfo: %s", gai_strerror(ec)); + if (c == NULL) { + strncpy(hbuf, "<internal>", sizeof(hbuf)); + sbuf[0] = '\0'; + } else { + len = sizeof(c->addr); + ec = getnameinfo((struct sockaddr*)&c->addr, len, + hbuf, sizeof(hbuf), + sbuf, sizeof(sbuf), + NI_NUMERICHOST | NI_NUMERICSERV); + if (ec != 0) + fatal("getnameinfo: %s", gai_strerror(ec)); + } if (vasprintf(&fmted, fmt, ap) == -1) fatal("vasprintf: %s", strerror(errno)); @@ -961,30 +960,6 @@ load_vhosts(struct tls_config *tlsconf) } } -/* we can augment this function to handle also capsicum and seccomp eventually */ -void -sandbox() -{ - struct vhost *h; - int has_cgi = 0; - - for (h = hosts; h->domain != NULL; ++h) { - if (unveil(h->dir, "rx") == -1) - err(1, "unveil %s for domain %s", h->dir, h->domain); - - if (h->cgi != NULL) - has_cgi = 1; - } - - if (pledge("stdio rpath inet proc exec", NULL) == -1) - err(1, "pledge"); - - /* drop proc and exec if cgi isn't enabled */ - if (!has_cgi) - if (pledge("stdio rpath inet", NULL) == -1) - err(1, "pledge"); -} - void usage(const char *me) { @@ -1002,7 +977,7 @@ main(int argc, char **argv) int sock4, sock6, ch; const char *config_path = NULL; size_t i; - int conftest = 0, has_cgi = 0; + int conftest = 0; bzero(hosts, sizeof(hosts)); for (i = 0; i < HOSTSLEN; ++i) @@ -28,11 +28,6 @@ #include <tls.h> #include <unistd.h> -#ifndef __OpenBSD__ -# define pledge(a, b) 0 -# define unveil(a, b) 0 -#endif - #ifndef INFTIM # define INFTIM -1 #endif @@ -52,6 +47,12 @@ #define HOSTSLEN 64 +#define LOGE(c, fmt, ...) logs(LOG_ERR, c, fmt, __VA_ARGS__) +#define LOGW(c, fmt, ...) logs(LOG_WARNING, c, fmt, __VA_ARGS__) +#define LOGN(c, fmt, ...) logs(LOG_NOTICE, c, fmt, __VA_ARGS__) +#define LOGI(c, fmt, ...) logs(LOG_INFO, c, fmt, __VA_ARGS__) +#define LOGD(c, fmt, ...) logs(LOG_DEBUG, c, fmt, __VA_ARGS__) + struct vhost { const char *domain; const char *cert; @@ -118,6 +119,8 @@ enum { }; /* gmid.c */ +__attribute__ ((format (printf, 3, 4))) void logs(int, struct client*, const char*, ...); + void sig_handler(int); int starts_with(const char*, const char*); @@ -149,7 +152,6 @@ void yyerror(const char*); int parse_portno(const char*); void parse_conf(const char*); void load_vhosts(struct tls_config*); -void sandbox(); void usage(const char*); @@ -158,6 +160,9 @@ extern int yylineno; extern int yyparse(void); extern int yylex(void); +/* sandbox.c */ +void sandbox(); + /* utf8.c */ int valid_multibyte_utf8(struct parser*); diff --git a/sandbox.c b/sandbox.c new file mode 100644 index 0000000..6618e5d --- /dev/null +++ b/sandbox.c @@ -0,0 +1,71 @@ +#include "gmid.h" + +#if defined(__FreeBSD__) + +#include <sys/capsicum.h> +#include <err.h> + +void +sandbox() +{ + struct vhost *h; + int has_cgi = 0; + + for (h = hosts; h->domain != NULL; ++h) + if (h->cgi != NULL) + has_cgi = 1; + + if (has_cgi) { + LOGW(NULL, "disabling sandbox because CGI scripts are enabled"); + return; + } + + if (cap_enter() == -1) + err(1, "cap_enter"); +} + +#elif defined(__linux__) + +void +sandbox() +{ + /* TODO: seccomp */ +} + +#elif defined(__OpenBSD__) + +#include <err.h> +#include <unistd.h> + +void +sandbox() +{ + struct vhost *h; + int has_cgi = 0; + + for (h = hosts; h->domain != NULL; ++h) { + if (unveil(h->dir, "rx") == -1) + err(1, "unveil %s for domain %s", h->dir, h->domain); + + if (h->cgi != NULL) + has_cgi = 1; + } + + if (pledge("stdio rpath inet proc exec", NULL) == -1) + err(1, "pledge"); + + /* drop proc and exec if cgi isn't enabled */ + if (!has_cgi) + if (pledge("stdio rpath inet", NULL) == -1) + err(1, "pledge"); +} + +#else + +void +sandbox() +{ + LOGN(NULL, "%s", "no sandbox method known for this OS"); +} + +#endif |