Merge branch 'master' of tildegit.org:solene/vger

This commit is contained in:
prx 2021-03-09 20:37:46 +01:00
commit de52acecfc
2 changed files with 28 additions and 65 deletions

87
main.c
View file

@ -27,12 +27,14 @@
*/
#define GEMINI_REQUEST_MAX 1025
int virtualhost;
void autoindex(const char *);
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 *);
int uridecode(char *);
@ -129,16 +131,14 @@ 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
* 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);
}
@ -159,6 +159,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)
{
@ -190,7 +197,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;
@ -229,7 +238,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;
@ -255,11 +264,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 */
@ -273,13 +279,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) ||
@ -301,58 +308,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
@ -363,7 +323,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;

View file

@ -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
@ -85,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)