commit - e17642a7bb0f182c3c6a26c27681d49ca9dce8dc
commit + 2fafa2d23e5607def335902b7a9d10a9de5247a9
blob - 04caedc4759aa3f09ad0ce28a1054fd9e460004e
blob + 2e8e76539818c835a64fe785bb7ff189514df722
--- ex.c
+++ ex.c
#include <errno.h>
#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
#include <signal.h>
+#include <stdarg.h>
#include <string.h>
#include "gmid.h"
}
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;
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 */
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);
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;
}
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)
|| !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
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*);
/* 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);
/* 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**);
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
}
*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
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
+#include <limits.h>
#include <string.h>
#include "gmid.h"
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;
}
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");
* 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 */
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;
}
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];
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)
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;
}