Commit Diff


commit - e17642a7bb0f182c3c6a26c27681d49ca9dce8dc
commit + 2fafa2d23e5607def335902b7a9d10a9de5247a9
blob - 04caedc4759aa3f09ad0ce28a1054fd9e460004e
blob + 2e8e76539818c835a64fe785bb7ff189514df722
--- ex.c
+++ ex.c
@@ -18,7 +18,10 @@
 #include <errno.h>
 
 #include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
 #include <signal.h>
+#include <stdarg.h>
 #include <string.h>
 
 #include "gmid.h"
@@ -65,6 +68,41 @@ recv_string(int fd, char **ret)
 }
 
 int
+send_iri(int fd, struct iri *i)
+{
+	return send_string(fd, i->schema)
+		&& send_string(fd, i->host)
+		&& send_string(fd, i->port)
+		&& send_string(fd, i->path)
+		&& send_string(fd, i->query);
+}
+
+int
+recv_iri(int fd, struct iri *i)
+{
+	memset(i, 0, sizeof(*i));
+
+	if (!recv_string(fd, &i->schema)
+	    || !recv_string(fd, &i->host)
+	    || !recv_string(fd, &i->port)
+	    || !recv_string(fd, &i->path)
+	    || !recv_string(fd, &i->query))
+		return 0;
+
+	return 1;
+}
+
+void
+free_recvd_iri(struct iri *i)
+{
+	free(i->schema);
+	free(i->host);
+	free(i->port);
+	free(i->path);
+	free(i->query);
+}
+
+int
 send_vhost(int fd, struct vhost *vhost)
 {
 	ssize_t n;
@@ -178,11 +216,25 @@ safe_setenv(const char *name, const char *val)
 	setenv(name, val, 1);
 }
 
+static char *
+xasprintf(const char *fmt, ...)
+{
+	va_list ap;
+	char *s;
+
+	va_start(ap, fmt);
+	if (vasprintf(&s, fmt, ap) == -1)
+		s = NULL;
+	va_end(ap);
+
+	return s;
+}
+
 /* fd or -1 on error */
 static int
