2 7edc455a 2021-01-15 op * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
4 7edc455a 2021-01-15 op * Permission to use, copy, modify, and distribute this software for any
5 7edc455a 2021-01-15 op * purpose with or without fee is hereby granted, provided that the above
6 7edc455a 2021-01-15 op * copyright notice and this permission notice appear in all copies.
8 7edc455a 2021-01-15 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 7edc455a 2021-01-15 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 7edc455a 2021-01-15 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 7edc455a 2021-01-15 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 7edc455a 2021-01-15 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 7edc455a 2021-01-15 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 7edc455a 2021-01-15 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 7edc455a 2021-01-15 op #include <netdb.h>
19 7edc455a 2021-01-15 op #include <errno.h>
20 7edc455a 2021-01-15 op #include <string.h>
22 7edc455a 2021-01-15 op #include "gmid.h"
24 7edc455a 2021-01-15 op static inline void
25 7edc455a 2021-01-15 op safe_setenv(const char *name, const char *val)
27 7edc455a 2021-01-15 op if (val == NULL)
29 7edc455a 2021-01-15 op setenv(name, val, 1);
33 7edc455a 2021-01-15 op * the inverse of this algorithm, i.e. starting from the start of the
34 7edc455a 2021-01-15 op * path + strlen(cgi), and checking if each component, should be
35 7edc455a 2021-01-15 op * faster. But it's tedious to write. This does the opposite: starts
36 7edc455a 2021-01-15 op * from the end and strip one component at a time, until either an
37 7edc455a 2021-01-15 op * executable is found or we emptied the path.
40 7edc455a 2021-01-15 op check_for_cgi(char *path, char *query, struct pollfd *fds, struct client *c)
43 7edc455a 2021-01-15 op end = strchr(path, '\0');
45 7edc455a 2021-01-15 op /* NB: assume CGI is enabled and path matches cgi */
47 7edc455a 2021-01-15 op while (end > path) {
48 7edc455a 2021-01-15 op /* go up one level. UNIX paths are simple and POSIX
49 7edc455a 2021-01-15 op * dirname, with its ambiguities on if the given path
50 7edc455a 2021-01-15 op * is changed or not, gives me headaches. */
51 7edc455a 2021-01-15 op while (*end != '/')
55 7edc455a 2021-01-15 op switch (check_path(c, path, &c->fd)) {
56 7edc455a 2021-01-15 op case FILE_EXECUTABLE:
57 7edc455a 2021-01-15 op return start_cgi(path, end+1, query, fds,c);
58 7edc455a 2021-01-15 op case FILE_MISSING:
69 7edc455a 2021-01-15 op if (!start_reply(fds, c, NOT_FOUND, "not found"))
71 7edc455a 2021-01-15 op goodbye(fds, c);
76 7edc455a 2021-01-15 op start_cgi(const char *spath, const char *relpath, const char *query,
77 7edc455a 2021-01-15 op struct pollfd *fds, struct client *c)
80 7edc455a 2021-01-15 op int p[2]; /* read end, write end */
82 7edc455a 2021-01-15 op if (pipe(p) == -1)
85 7edc455a 2021-01-15 op switch (pid = fork()) {
89 7edc455a 2021-01-15 op case 0: { /* child */
90 7edc455a 2021-01-15 op char *ex, *requri, *portno;
91 7edc455a 2021-01-15 op char addr[NI_MAXHOST];
92 7edc455a 2021-01-15 op char *argv[] = { NULL, NULL, NULL };
96 7edc455a 2021-01-15 op if (dup2(p[1], 1) == -1)
97 7edc455a 2021-01-15 op goto childerr;
99 7edc455a 2021-01-15 op ec = getnameinfo((struct sockaddr*)&c->addr, sizeof(c->addr),
100 7edc455a 2021-01-15 op addr, sizeof(addr),
102 7edc455a 2021-01-15 op NI_NUMERICHOST | NI_NUMERICSERV);
104 7edc455a 2021-01-15 op goto childerr;
106 7edc455a 2021-01-15 op if (asprintf(&portno, "%d", conf.port) == -1)
107 7edc455a 2021-01-15 op goto childerr;
109 7edc455a 2021-01-15 op if (asprintf(&ex, "%s/%s", c->host->dir, spath) == -1)
110 7edc455a 2021-01-15 op goto childerr;
112 7edc455a 2021-01-15 op if (asprintf(&requri, "%s%s%s", spath,
113 7edc455a 2021-01-15 op *relpath == '\0' ? "" : "/", relpath) == -1)
114 7edc455a 2021-01-15 op goto childerr;
116 7edc455a 2021-01-15 op argv[0] = argv[1] = ex;
118 7edc455a 2021-01-15 op /* fix the env */
119 7edc455a 2021-01-15 op safe_setenv("GATEWAY_INTERFACE", "CGI/1.1");
120 7edc455a 2021-01-15 op safe_setenv("SERVER_SOFTWARE", "gmid");
121 7edc455a 2021-01-15 op safe_setenv("SERVER_PORT", portno);
123 bd726b55 2021-01-15 op if (!strcmp(c->host->domain, "*"))
124 bd726b55 2021-01-15 op safe_setenv("SERVER_NAME", c->host->domain)
126 7edc455a 2021-01-15 op safe_setenv("SCRIPT_NAME", spath);
127 7edc455a 2021-01-15 op safe_setenv("SCRIPT_EXECUTABLE", ex);
128 7edc455a 2021-01-15 op safe_setenv("REQUEST_URI", requri);
129 7edc455a 2021-01-15 op safe_setenv("REQUEST_RELATIVE", relpath);
130 7edc455a 2021-01-15 op safe_setenv("QUERY_STRING", query);
131 7edc455a 2021-01-15 op safe_setenv("REMOTE_HOST", addr);
132 7edc455a 2021-01-15 op safe_setenv("REMOTE_ADDR", addr);
133 7edc455a 2021-01-15 op safe_setenv("DOCUMENT_ROOT", c->host->dir);
135 7edc455a 2021-01-15 op if (tls_peer_cert_provided(c->ctx)) {
136 7edc455a 2021-01-15 op safe_setenv("AUTH_TYPE", "Certificate");
137 7edc455a 2021-01-15 op safe_setenv("REMOTE_USER", tls_peer_cert_subject(c->ctx));
138 7edc455a 2021-01-15 op safe_setenv("TLS_CLIENT_ISSUER", tls_peer_cert_issuer(c->ctx));
139 7edc455a 2021-01-15 op safe_setenv("TLS_CLIENT_HASH", tls_peer_cert_hash(c->ctx));
142 7edc455a 2021-01-15 op execvp(ex, argv);
143 7edc455a 2021-01-15 op goto childerr;
146 7edc455a 2021-01-15 op default: /* parent */
148 7edc455a 2021-01-15 op close(c->fd);
149 7edc455a 2021-01-15 op c->fd = p[0];
150 7edc455a 2021-01-15 op c->child = pid;
151 7edc455a 2021-01-15 op mark_nonblock(c->fd);
152 7edc455a 2021-01-15 op c->state = S_SENDING;
153 7edc455a 2021-01-15 op handle_cgi(fds, c);
158 7edc455a 2021-01-15 op if (!start_reply(fds, c, TEMP_FAILURE, "internal server error"))
160 7edc455a 2021-01-15 op goodbye(fds, c);
164 7edc455a 2021-01-15 op dprintf(p[1], "%d internal server error\r\n", TEMP_FAILURE);
170 7edc455a 2021-01-15 op cgi_poll_on_child(struct pollfd *fds, struct client *c)
174 7edc455a 2021-01-15 op if (c->waiting_on_child)
176 7edc455a 2021-01-15 op c->waiting_on_child = 1;
178 7edc455a 2021-01-15 op fds->events = POLLIN;
180 7edc455a 2021-01-15 op fd = fds->fd;
181 7edc455a 2021-01-15 op fds->fd = c->fd;
186 7edc455a 2021-01-15 op cgi_poll_on_client(struct pollfd *fds, struct client *c)
190 7edc455a 2021-01-15 op if (!c->waiting_on_child)
192 7edc455a 2021-01-15 op c->waiting_on_child = 0;
194 7edc455a 2021-01-15 op fd = fds->fd;
195 7edc455a 2021-01-15 op fds->fd = c->fd;
200 7edc455a 2021-01-15 op handle_cgi(struct pollfd *fds, struct client *c)
204 7edc455a 2021-01-15 op /* ensure c->fd is the child and fds->fd the client */
205 7edc455a 2021-01-15 op cgi_poll_on_client(fds, c);
208 7edc455a 2021-01-15 op if (c->len == 0) {
209 7edc455a 2021-01-15 op if ((r = read(c->fd, c->sbuf, sizeof(c->sbuf))) == 0)
211 7edc455a 2021-01-15 op if (r == -1) {
212 7edc455a 2021-01-15 op if (errno == EAGAIN || errno == EWOULDBLOCK) {
213 7edc455a 2021-01-15 op cgi_poll_on_child(fds, c);
222 7edc455a 2021-01-15 op while (c->len > 0) {
223 7edc455a 2021-01-15 op switch (r = tls_write(c->ctx, c->sbuf + c->off, c->len)) {
227 7edc455a 2021-01-15 op case TLS_WANT_POLLOUT:
228 7edc455a 2021-01-15 op fds->events = POLLOUT;
231 7edc455a 2021-01-15 op case TLS_WANT_POLLIN:
232 7edc455a 2021-01-15 op fds->events = POLLIN;
244 7edc455a 2021-01-15 op goodbye(fds, c);