ignore after ? and make cgi+virtualhost work (sort of)

This commit is contained in:
prx 2021-01-31 21:21:15 +01:00
parent 3510035711
commit de7cd12f9f
4 changed files with 39 additions and 17 deletions

29
main.c
View File

@ -82,6 +82,9 @@ drop_privileges(const char *user, const char *path)
estrlcat(cgifullpath, cgibin, sizeof(cgifullpath)); estrlcat(cgifullpath, cgibin, sizeof(cgifullpath));
eunveil(cgifullpath, "rx"); eunveil(cgifullpath, "rx");
} }
/* no more unveil later */
eunveil(NULL, NULL);
/* /*
* prevent system calls other parsing queryfor fread file and * prevent system calls other parsing queryfor fread file and
* write to stdio * write to stdio
@ -292,6 +295,7 @@ main(int argc, char **argv)
char hostname [GEMINI_REQUEST_MAX] = {'\0'}; char hostname [GEMINI_REQUEST_MAX] = {'\0'};
char uri [PATH_MAX] = {'\0'}; char uri [PATH_MAX] = {'\0'};
char user [_SC_LOGIN_NAME_MAX] = ""; char user [_SC_LOGIN_NAME_MAX] = "";
char query[PATH_MAX] = {'\0'};
int virtualhost = 0; int virtualhost = 0;
int option = 0; int option = 0;
char *pos = NULL; char *pos = NULL;
@ -383,6 +387,14 @@ main(int argc, char **argv)
/* copy hostname from request */ /* copy hostname from request */
estrlcpy(hostname, request, sizeof(hostname)); 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 + * if virtualhost feature is actived looking under the chroot_path +
* hostname directory gemini://foobar/hello will look for * hostname directory gemini://foobar/hello will look for
@ -392,15 +404,16 @@ main(int argc, char **argv)
if (strlen(uri) == 0) { if (strlen(uri) == 0) {
estrlcpy(uri, "/index.gmi", sizeof(uri)); estrlcpy(uri, "/index.gmi", sizeof(uri));
} }
char new_uri[PATH_MAX] = {'\0'}; char tmp[PATH_MAX] = {'\0'};
estrlcpy(new_uri, hostname, sizeof(new_uri)); estrlcpy(tmp, hostname, sizeof(tmp));
estrlcat(new_uri, uri, sizeof(new_uri)); estrlcat(tmp, uri, sizeof(tmp));
estrlcpy(uri, new_uri, sizeof(uri)); estrlcpy(uri, tmp, sizeof(uri));
} }
/* check if uri is cgibin */ /* check if uri is cgibin */
if ((strlen(cgibin) > 0) && if ((strlen(cgibin) > 0) &&
(strncmp(uri, cgibin, strlen(cgibin)) == 0)) { (strncmp(uri, cgibin, strlen(cgibin)) == 0)) {
char cgipath[PATH_MAX] = {'\0'}; char cgipath[PATH_MAX] = {'\0'};
estrlcpy(cgipath, chroot_dir, sizeof(cgipath)); estrlcpy(cgipath, chroot_dir, sizeof(cgipath));
estrlcat(cgipath, uri, sizeof(cgipath)); estrlcat(cgipath, uri, sizeof(cgipath));
@ -410,14 +423,6 @@ main(int argc, char **argv)
esetenv("SERVER_PROTOCOL", "GEMINI", 1); esetenv("SERVER_PROTOCOL", "GEMINI", 1);
esetenv("SERVER_SOFTWARE", "vger/1", 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 */ /* look for an extension to find PATH_INFO */
pos = strrchr(cgipath, '.'); pos = strrchr(cgipath, '.');
if (pos != NULL) { if (pos != NULL) {

View File

@ -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) 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 = "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 ! # must fail only on OpenBSD !
# try to escape from unveil # try to escape from unveil
if [ -f /bsd ] if [ -f /bsd ]

View File

@ -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

10
vger.8
View File

@ -44,7 +44,10 @@ will read the file /var/gemini/hostname.example/file.gmi
.It Op Fl c .It Op Fl c
Enable CGI support. Enable CGI support.
.Ar cgi_path .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 .Bd -literal -offset indent
vger -c /cgi-bin/hello.cgi vger -c /cgi-bin/hello.cgi
.Ed .Ed
@ -53,10 +56,7 @@ Note you can define a directory instead of a single file.
.Pp .Pp
In this case, In this case,
.Xr pledge 2 .Xr pledge 2
promises are set to "stdio proc exec" promises and unveil permission are set to enable cgi execution.
and an additional
.Xr unveil 2
permission on the cgi script is set to "rx".
.Pp .Pp
Be very careful on how you write your CGI, it can read outside the chroot. Be very careful on how you write your CGI, it can read outside the chroot.
.It Op Fl m Ar mimetype .It Op Fl m Ar mimetype