-launch_cgi(const char *spath, const char *relpath, const char *query,
-    const char *addr, const char *ruser, const char *cissuer, const char *chash,
-    struct vhost *vhost)
+launch_cgi(struct iri *iri, const char *spath, char *relpath,
+    const char *addr, const char *ruser, const char *cissuer,
+    const char *chash, struct vhost *vhost)
 {
 	int p[2];		/* read end, write end */
 
@@ -194,43 +246,59 @@ launch_cgi(const char *spath, const char *relpath, con
 		return -1;
 
 	case 0: {		/* child */
-		char *portno, *ex, *requri;
-		char *argv[] = { NULL, NULL, NULL };
+		char *argv[] = {NULL, NULL, NULL};
+		char *ex, *pwd;
+		char iribuf[GEMINI_URL_LEN];
+		char path[PATH_MAX];
 
 		close(p[0]);
 		if (dup2(p[1], 1) == -1)
 			goto childerr;
 
-		if (asprintf(&portno, "%d", conf.port) == -1)
-			goto childerr;
+		ex = xasprintf("%s/%s", vhost->dir, spath);
+		argv[0] = ex;
+		argv[1] = iri->query;
 
-		if (asprintf(&ex, "%s/%s", vhost->dir, spath) == -1)
-			goto childerr;
+		serialize_iri(iri, iribuf, sizeof(iribuf));
 
-		if (asprintf(&requri, "%s%s%s", spath,
-		    (relpath != NULL && *relpath == '\0') ? "" : "/",
-		    (relpath != NULL ? relpath : "")) == -1)
-			goto childerr;
-
-		argv[0] = argv[1] = ex;
-
 		safe_setenv("GATEWAY_INTERFACE", "CGI/1.1");
-		safe_setenv("SERVER_PROTOCOL", "GEMINI");
-		safe_setenv("SERVER_SOFTWARE", "gmid");
-		safe_setenv("SERVER_PORT", portno);
+		safe_setenv("GEMINI_DOCUMENT_ROOT", vhost->dir);
+		safe_setenv("GEMINI_SCRIPT_FILENAME",
+		    xasprintf("%s/%s", vhost->dir, spath));
+		safe_setenv("GEMINI_URL", iribuf);
 
-		if (!strcmp(vhost->domain, "*"))
-			safe_setenv("SERVER_NAME", vhost->domain);
+		strlcpy(path, "/", sizeof(path));
+		strlcat(path, spath, sizeof(path));
+		safe_setenv("GEMINI_URL_PATH", path);
 
-		safe_setenv("SCRIPT_NAME", spath);
-		safe_setenv("SCRIPT_EXECUTABLE", ex);
-		safe_setenv("REQUEST_URI", requri);
-		safe_setenv("REQUEST_RELATIVE", relpath);
-		safe_setenv("QUERY_STRING", query);
-		safe_setenv("REMOTE_HOST", addr);
+		if (relpath != NULL) {
+			strlcpy(path, "/", sizeof(path));
+			strlcat(path, relpath, sizeof(path));
+			safe_setenv("PATH_INFO", path);
+
+			strlcpy(path, vhost->dir, sizeof(path));
+			strlcat(path, "/", sizeof(path));
+			strlcat(path, relpath, sizeof(path));
+			safe_setenv("PATH_TRANSLATED", path);
+		}
+
+		safe_setenv("QUERY_STRING", iri->query);
 		safe_setenv("REMOTE_ADDR", addr);
-		safe_setenv("DOCUMENT_ROOT", vhost->dir);
+		safe_setenv("REMOTE_HOST", addr);
+		safe_setenv("REQUEST_METHOD", "");
 
+		strlcpy(path, "/", sizeof(path));
+		strlcat(path, spath, sizeof(path));
+		safe_setenv("SCRIPT_NAME", path);
+
+		safe_setenv("SERVER_NAME", iri->host);
+
+		snprintf(path, sizeof(path), "%d", conf.port);
+		safe_setenv("SERVER_PORT", path);
+
+		safe_setenv("SERVER_PROTOCOL", "GEMINI");
+		safe_setenv("SERVER_SOFTWARE", "gmid/1.5");
+
 		if (ruser != NULL) {
 			safe_setenv("AUTH_TYPE", "Certificate");
 			safe_setenv("REMOTE_USER", ruser);
@@ -238,9 +306,15 @@ launch_cgi(const char *spath, const char *relpath, con
 			safe_setenv("TLS_CLIENT_HASH", chash);
 		}
 
-		fchdir(vhost->dirfd);
+		strlcpy(path, argv[0], sizeof(path));
+		pwd = dirname(path);
+		if (chdir(pwd)) {
+			warn("chdir");
+			goto childerr;
+		}
 
-		execvp(ex, argv);
+		execvp(argv[0], argv);
+		warn("execvp: %s", argv[0]);
 		goto childerr;
 	}
 
@@ -257,25 +331,28 @@ childerr:
 int
 executor_main(int fd)
 {
-	char *spath, *relpath, *query, *addr, *ruser, *cissuer, *chash;
+	char *spath, *relpath, *addr, *ruser, *cissuer, *chash;
         struct vhost *vhost;
+	struct iri iri;
 	int d;
 
 #ifdef __OpenBSD__
 	for (vhost = hosts; vhost->domain != NULL; ++vhost) {
-		if (unveil(vhost->dir, "x") == -1)
+		/* r so we can chdir into the correct directory */
+		if (unveil(vhost->dir, "rx") == -1)
 			err(1, "unveil %s for domain %s",
 			    vhost->dir, vhost->domain);
 	}
 
-	if (pledge("stdio sendfd proc exec", NULL))
+	/* rpath to chdir into the correct directory */
+	if (pledge("stdio rpath sendfd proc exec", NULL))
 		err(1, "pledge");
 #endif
 
 	for (;;) {
-		if (!recv_string(fd, &spath)
+		if (!recv_iri(fd, &iri)
+		    || !recv_string(fd, &spath)
 		    || !recv_string(fd, &relpath)
-		    || !recv_string(fd, &query)
 		    || !recv_string(fd, &addr)
 		    || !recv_string(fd, &ruser)
 		    || !recv_string(fd, &cissuer)
@@ -283,15 +360,15 @@ executor_main(int fd)
 		    || !recv_vhost(fd, &vhost))
 			break;
 
-		d = launch_cgi(spath, relpath, query,
-		    addr, ruser, cissuer, chash, vhost);
+		d = launch_cgi(&iri, spath, relpath, addr, ruser, cissuer, chash,
+		    vhost);
 		if (!send_fd(fd, d))
 			break;
 		close(d);
 
+		free_recvd_iri(&iri);
 		free(spath);
 		free(relpath);
-		free(query);
 		free(addr);
 		free(ruser);
 		free(cissuer);
blob - fc9ec53396cd01bcffd98b0364cc20e7e526f28c
blob + 5d4becfadf20bfc62c907d4ff56193abad4314ec
--- gmid.h
+++ gmid.h
@@ -204,12 +204,12 @@ int		 vhost_auto_index(struct vhost*, const char*);
 int		 check_path(struct client*, const char*, int*);
 void		 open_file(struct pollfd*, struct client*);
 void		 load_file(struct pollfd*, struct client*);
-void		 check_for_cgi(char *, char*, struct pollfd*, struct client*);
+void		 check_for_cgi(struct pollfd*, struct client*);
 void		 mark_nonblock(int);
 void		 handle_handshake(struct pollfd*, struct client*);
 void		 handle_open_conn(struct pollfd*, struct client*);
 void		 start_reply(struct pollfd*, struct client*, int, const char*);
-void		 start_cgi(const char*, const char*, const char*, struct pollfd*, struct client*);
+void		 start_cgi(const char*, const char*, struct pollfd*, struct client*);
 void		 send_file(struct pollfd*, struct client*);
 void		 open_dir(struct pollfd*, struct client*);
 void		 redirect_canonical_dir(struct pollfd*, struct client*);
@@ -226,6 +226,9 @@ void		 loop(struct tls*, int, int);
 /* ex.c */
 int		 send_string(int, const char*);
 int		 recv_string(int, char**);
+int		 send_iri(int, struct iri*);
+int		 recv_iri(int, struct iri*);
+void		 free_recvd_iri(struct iri*);
 int		 send_vhost(int, struct vhost*);
 int		 recv_vhost(int, struct vhost**);
 int		 send_fd(int, int);
@@ -242,6 +245,7 @@ char		*utf8_nth(char*, size_t);
 /* iri.c */
 int		 parse_iri(char*, struct iri*, const char**);
 int		 trim_req_iri(char*, const char **);
+int		 serialize_iri(struct iri*, char*, size_t);
 
 /* puny.c */
 int		 puny_decode(const char*, char*, size_t, const char**);
@@ -250,5 +254,6 @@ int		 puny_decode(const char*, char*, size_t, const ch
 int		 starts_with(const char*, const char*);
 int		 ends_with(const char*, const char*);
 ssize_t		 filesize(int);
+char		*absolutify_path(const char*);
 
 #endif
blob - 3336b6e8e834821ad906148c6e13914ac71da958
blob + efdeb11b936ab9afd973768afc980c2885d14288
--- iri.c
+++ iri.c
@@ -376,4 +376,32 @@ trim_req_iri(char *iri, const char **err)
 	}
 	*i = '\0';
 	return 1;
+}
+
+
+int
+serialize_iri(struct iri *i, char *buf, size_t len)
+{
+	size_t l;
+
+	/* in ex.c we receive empty "" strings as NULL */
+	if (i->schema == NULL || i->host == NULL) {
+		memset(buf, 0, len);
+		return 0;
+	}
+
+	strlcpy(buf, i->schema, len);
+	strlcat(buf, "://", len);
+        strlcat(buf, i->host, len);
+	strlcat(buf, "/", len);
+
+	if (i->path != NULL)
+		l = strlcat(buf, i->path, len);
+
+	if (i->query != NULL && *i->query != '\0') {
+		strlcat(buf, "?", len);
+		l = strlcat(buf, i->query, len);
+	}
+
+	return l < len;
 }
blob - 0df7e6d9cea0654f45129eeaa0b53c00b790c401
blob + 30f413c685dc2e63601f4fc5428bdad8875bec86
--- server.c
+++ server.c
@@ -23,6 +23,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <fnmatch.h>
+#include <limits.h>
 #include <string.h>
 
 #include "gmid.h"
@@ -150,7 +151,7 @@ open_file(struct pollfd *fds, struct client *c)
 	switch (check_path(c, c->iri.path, &c->fd)) {
 	case FILE_EXECUTABLE:
 		if (starts_with(c->iri.path, c->host->cgi)) {
-			start_cgi(c->iri.path, "", c->iri.query, fds, c);
+			start_cgi(c->iri.path, "", fds, c);
 			return;
 		}
 
@@ -166,7 +167,7 @@ open_file(struct pollfd *fds, struct client *c)
 
 	case FILE_MISSING:
 		if (c->host->cgi != NULL && starts_with(c->iri.path, c->host->cgi)) {
-			check_for_cgi(c->iri.path, c->iri.query, fds, c);
+			check_for_cgi(fds, c);
 			return;
 		}
 		start_reply(fds, c, NOT_FOUND, "not found");
@@ -206,9 +207,12 @@ load_file(struct pollfd *fds, struct client *c)
  * executable is found or we emptied the path.
  */
 void
-check_for_cgi(char *path, char *query, struct pollfd *fds, struct client *c)
+check_for_cgi(struct pollfd *fds, struct client *c)
 {
+	char path[PATH_MAX];
 	char *end;
+
+	strlcpy(path, c->iri.path, sizeof(path));
 	end = strchr(path, '\0');
 
 	/* NB: assume CGI is enabled and path matches cgi */
@@ -223,7 +227,7 @@ check_for_cgi(char *path, char *query, struct pollfd *
 
 		switch (check_path(c, path, &c->fd)) {
 		case FILE_EXECUTABLE:
-			start_cgi(path, end+1, query, fds,c);
+			start_cgi(path, end+1, fds, c);
 			return;
 		case FILE_MISSING:
 			break;
@@ -396,7 +400,7 @@ start_reply(struct pollfd *pfd, struct client *c, int 
 }
 
 void
-start_cgi(const char *spath, const char *relpath, const char *query,
+start_cgi(const char *spath, const char *relpath,
     struct pollfd *fds, struct client *c)
 {
 	char addr[NI_MAXHOST];
@@ -420,9 +424,9 @@ start_cgi(const char *spath, const char *relpath, cons
 		chash = NULL;
 	}
 
-	if (!send_string(exfd, spath)
+	if (!send_iri(exfd, &c->iri)
+	    || !send_string(exfd, spath)
 	    || !send_string(exfd, relpath)
-	    || !send_string(exfd, query)
 	    || !send_string(exfd, addr)
 	    || !send_string(exfd, ruser)
 	    || !send_string(exfd, cissuer)
@@ -515,7 +519,7 @@ open_dir(struct pollfd *fds, struct client *c)
 	switch (check_path(c, c->iri.path, &c->fd)) {
 	case FILE_EXECUTABLE:
 		if (starts_with(c->iri.path, c->host->cgi)) {
-			start_cgi(c->iri.path, "", c->iri.query, fds, c);
+			start_cgi(c->iri.path, "", fds, c);
 			break;
 		}