Add chroot() feature

This commit is contained in:
Solene Rapenne 2020-12-03 22:59:39 +01:00
parent f00fb88c62
commit b3bb3b2f91
4 changed files with 53 additions and 9 deletions

View file

@ -1,7 +1,7 @@
# A simplistic and secure Gemini server # A simplistic and secure Gemini server
**Vger** is a gemini server supporting virtualhosts, default language **Vger** is a gemini server supporting chroot, virtualhosts, default
choice and MIME types detection. language choice and MIME types detection.
**Vger** design is relying on inetd and a daemon to take care of **Vger** design is relying on inetd and a daemon to take care of
TLS. The idea is to delegate TLS and network to daemons which TLS. The idea is to delegate TLS and network to daemons which
@ -43,9 +43,10 @@ without a `-d` parameter.
**Vger** has a few parameters you can use in inetd configuration. **Vger** has a few parameters you can use in inetd configuration.
- `-d PATH`: use `PATH` to look for files. Default is `/var/gemini` - `-d PATH`: use `PATH` as the data directory to serve files from. Default is `/var/gemini`
- `-l LANG`: change the language in the status return code. Default is `en` - `-l LANG`: change the language in the status return code. Default is `en`
- `-v`: enable virtualhost support, the hostname in the query will be considered as a directory name. - `-v`: enable virtualhost support, the hostname in the query will be considered as a directory name.
- `-u username`: enable chroot to the data directory and drop privileges to `username`.
# How to configure Vger using relayd and inetd # How to configure Vger using relayd and inetd

38
main.c
View file

@ -1,10 +1,11 @@
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mimes.c" #include "mimes.c"
#define BUFF_LEN_1 1000 #define BUFF_LEN_1 1000
@ -92,12 +93,14 @@ main(int argc, char **argv)
char file [BUFF_LEN_2]; char file [BUFF_LEN_2];
char path [BUFF_LEN_2] = DEFAULT_CHROOT; char path [BUFF_LEN_2] = DEFAULT_CHROOT;
char lang [3] = DEFAULT_LANG; char lang [3] = DEFAULT_LANG;
char user [_SC_LOGIN_NAME_MAX];
struct passwd *pw;
int virtualhost = 0; int virtualhost = 0;
int option; int option;
int start_with_gemini; int start_with_gemini;
char *pos; char *pos;
while ((option = getopt(argc, argv, ":d:l:v")) != -1) { while ((option = getopt(argc, argv, ":d:l:u:v")) != -1) {
switch (option) { switch (option) {
case 'd': case 'd':
strlcpy(path, optarg, sizeof(path)); strlcpy(path, optarg, sizeof(path));
@ -108,10 +111,33 @@ main(int argc, char **argv)
case 'l': case 'l':
strlcpy(lang, optarg, sizeof(lang)); strlcpy(lang, optarg, sizeof(lang));
break; break;
case 'u':
strlcpy(user, optarg, sizeof(user));
break;
} }
} }
/*
* use chroot() if an user is specified requires root user to be
* running the program to run chroot() and then drop privileges
*/
if (strlen(user) > 0) {
/* is root? */
if (getuid() != 0)
err(1, "chroot requires root user");
/* search user uid from name */
if ((pw = getpwnam(user)) == NULL)
err(1, "finding user");
/* chroot worked? */
if (chroot(path) != 0)
err(1, "chroot");
/* drop privileges */
if (setuid(pw->pw_uid) != 0)
err(1, "Can't drop privileges");
}
#ifdef __OpenBSD__ #ifdef __OpenBSD__
/* /*
* prevent access to files other than the one in path * prevent access to files other than the one in path

View file

@ -42,6 +42,13 @@ if ! [ $OUT = "0d36a423a4e8be813fda4022f08b3844" ] ; then echo "error" ; exit 1
OUT=$(printf "gemini://perso.pw\r\n" | ../vger -v -d var/gemini/ -l fr | tee /dev/stderr | $MD5) OUT=$(printf "gemini://perso.pw\r\n" | ../vger -v -d var/gemini/ -l fr | tee /dev/stderr | $MD5)
if ! [ $OUT = "7db981ce93fee268f29324912800f00d" ] ; then echo "error" ; exit 1 ; fi if ! [ $OUT = "7db981ce93fee268f29324912800f00d" ] ; then echo "error" ; exit 1 ; fi
type doas 2>/dev/null
if [ $? -eq 0 ]; then
# file from local directory chroot
OUT=$(printf "gemini://perso.pw\r\n" | doas ../vger -v -d var/gemini/ -u solene -l fr | tee /dev/stderr | $MD5)
if ! [ $OUT = "7db981ce93fee268f29324912800f00d" ] ; then echo "error" ; exit 1 ; fi
fi
#### no -d parameter from here #### no -d parameter from here
if [ -d /var/gemini/ ] if [ -d /var/gemini/ ]

10
vger.8
View file

@ -9,6 +9,7 @@
.Op Fl l Ar lang .Op Fl l Ar lang
.Op Fl v .Op Fl v
.Op Fl d Ar path .Op Fl d Ar path
.Op Fl u Ar username
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
is a secure gemini server that is meant to be run on is a secure gemini server that is meant to be run on
@ -40,6 +41,14 @@ On
will use will use
.Xr unveil 2 .Xr unveil 2
on this path in read-only to prevent file access outside this directory. on this path in read-only to prevent file access outside this directory.
.It Op Fl u Ar username
Enable
.Xr chroot 2
on the data directory and then drop privileges to
.Ar username .
This requires
.Nm
to be run as root user.
.El .El
.Sh DEPLOYMENT .Sh DEPLOYMENT
.Nm .Nm
@ -70,6 +79,7 @@ relay "gemini" {
} }
.Ed .Ed
.Sh SEE ALSO .Sh SEE ALSO
.Xr chroot 2 ,
.Xr unveil 2 , .Xr unveil 2 ,
.Xr relayd.conf 5 , .Xr relayd.conf 5 ,
.Xr inetd 8 , .Xr inetd 8 ,