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
.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

79
gmid.c
View File

@ -18,6 +18,7 @@
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <string.h>
@ -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,10 +329,26 @@ 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,6 +381,38 @@ 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
@ -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);

16
gmid.h
View File

@ -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 */

2
lex.l
View File

@ -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;

View File

@ -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 */