From de7cd12f9f08b81eb56f35b1f3b59f38a627c91a Mon Sep 17 00:00:00 2001 From: prx Date: Sun, 31 Jan 2021 21:21:15 +0100 Subject: [PATCH] ignore after ? and make cgi+virtualhost work (sort of) --- main.c | 29 +++++++++++++--------- tests/test.sh | 8 ++++++ tests/var/gemini/perso.pw/cgi-bin/test.cgi | 9 +++++++ vger.8 | 10 ++++---- 4 files changed, 39 insertions(+), 17 deletions(-) create mode 100755 tests/var/gemini/perso.pw/cgi-bin/test.cgi diff --git a/main.c b/main.c index 79bebb1..1a7c44f 100644 --- a/main.c +++ b/main.c @@ -82,6 +82,9 @@ drop_privileges(const char *user, const char *path) estrlcat(cgifullpath, cgibin, sizeof(cgifullpath)); eunveil(cgifullpath, "rx"); } + /* no more unveil later */ + eunveil(NULL, NULL); + /* * prevent system calls other parsing queryfor fread file and * write to stdio @@ -292,6 +295,7 @@ main(int argc, char **argv) char hostname [GEMINI_REQUEST_MAX] = {'\0'}; char uri [PATH_MAX] = {'\0'}; char user [_SC_LOGIN_NAME_MAX] = ""; + char query[PATH_MAX] = {'\0'}; int virtualhost = 0; int option = 0; char *pos = NULL; @@ -383,6 +387,14 @@ main(int argc, char **argv) /* copy hostname from request */ estrlcpy(hostname, request, sizeof(hostname)); + /* look for "?" if any to set query for cgi, or remove it*/ + pos = strchr(uri, '?'); + if (pos != NULL) { + estrlcpy(query, pos+1, sizeof(query)); + esetenv("QUERY_STRING", query, 1); + pos[0] = '\0'; + } + /* * if virtualhost feature is actived looking under the chroot_path + * hostname directory gemini://foobar/hello will look for @@ -392,15 +404,16 @@ main(int argc, char **argv) if (strlen(uri) == 0) { estrlcpy(uri, "/index.gmi", sizeof(uri)); } - char new_uri[PATH_MAX] = {'\0'}; - estrlcpy(new_uri, hostname, sizeof(new_uri)); - estrlcat(new_uri, uri, sizeof(new_uri)); - estrlcpy(uri, new_uri, sizeof(uri)); + char tmp[PATH_MAX] = {'\0'}; + estrlcpy(tmp, hostname, sizeof(tmp)); + estrlcat(tmp, uri, sizeof(tmp)); + estrlcpy(uri, tmp, sizeof(uri)); } /* check if uri is cgibin */ if ((strlen(cgibin) > 0) && (strncmp(uri, cgibin, strlen(cgibin)) == 0)) { + char cgipath[PATH_MAX] = {'\0'}; estrlcpy(cgipath, chroot_dir, sizeof(cgipath)); estrlcat(cgipath, uri, sizeof(cgipath)); @@ -410,14 +423,6 @@ main(int argc, char **argv) esetenv("SERVER_PROTOCOL", "GEMINI", 1); esetenv("SERVER_SOFTWARE", "vger/1", 1); - /* look for "?" to set query */ - pos = strchr(cgipath, '?'); - if (pos != NULL) { - char query[PATH_MAX] = {'\0'}; - estrlcpy(query, pos+1, sizeof(query)); - esetenv("QUERY_STRING", query, 1); - pos[0] = '\0'; - } /* look for an extension to find PATH_INFO */ pos = strrchr(cgipath, '.'); if (pos != NULL) { diff --git a/tests/test.sh b/tests/test.sh index abe914a..bad3c1a 100644 --- a/tests/test.sh +++ b/tests/test.sh @@ -86,6 +86,14 @@ if ! [ $OUT = "fa065a67d1f7c973501d4a9e3ca2ea57" ] ; then echo "error" ; exit 1 OUT=$(printf "gemini://host.name/cgi-bin/nope\r\n" | ../vger -d var/gemini/ -c /cgi-bin | tee /dev/stderr | $MD5) if ! [ $OUT = "2c88347cfac44450035283a8508a29cb" ] ; then echo "error" ; exit 1 ; fi +# remove ?.* if any +OUT=$(printf "gemini://host.name/main.gmi?anything-here\r\n" | ../vger -d var/gemini/ | tee /dev/stderr | $MD5) +if ! [ $OUT = "c7e352d6aae4ee7e7604548f7874fb9d" ] ; then echo "error" ; exit 1 ; fi + +# virtualhost + cgi +OUT=$(printf "gemini://perso.pw/cgi-bin/test.cgi\r\n" | ../vger -v -d var/gemini/ -c perso.pw/cgi-bin | tee /dev/stderr | $MD5) +if ! [ $OUT = "666e48200f90018b5e96c2cf974882dc" ] ; then echo "error" ; exit 1 ; fi + # must fail only on OpenBSD ! # try to escape from unveil if [ -f /bsd ] diff --git a/tests/var/gemini/perso.pw/cgi-bin/test.cgi b/tests/var/gemini/perso.pw/cgi-bin/test.cgi new file mode 100755 index 0000000..7c67506 --- /dev/null +++ b/tests/var/gemini/perso.pw/cgi-bin/test.cgi @@ -0,0 +1,9 @@ +#!/bin/sh + +printf "%s %s: cgi_test\r\n" "20 text/plain" + +echo "env vars:" +echo $GATEWAY_INTERFACE +echo $SERVER_SOFTWARE +echo $PATH_INFO +echo $QUERY_STRING diff --git a/vger.8 b/vger.8 index 948f177..c172b64 100644 --- a/vger.8 +++ b/vger.8 @@ -44,7 +44,10 @@ will read the file /var/gemini/hostname.example/file.gmi .It Op Fl c Enable CGI support. .Ar cgi_path -will be executed as a cgi script. This path is relative to the served capsule. As example, for a request gemini://hostname.example/cgi-bin/hello.cgi, one must set: +will be executed as a cgi script. This path is relative to the directory set with +.Fl d +flag. If using virtualhost, you must insert the virtualhost directory in the cgi path. +As example, for a request gemini://hostname.example/cgi-bin/hello.cgi, one must set: .Bd -literal -offset indent vger -c /cgi-bin/hello.cgi .Ed @@ -53,10 +56,7 @@ Note you can define a directory instead of a single file. .Pp In this case, .Xr pledge 2 -promises are set to "stdio proc exec" -and an additional -.Xr unveil 2 -permission on the cgi script is set to "rx". +promises and unveil permission are set to enable cgi execution. .Pp Be very careful on how you write your CGI, it can read outside the chroot. .It Op Fl m Ar mimetype