[dev] [quark] [PATCH] Add the chrootdir configuration variable

From: Ivan Delalande <colona_AT_ycc.fr>
Date: Sat, 29 Nov 2014 08:42:17 +0100

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.
---
 config.def.h |  1 +
 quark.1      |  7 ++++++-
 quark.c      | 43 +++++++++++++++++++++++++++++--------------
 3 files changed, 36 insertions(+), 15 deletions(-)
diff --git a/config.def.h b/config.def.h
index 35ee857..716fb0d 100644
--- a/config.def.h
+++ b/config.def.h
_AT_@ -2,6 +2,7 @@
 
 static const char *servername = "127.0.0.1";
 static const char *serverport = "80";
+static const char *chrootdir  = ".";
 static const char *docroot    = ".";
 static const char *docindex   = "index.html";
 static const char *user       = "nobody";
diff --git a/quark.1 b/quark.1
index ceee081..35f854c 100644
--- a/quark.1
+++ b/quark.1
_AT_@ -4,6 +4,8 @@ quark \- simple httpd
 .SH SYNOPSIS
 .B quark
 .RB [ \-c ]
+.RB [ \-C
+.IR chrootdir ]
 .RB [ \-d
 .IR cgidir ]
 .RB [ \-e
_AT_@ -29,6 +31,9 @@ Quark is a simple httpd.
 .B \-c
 enable CGI-mode, disabled by default.
 .TP
+.B \-C " chrootdir"
+chroot into chrootdir, by default ".".
+.TP
 .B \-d " cgidir"
 change directory to cgidir for CGI-mode, by default ".".
 .TP
_AT_@ -48,7 +53,7 @@ enable directory listing, disabled by default.
 listen on port, by default "80".
 .TP
 .B \-r " docroot"
-change directory to docroot, by default ".".
+change directory to docroot for static files, by default ".".
 .TP
 .B \-s " server"
 listen on server, by default "127.0.0.1".
diff --git a/quark.c b/quark.c
index d211abb..575eaa0 100644
--- a/quark.c
+++ b/quark.c
_AT_@ -93,7 +93,8 @@ static char location[256];
 static int running = 1;
 static int status;
 static char host[NI_MAXHOST];
-static char reqbuf[MAXBUFLEN];
+static char* reqbuf = NULL;
+static char* reqpath = NULL;
 static char resbuf[MAXBUFLEN];
 static char reqhost[256];
 static char reqmod[256];
_AT_@ -204,7 +205,7 @@ responsefile(void) {
 	int r, ffd;
 	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 */
 		if (putresentry(HEADER, HttpNotFound, tstamp(0))
 		 || putresentry(CONTENTTYPE, texthtml))
_AT_@ -291,8 +292,8 @@ responsedir(void) {
 		return;
 	}
 	if (len + strlen(docindex) + 1 < MAXBUFLEN)
-		memcpy(reqbuf + len, docindex, strlen(docindex) + 1);
-	if (access(reqbuf, R_OK) == -1) { /* directory mode */
+		memmove(reqbuf + len, docindex, strlen(docindex) + 1);
+	if (access(reqpath, R_OK) == -1) { /* directory mode */
 		reqbuf[len] = 0; /* cut off docindex again */
 		if(!allowdirlist) {
 			if (putresentry(HEADER, HttpForbidden, tstamp(0))
_AT_@ -303,12 +304,12 @@ responsedir(void) {
 				writetext("\r\n<html><body>"HttpForbidden"</body></html>\r\n");
 			return;
 		}
-		if ((n = scandir(reqbuf, &namelist, NULL, alphasort)) >= 0) {
+		if ((n = scandir(reqpath, &namelist, NULL, alphasort)) >= 0) {
 			responsedirdata(namelist, n);
 			free(namelist);
 		} else {
 			logerrmsg("client %s requests %s but scandir failed: %s\n",
-				  host, reqbuf, strerror(errno));
+				  host, reqpath, strerror(errno));
 		}
 	} else {
 		responsefile(); /* docindex */
_AT_@ -406,7 +407,7 @@ response(void) {
 		}
 	}
 
-	r = stat(reqbuf, &st);
+	r = stat(reqpath, &st);
 	if (cgi_mode) {
 		if(r != -1 && !S_ISDIR(st.st_mode))
 			responsefile();
_AT_@ -562,9 +563,9 @@ sighandler(int sig) {
 
 void
 usage(void) {
-	fprintf(stderr, "usage: quark [-c] [-d cgidir] [-e cgiscript] [-g group] "
-	                "[-i index] [-l] [-p port] [-r docroot] [-s server] "
-	                "[-u user] [-v]\n");
+	fprintf(stderr, "usage: quark [-c] [-C chrootdir] [-d cgidir] "
+					"[-e cgiscript] [-g group] [-i index] [-l] [-p port] "
+					"[-r docroot] [-s server] [-u user] [-v]\n");
 	exit(EXIT_FAILURE);
 }
 
_AT_@ -574,12 +575,15 @@ main(int argc, char *argv[]) {
 	struct passwd *upwd = NULL;
 	struct group *gpwd = NULL;
 	struct rlimit rlim;
-	int i;
+	int i, docrootlen;
 
 	ARGBEGIN {
 	case 'c':
 		cgi_mode = 1;
 		break;
+	case 'C':
+		chrootdir = EARGF(usage());
+		break;
 	case 'd':
 		cgi_dir = EARGF(usage());
 		break;
_AT_@ -619,6 +623,15 @@ main(int argc, char *argv[]) {
 	if (group && *group && !(gpwd = getgrnam(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(SIGHUP, sighandler);
 	signal(SIGINT, sighandler);
_AT_@ -666,8 +679,8 @@ main(int argc, char *argv[]) {
 		goto err;
 	}
 
-	if (chdir(docroot) == -1) {
-		logerrmsg("error\tchdir %s: %s\n", docroot, strerror(errno));
+	if (chdir(chrootdir) == -1) {
+		logerrmsg("error\tchdir %s: %s\n", chrootdir, strerror(errno));
 		goto err;
 	}
 	if (chroot(".") == -1) {
_AT_@ -693,15 +706,17 @@ main(int argc, char *argv[]) {
 		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 */
 	close(listenfd);
+	free(reqpath);
 	freeaddrinfo(ai);
 	return EXIT_SUCCESS;
 err:
 	if (listenfd != -1)
 		close(listenfd);
+	free(reqpath);
 	if (ai)
 		freeaddrinfo(ai);
 	return EXIT_FAILURE;
-- 
2.1.3
-- 
Ivan "Colona" Delalande
Received on Sat Nov 29 2014 - 08:42:17 CET

This archive was generated by hypermail 2.3.0 : Sat Nov 29 2014 - 08:48:12 CET