chroot & drop privileges

This commit is contained in:
Omar Polo 2021-01-25 10:30:07 +00:00
parent 2030e31486
commit ae08ec7da5
5 changed files with 95 additions and 23 deletions

16
gmid.1
View File

@ -129,6 +129,22 @@ Add a mapping for the given
to the given to the given
.Ar mime-type . .Ar mime-type .
Both argument are strings. 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 .El
.Ss Servers .Ss Servers
Every virtual host is defined by a Every virtual host is defined by a

79
gmid.c
View File

@ -18,6 +18,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <netdb.h> #include <netdb.h>
#include <pwd.h>
#include <signal.h> #include <signal.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
@ -32,6 +33,8 @@ int exfd;
struct conf conf; struct conf conf;
struct tls *ctx;
void void
fatal(const char *fmt, ...) fatal(const char *fmt, ...)
{ {
@ -242,19 +245,11 @@ parse_conf(const char *path)
} }
void void
load_vhosts(struct tls_config *tlsconf) load_vhosts(void)
{ {
struct vhost *h; 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) { 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) if ((h->dirfd = open(h->dir, O_RDONLY | O_DIRECTORY)) == -1)
fatal("open %s for domain %s", h->dir, h->domain); fatal("open %s for domain %s", h->dir, h->domain);
} }
@ -315,14 +310,11 @@ make_socket(int port, int family)
return sock; return sock;
} }
int void
listener_main() setup_tls(void)
{ {
int sock4, sock6;
struct tls *ctx = NULL;
struct tls_config *tlsconf; struct tls_config *tlsconf;
struct vhost *h;
load_default_mime(&conf.mime);
if ((tlsconf = tls_config_new()) == NULL) if ((tlsconf = tls_config_new()) == NULL)
fatal("tls_config_new"); fatal("tls_config_new");
@ -337,10 +329,26 @@ listener_main()
if ((ctx = tls_server()) == NULL) if ((ctx = tls_server()) == NULL)
fatal("tls_server failure"); 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) if (tls_configure(ctx, tlsconf) == -1)
fatal("tls_configure: %s", tls_error(ctx)); 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) if (!conf.foreground && daemon(0, 1) == -1)
exit(1); exit(1);
@ -350,6 +358,8 @@ listener_main()
if (conf.ipv6) if (conf.ipv6)
sock6 = make_socket(conf.port, AF_INET6); sock6 = make_socket(conf.port, AF_INET6);
load_vhosts();
sandbox(); sandbox();
loop(ctx, sock4, sock6); loop(ctx, sock4, sock6);
@ -371,6 +381,38 @@ init_config(void)
conf.protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3; conf.protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
init_mime(&conf.mime); 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 void
@ -461,6 +503,11 @@ main(int argc, char **argv)
return 0; 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(SIGPIPE, SIG_IGN);
signal(SIGCHLD, SIG_IGN); signal(SIGCHLD, SIG_IGN);

16
gmid.h
View File

@ -92,11 +92,13 @@ struct mime {
}; };
struct conf { struct conf {
int foreground; int foreground;
int port; int port;
int ipv6; int ipv6;
uint32_t protos; uint32_t protos;
struct mime mime; struct mime mime;
char *chroot;
char *user;
}; };
extern struct conf conf; extern struct conf conf;
@ -169,10 +171,12 @@ char *absolutify_path(const char*);
void yyerror(const char*); void yyerror(const char*);
int parse_portno(const char*); int parse_portno(const char*);
void parse_conf(const char*); void parse_conf(const char*);
void load_vhosts(struct tls_config*); void load_vhosts(void);
int make_socket(int, int); int make_socket(int, int);
void setup_tls(void);
int listener_main(void); int listener_main(void);
void init_config(void); void init_config(void);
void drop_priv(void);
void usage(const char*); void usage(const char*);
/* provided by lex/yacc */ /* provided by lex/yacc */

2
lex.l
View File

@ -58,6 +58,8 @@ protocols return TPROTOCOLS;
mime return TMIME; mime return TMIME;
default return TDEFAULT; default return TDEFAULT;
type return TTYPE; type return TTYPE;
chroot return TCHROOT;
user return TUSER;
server return TSERVER; server return TSERVER;
location return TLOCATION; location return TLOCATION;

View File

@ -45,7 +45,8 @@ extern void yyerror(const char*);
int num; 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 TLOCATION TCERT TKEY TROOT TCGI TLANG TINDEX TAUTO
%token TERR %token TERR
@ -69,6 +70,8 @@ option : TDAEMON TBOOL { conf.foreground = !$2; }
errx(1, "invalid protocols string \"%s\"", $2); errx(1, "invalid protocols string \"%s\"", $2);
} }
| TMIME TSTRING TSTRING { add_mime(&conf.mime, $2, $3); } | TMIME TSTRING TSTRING { add_mime(&conf.mime, $2, $3); }
| TCHROOT TSTRING { conf.chroot = $2; }
| TUSER TSTRING { conf.user = $2; }
; ;
vhosts : /* empty */ vhosts : /* empty */