mirror of https://github.com/omar-polo/gmid.git
bring the CGI implementation in par with GLV-1.12556
This commit is contained in:
parent
e17642a7bb
commit
2fafa2d23e
153
ex.c
153
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"
|
||||
|
@ -64,6 +67,41 @@ recv_string(int fd, char **ret)
|
|||
return 1;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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,42 +246,58 @@ launch_cgi(const char *spath, const char *relpath, const char *query,
|
|||
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;
|
||||
|
||||
if (asprintf(&requri, "%s%s%s", spath,
|
||||
(relpath != NULL && *relpath == '\0') ? "" : "/",
|
||||
(relpath != NULL ? relpath : "")) == -1)
|
||||
goto childerr;
|
||||
|
||||
argv[0] = argv[1] = ex;
|
||||
serialize_iri(iri, iribuf, sizeof(iribuf));
|
||||
|
||||
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");
|
||||
|
@ -238,9 +306,15 @@ launch_cgi(const char *spath, const char *relpath, const char *query,
|
|||
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);
|
||||
|
|
9
gmid.h
9
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 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
|
||||
|
|
28
iri.c
28
iri.c
|
@ -377,3 +377,31 @@ 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;
|
||||
}
|
||||
|
|
20
server.c
20
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 *fds, struct client *c)
|
|||
|
||||
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 code, const char *meta)
|
|||
}
|
||||
|
||||
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, const char *query,
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue