From 7431d3eeec4c6bca30a9c04f503d5b359b1d0aef Mon Sep 17 00:00:00 2001 From: Omar Polo Date: Sat, 6 Mar 2021 20:21:13 +0000 Subject: [PATCH 1/5] Use the correct error codes and meaningful explanations Introduce status_error: it's like status or status_redirect but for errors, thus it doesn't add ``;lang=$lang'' at the end. --- main.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/main.c b/main.c index 42fc6eb..351f7ad 100644 --- a/main.c +++ b/main.c @@ -32,6 +32,7 @@ void cgi(const char *cgicmd); void display_file(const char *); void status(const int, const char *); void status_redirect(const int, const char *); +void status_error(const int, const char*); void drop_privileges(const char *, const char *); void @@ -121,6 +122,13 @@ status_redirect(const int code, const char *url) code, url); } +void +status_error(const int code, const char *reason) +{ + printf("%i %s\r\n", + code, reason); +} + void display_file(const char *uri) { @@ -191,7 +199,7 @@ display_file(const char *uri) err: /* return an error code and no content */ - status(51, "text/gemini"); + status_error(51, "file not found"); syslog(LOG_DAEMON, "path invalid %s", fp); goto closefd; @@ -217,11 +225,8 @@ autoindex(const char *path) char *pos = NULL; struct dirent **namelist; /* this must be freed at last */ - syslog(LOG_DAEMON, "autoindex: %s", path); - status(20, "text/gemini"); - /* display link to parent */ char parent[PATH_MAX] = {'\0'}; /* parent is "path" without chroot_dir */ @@ -235,13 +240,14 @@ autoindex(const char *path) if (pos != NULL) { pos[1] = '\0'; /* at worse, parent is now "/" */ } - printf("=> %s ../\n", parent); /* use alphasort to always have the same order on every system */ if ((n = scandir(path, &namelist, NULL, alphasort)) < 0) { - status(51, "text/gemini"); + status_error(50, "Internal server error"); errlog("Can't scan %s", path); } else { + status(20, "text/gemini"); + printf("=> %s ../\n", parent); for(int j = 0; j < n; j++) { /* skip self and parent */ if ((strcmp(namelist[j]->d_name, ".") == 0) || From cbcf4ec9b60ca8d7a684d3a4b4c1ec6b11d500de Mon Sep 17 00:00:00 2001 From: Omar Polo Date: Sat, 6 Mar 2021 20:31:39 +0000 Subject: [PATCH 2/5] fix redirect when vhost support is enabled --- main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 351f7ad..08661a9 100644 --- a/main.c +++ b/main.c @@ -26,6 +26,7 @@ */ #define GEMINI_REQUEST_MAX 1025 +int virtualhost; void autoindex(const char *); void cgi(const char *cgicmd); @@ -160,7 +161,9 @@ display_file(const char *uri) if (S_ISDIR(sb.st_mode) != 0) { if (fp[strlen(fp) -1 ] != '/') { /* no ending "/", redirect to "path/" */ - estrlcpy(tmp, uri, sizeof(tmp)); + if (virtualhost) + estrlcat(tmp, "gemini://", sizeof(tmp)); + estrlcat(tmp, uri, sizeof(tmp)); estrlcat(tmp, "/", sizeof(tmp)); status_redirect(31, tmp); return; @@ -331,7 +334,6 @@ main(int argc, char **argv) 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; From 8454548b512769d69695703b1836d1ec16d17ee6 Mon Sep 17 00:00:00 2001 From: Omar Polo Date: Sat, 6 Mar 2021 20:36:06 +0000 Subject: [PATCH 3/5] add test for redirect with trailing slash with vhosts on --- tests/test.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test.sh b/tests/test.sh index bd50983..6ffa703 100644 --- a/tests/test.sh +++ b/tests/test.sh @@ -31,6 +31,10 @@ if ! [ $OUT = "fcc5a293f316e01f7b3103f97eca26b1" ] ; then echo "error" ; exit 1 OUT=$(printf "gemini://host.name/subdir\r\n" | ../vger -d var/gemini/ | tee /dev/stderr | MD5) if ! [ $OUT = "84e5e7bb3eee0dfcc8db14865dc83e77" ] ; then echo "error" ; exit 1 ; fi +# redirect to uri with trailing / if directory and vhost enabled +OUT=$(printf "gemini://perso.pw/cgi-bin\r\n" | ../vger -vd var/gemini | tee /dev/stderr | MD5) +if ! [ $OUT = "c782da4173898f57033a0804b8e96fc3" ] ; then echo "error" ; exit 1 ; fi + # file from local directory with lang=fr and markdown MIME type OUT=$(printf "gemini://perso.pw/file.md\r\n" | ../vger -d var/gemini/ -l fr | tee /dev/stderr | MD5) if ! [ $OUT = "e663f17730d5ddc24010c14a238e1e78" ] ; then echo "error" ; exit 1 ; fi From 16a5ed7b30d1a0d92e9655b95ecda30237d26b50 Mon Sep 17 00:00:00 2001 From: Omar Polo Date: Sat, 6 Mar 2021 20:38:54 +0000 Subject: [PATCH 4/5] drop unnecessary unveil(NULL, NULL) the next line is a call to pledge, that alone is will block further calls to unveil(2) since ``unveil'' isn't in the set of pledges. --- main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/main.c b/main.c index 08661a9..4e3a147 100644 --- a/main.c +++ b/main.c @@ -93,8 +93,6 @@ drop_privileges(const char *user, const char *path) eunveil(cgifullpath, "rx"); } - /* forbid more unveil */ - eunveil(NULL, NULL); /* * prevent system calls other parsing queryfor fread file and From ee8569c6e692a56f96cd6717453270ce2a28fa39 Mon Sep 17 00:00:00 2001 From: Omar Polo Date: Sat, 6 Mar 2021 20:46:47 +0000 Subject: [PATCH 5/5] simplify cgi function Don't fork+execlp the script. There's no need to do so since on exec the new process will inherit our file descriptor table (and hence our stdout), so copying from its stdout to ours is just a waste of time. This allows to drop the ``proc'' pledge(2) promise and to (slightly) improve performance. --- main.c | 61 ++++++--------------------------------------------- tests/test.sh | 2 +- 2 files changed, 8 insertions(+), 55 deletions(-) diff --git a/main.c b/main.c index 4e3a147..1f038bb 100644 --- a/main.c +++ b/main.c @@ -99,8 +99,8 @@ drop_privileges(const char *user, const char *path) * write to stdio */ if (strlen(cgibin) > 0) { - /* cgi need execlp() (exec) and fork() (proc) */ - epledge("stdio rpath exec proc", NULL); + /* cgi need execlp() (exec) */ + epledge("stdio rpath exec", NULL); } else { epledge("stdio rpath", NULL); } @@ -270,58 +270,11 @@ autoindex(const char *path) void cgi(const char *cgicmd) { - - int pipedes[2] = {0}; - pid_t pid; - - /* get a pipe to get stdout */ - if (pipe(pipedes) != 0) { - status(42, "text/gemini"); - err(1, "pipe failed"); - } - - pid = fork(); - - if (pid < 0) { - close(pipedes[0]); - close(pipedes[1]); - status(42, "text/gemini"); - err(1, "fork failed"); - } - - if (pid > 0) { /* parent */ - char buf[3]; - size_t nread = 0; - FILE *output = NULL; - - close(pipedes[1]); /* make sure entry is closed so fread() gets EOF */ - - /* use fread/fwrite because are buffered */ - output = fdopen(pipedes[0], "r"); - if (output == NULL) { - status(42, "text/gemini"); - err(1, "fdopen failed"); - } - - /* read pipe output */ - while ((nread = fread(buf, 1, sizeof(buf), output)) != 0) { - fwrite(buf, 1, nread, stdout); - } - close(pipedes[0]); - fclose(output); - - wait(NULL); /* wait for child to terminate */ - - exit(0); - - } else if (pid == 0) { /* child */ - dup2(pipedes[1], STDOUT_FILENO); /* set pipe output equal to stdout */ - close(pipedes[1]); /* no need this file descriptor : it is now stdout */ - execlp(cgicmd, cgicmd, NULL); - /* if execlp is ok, this will never be reached */ - status(42, "text/gemini"); - errlog("error when trying to execlp %s", cgicmd); - } + execlp(cgicmd, cgicmd, NULL); + /* if execlp is ok, this will never be reached */ + status(42, "Couldn't execute CGI script"); + errlog("error when trying to execlp %s", cgicmd); + exit(1); } int diff --git a/tests/test.sh b/tests/test.sh index 6ffa703..011cf71 100644 --- a/tests/test.sh +++ b/tests/test.sh @@ -89,7 +89,7 @@ if ! [ $OUT = "fa065a67d1f7c973501d4a9e3ca2ea57" ] ; then echo "error" ; exit 1 # cgi with error 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 +if ! [ $OUT = "4156170c2aa8a6a8a0892ff5a61bf5f5" ] ; 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)