commit 2fafa2d23e5607def335902b7a9d10a9de5247a9 from: Omar Polo date: Mon Feb 01 11:11:43 2021 UTC bring the CGI implementation in par with GLV-1.12556 commit - e17642a7bb0f182c3c6a26c27681d49ca9dce8dc commit + 2fafa2d23e5607def335902b7a9d10a9de5247a9 blob - 04caedc4759aa3f09ad0ce28a1054fd9e460004e blob + 2e8e76539818c835a64fe785bb7ff189514df722 --- ex.c +++ ex.c @@ -18,7 +18,10 @@ #include #include +#include +#include #include +#include #include #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 #include #include +#include #include #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; }