change the behavior of docroot

Change the behavior of docroot, which is now used as a prefix path for
all file operations related to static files. And add chrootdir, which is
just the old docroot behavior and allows to control the path into which
quark will chroot.

Not having properly distinct configuration variables for chroot,
document root and CGI root was specially annoying since commit 2822488
which allowed users to retrieve the CGI script or binary by just
guessing its path, since quark was chrooting into docroot before
anything else, and thus the CGI script/binary was in the user accessible
path.

This is implemented by moving the reqbuf buffer in the middle of a
bigger buffer, reqpath. That buffer contains the value of docroot at its
beginning and reqbuf simply points to the first byte after this value.
This commit is contained in:
Ivan Delalande 2014-11-30 14:37:28 +01:00 committed by FRIGN
parent 4674ccde50
commit e42bb27846
3 changed files with 36 additions and 15 deletions

View file

@ -2,6 +2,7 @@
static const char *servername = "127.0.0.1"; static const char *servername = "127.0.0.1";
static const char *serverport = "80"; static const char *serverport = "80";
static const char *chrootdir = ".";
static const char *docroot = "."; static const char *docroot = ".";
static const char *docindex = "index.html"; static const char *docindex = "index.html";
static const char *user = "nobody"; static const char *user = "nobody";

View file

@ -4,6 +4,8 @@ quark \- simple httpd
.SH SYNOPSIS .SH SYNOPSIS
.B quark .B quark
.RB [ \-c ] .RB [ \-c ]
.RB [ \-C
.IR chrootdir ]
.RB [ \-d .RB [ \-d
.IR cgidir ] .IR cgidir ]
.RB [ \-e .RB [ \-e
@ -29,6 +31,9 @@ Quark is a simple httpd.
.B \-c .B \-c
enable CGI-mode, disabled by default. enable CGI-mode, disabled by default.
.TP .TP
.B \-C " chrootdir"
chroot into chrootdir, by default ".".
.TP
.B \-d " cgidir" .B \-d " cgidir"
change directory to cgidir for CGI-mode, by default ".". change directory to cgidir for CGI-mode, by default ".".
.TP .TP
@ -48,7 +53,7 @@ enable directory listing, disabled by default.
listen on port, by default "80". listen on port, by default "80".
.TP .TP
.B \-r " docroot" .B \-r " docroot"
change directory to docroot, by default ".". change directory to docroot for static files, by default ".".
.TP .TP
.B \-s " server" .B \-s " server"
listen on server, by default "127.0.0.1". listen on server, by default "127.0.0.1".

43
quark.c
View file

@ -93,7 +93,8 @@ static char location[256];
static int running = 1; static int running = 1;
static int status; static int status;
static char host[NI_MAXHOST]; static char host[NI_MAXHOST];
static char reqbuf[MAXBUFLEN]; static char* reqbuf = NULL;
static char* reqpath = NULL;
static char resbuf[MAXBUFLEN]; static char resbuf[MAXBUFLEN];
static char reqhost[256]; static char reqhost[256];
static char reqmod[256]; static char reqmod[256];
@ -204,7 +205,7 @@ responsefile(void) {
int r, ffd; int r, ffd;
struct stat st; struct stat st;
if ((r = stat(reqbuf, &st)) == -1 || (ffd = open(reqbuf, O_RDONLY)) == -1) { if ((r = stat(reqpath, &st)) == -1 || (ffd = open(reqpath, O_RDONLY)) == -1) {
/* file not found */ /* file not found */
if (putresentry(HEADER, HttpNotFound, tstamp(0)) if (putresentry(HEADER, HttpNotFound, tstamp(0))
|| putresentry(CONTENTTYPE, texthtml)) || putresentry(CONTENTTYPE, texthtml))
@ -291,8 +292,8 @@ responsedir(void) {
return; return;
} }
if (len + strlen(docindex) + 1 < MAXBUFLEN) if (len + strlen(docindex) + 1 < MAXBUFLEN)
memcpy(reqbuf + len, docindex, strlen(docindex) + 1); memmove(reqbuf + len, docindex, strlen(docindex) + 1);
if (access(reqbuf, R_OK) == -1) { /* directory mode */ if (access(reqpath, R_OK) == -1) { /* directory mode */
reqbuf[len] = 0; /* cut off docindex again */ reqbuf[len] = 0; /* cut off docindex again */
if(!allowdirlist) { if(!allowdirlist) {
if (putresentry(HEADER, HttpForbidden, tstamp(0)) if (putresentry(HEADER, HttpForbidden, tstamp(0))
@ -303,12 +304,12 @@ responsedir(void) {
writetext("\r\n<html><body>"HttpForbidden"</body></html>\r\n"); writetext("\r\n<html><body>"HttpForbidden"</body></html>\r\n");
return; return;
} }
if ((n = scandir(reqbuf, &namelist, NULL, alphasort)) >= 0) { if ((n = scandir(reqpath, &namelist, NULL, alphasort)) >= 0) {
responsedirdata(namelist, n); responsedirdata(namelist, n);
free(namelist); free(namelist);
} else { } else {
logerrmsg("client %s requests %s but scandir failed: %s\n", logerrmsg("client %s requests %s but scandir failed: %s\n",
host, reqbuf, strerror(errno)); host, reqpath, strerror(errno));
} }
} else { } else {
responsefile(); /* docindex */ responsefile(); /* docindex */
@ -406,7 +407,7 @@ response(void) {
} }
} }
r = stat(reqbuf, &st); r = stat(reqpath, &st);
if (cgi_mode) { if (cgi_mode) {
if(r != -1 && !S_ISDIR(st.st_mode)) if(r != -1 && !S_ISDIR(st.st_mode))
responsefile(); responsefile();
@ -562,9 +563,9 @@ sighandler(int sig) {
void void
usage(void) { usage(void) {
fprintf(stderr, "usage: quark [-c] [-d cgidir] [-e cgiscript] [-g group] " fprintf(stderr, "usage: quark [-c] [-C chrootdir] [-d cgidir] "
"[-i index] [-l] [-p port] [-r docroot] [-s server] " "[-e cgiscript] [-g group] [-i index] [-l] [-p port] "
"[-u user] [-v]\n"); "[-r docroot] [-s server] [-u user] [-v]\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -574,12 +575,15 @@ main(int argc, char *argv[]) {
struct passwd *upwd = NULL; struct passwd *upwd = NULL;
struct group *gpwd = NULL; struct group *gpwd = NULL;
struct rlimit rlim; struct rlimit rlim;
int i; int i, docrootlen;
ARGBEGIN { ARGBEGIN {
case 'c': case 'c':
cgi_mode = 1; cgi_mode = 1;
break; break;
case 'C':
chrootdir = EARGF(usage());
break;
case 'd': case 'd':
cgi_dir = EARGF(usage()); cgi_dir = EARGF(usage());
break; break;
@ -619,6 +623,15 @@ main(int argc, char *argv[]) {
if (group && *group && !(gpwd = getgrnam(group))) if (group && *group && !(gpwd = getgrnam(group)))
die("error\tinvalid group %s\n", group); die("error\tinvalid group %s\n", group);
docrootlen = strlen(docroot);
reqpath = malloc(docrootlen + MAXBUFLEN);
if (reqpath == NULL) {
logerrmsg("error\tcannot allocate memory\n");
goto err;
}
memcpy(reqpath, docroot, docrootlen + 1);
reqbuf = reqpath + docrootlen;
signal(SIGCHLD, sighandler); signal(SIGCHLD, sighandler);
signal(SIGHUP, sighandler); signal(SIGHUP, sighandler);
signal(SIGINT, sighandler); signal(SIGINT, sighandler);
@ -666,8 +679,8 @@ main(int argc, char *argv[]) {
goto err; goto err;
} }
if (chdir(docroot) == -1) { if (chdir(chrootdir) == -1) {
logerrmsg("error\tchdir %s: %s\n", docroot, strerror(errno)); logerrmsg("error\tchdir %s: %s\n", chrootdir, strerror(errno));
goto err; goto err;
} }
if (chroot(".") == -1) { if (chroot(".") == -1) {
@ -693,15 +706,17 @@ main(int argc, char *argv[]) {
goto err; goto err;
} }
logmsg("ready\t%s:%s\t%s\n", servername, serverport, docroot); logmsg("ready\t%s:%s\t%s\n", servername, serverport, chrootdir);
serve(listenfd); /* main loop */ serve(listenfd); /* main loop */
close(listenfd); close(listenfd);
free(reqpath);
freeaddrinfo(ai); freeaddrinfo(ai);
return EXIT_SUCCESS; return EXIT_SUCCESS;
err: err:
if (listenfd != -1) if (listenfd != -1)
close(listenfd); close(listenfd);
free(reqpath);
if (ai) if (ai)
freeaddrinfo(ai); freeaddrinfo(ai);
return EXIT_FAILURE; return EXIT_FAILURE;