commit ae08ec7da5bf349bea4621219df41f297b3116e9 from: Omar Polo date: Mon Jan 25 10:30:07 2021 UTC chroot & drop privileges commit - 2030e314860f1ba4a1b0294b741164dca2391466 commit + ae08ec7da5bf349bea4621219df41f297b3116e9 blob - ad0aeba97f7232a1d19b9386ae486e802cb90884 blob + 4382cd017e3394902cda8acc1039180613f0b74f --- gmid.1 +++ gmid.1 @@ -129,6 +129,22 @@ Add a mapping for the given to the given .Ar mime-type . Both argument are strings. +.It Ic chroot Pa path +.Xr chroot 2 +the process to the given +.Pa path . +The daemon has to be run with root privileges and thus the option +.Ic user +needs to be provided, so +.Nm +can drop the privileges. +Note that they are dropped after loading the TLS keys, so it's +recommended to put those outside the chroot. +Future version of +.Nm +may require this. +.It Ic user Ar string +Run the daemon as the given user. .El .Ss Servers Every virtual host is defined by a blob - f2db8c66f860bc88d146e1aa0dd60cada498403c blob + 7b1238e37afbcfbfe0d8ed4fd64d3f936768f082 --- gmid.c +++ gmid.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,8 @@ int exfd; struct conf conf; +struct tls *ctx; + void fatal(const char *fmt, ...) { @@ -242,19 +245,11 @@ parse_conf(const char *path) } void -load_vhosts(struct tls_config *tlsconf) +load_vhosts(void) { struct vhost *h; - /* we need to set something, then we can add how many key we want */ - if (tls_config_set_keypair_file(tlsconf, hosts->cert, hosts->key)) - fatal("tls_config_set_keypair_file failed"); - for (h = hosts; h->domain != NULL; ++h) { - if (tls_config_add_keypair_file(tlsconf, h->cert, h->key) == -1) - fatal("failed to load the keypair (%s, %s)", - h->cert, h->key); - if ((h->dirfd = open(h->dir, O_RDONLY | O_DIRECTORY)) == -1) fatal("open %s for domain %s", h->dir, h->domain); } @@ -315,14 +310,11 @@ make_socket(int port, int family) return sock; } -int -listener_main() +void +setup_tls(void) { - int sock4, sock6; - struct tls *ctx = NULL; struct tls_config *tlsconf; - - load_default_mime(&conf.mime); + struct vhost *h; if ((tlsconf = tls_config_new()) == NULL) fatal("tls_config_new"); @@ -337,11 +329,27 @@ listener_main() if ((ctx = tls_server()) == NULL) fatal("tls_server failure"); - load_vhosts(tlsconf); + /* we need to set something, then we can add how many key we want */ + if (tls_config_set_keypair_file(tlsconf, hosts->cert, hosts->key)) + fatal("tls_config_set_keypair_file failed"); + for (h = hosts; h->domain != NULL; ++h) { + if (tls_config_add_keypair_file(tlsconf, h->cert, h->key) == -1) + fatal("failed to load the keypair (%s, %s)", + h->cert, h->key); + } + if (tls_configure(ctx, tlsconf) == -1) fatal("tls_configure: %s", tls_error(ctx)); +} +int +listener_main(void) +{ + int sock4, sock6; + + load_default_mime(&conf.mime); + if (!conf.foreground && daemon(0, 1) == -1) exit(1); @@ -350,6 +358,8 @@ listener_main() if (conf.ipv6) sock6 = make_socket(conf.port, AF_INET6); + load_vhosts(); + sandbox(); loop(ctx, sock4, sock6); @@ -371,9 +381,41 @@ init_config(void) conf.protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3; init_mime(&conf.mime); + + conf.chroot = NULL; + conf.user = NULL; } void +drop_priv(void) +{ + struct passwd *pw = NULL; + + if (conf.chroot != NULL && conf.user == NULL) + fatal("can't chroot without an user to switch to after."); + + if (conf.user != NULL) { + if ((pw = getpwnam(conf.user)) == NULL) + fatal("can't find user %s", conf.user); + } + + if (conf.chroot != NULL) { + if (chroot(conf.chroot) != 0 || chdir("/") != 0) + fatal("%s: %s", conf.chroot, strerror(errno)); + } + + if (pw != NULL) { + if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) + fatal("setresuid(%d): %s", pw->pw_uid, + strerror(errno)); + } + + if (getuid() == 0) + LOGW(NULL, "%s", + "not a good idea to run a network daemon as root"); +} + +void usage(const char *me) { fprintf(stderr, @@ -461,6 +503,11 @@ main(int argc, char **argv) return 0; } + /* setup tls before dropping privileges: we don't want user + * to put private certs inside the chroot. */ + setup_tls(); + drop_priv(); + signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); blob - 2364e7c7bc0cbda5e0eeb965b11ca858c6c21db1 blob + 968559bddf67af3f24a4879b61fd3bf1783d0594 --- gmid.h +++ gmid.h @@ -92,11 +92,13 @@ struct mime { }; struct conf { - int foreground; - int port; - int ipv6; - uint32_t protos; - struct mime mime; + int foreground; + int port; + int ipv6; + uint32_t protos; + struct mime mime; + char *chroot; + char *user; }; extern struct conf conf; @@ -169,10 +171,12 @@ char *absolutify_path(const char*); void yyerror(const char*); int parse_portno(const char*); void parse_conf(const char*); -void load_vhosts(struct tls_config*); +void load_vhosts(void); int make_socket(int, int); +void setup_tls(void); int listener_main(void); void init_config(void); +void drop_priv(void); void usage(const char*); /* provided by lex/yacc */ blob - 240f7c466e7c1551d21d5664d4aaab6974aba9d3 blob + 099b3c4b19d822ba495bb7d4980f114d99cbd54f --- lex.l +++ lex.l @@ -58,6 +58,8 @@ protocols return TPROTOCOLS; mime return TMIME; default return TDEFAULT; type return TTYPE; +chroot return TCHROOT; +user return TUSER; server return TSERVER; location return TLOCATION; blob - 5e7cb216241e588d84ac594ed7b7a2ef4a4671cc blob + 97934599fd9039217e0a83785418fb3fb5a25d6f --- parse.y +++ parse.y @@ -45,7 +45,8 @@ extern void yyerror(const char*); int num; } -%token TDAEMON TIPV6 TPORT TPROTOCOLS TMIME TDEFAULT TTYPE TSERVER +%token TDAEMON TIPV6 TPORT TPROTOCOLS TMIME TDEFAULT TTYPE +%token TCHROOT TUSER TSERVER %token TLOCATION TCERT TKEY TROOT TCGI TLANG TINDEX TAUTO %token TERR @@ -69,6 +70,8 @@ option : TDAEMON TBOOL { conf.foreground = !$2; } errx(1, "invalid protocols string \"%s\"", $2); } | TMIME TSTRING TSTRING { add_mime(&conf.mime, $2, $3); } + | TCHROOT TSTRING { conf.chroot = $2; } + | TUSER TSTRING { conf.user = $2; } ; vhosts : /* empty */