Blame


1 7edc455a 2021-01-15 op /*
2 7edc455a 2021-01-15 op * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
3 7edc455a 2021-01-15 op *
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.
7 7edc455a 2021-01-15 op *
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.
15 7edc455a 2021-01-15 op */
16 7edc455a 2021-01-15 op
17 7edc455a 2021-01-15 op #include <netdb.h>
18 7edc455a 2021-01-15 op
19 7edc455a 2021-01-15 op #include <errno.h>
20 7edc455a 2021-01-15 op #include <string.h>
21 7edc455a 2021-01-15 op
22 7edc455a 2021-01-15 op #include "gmid.h"
23 7edc455a 2021-01-15 op
24 7edc455a 2021-01-15 op static inline void
25 7edc455a 2021-01-15 op safe_setenv(const char *name, const char *val)
26 7edc455a 2021-01-15 op {
27 7edc455a 2021-01-15 op if (val == NULL)
28 7edc455a 2021-01-15 op val = "";
29 7edc455a 2021-01-15 op setenv(name, val, 1);
30 7edc455a 2021-01-15 op }
31 7edc455a 2021-01-15 op
32 7edc455a 2021-01-15 op /*
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.
38 7edc455a 2021-01-15 op */
39 7edc455a 2021-01-15 op int
40 7edc455a 2021-01-15 op check_for_cgi(char *path, char *query, struct pollfd *fds, struct client *c)
41 7edc455a 2021-01-15 op {
42 7edc455a 2021-01-15 op char *end;
43 7edc455a 2021-01-15 op end = strchr(path, '\0');
44 7edc455a 2021-01-15 op
45 7edc455a 2021-01-15 op /* NB: assume CGI is enabled and path matches cgi */
46 7edc455a 2021-01-15 op
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 != '/')
52 7edc455a 2021-01-15 op end--;
53 7edc455a 2021-01-15 op *end = '\0';
54 7edc455a 2021-01-15 op
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:
59 7edc455a 2021-01-15 op break;
60 7edc455a 2021-01-15 op default:
61 7edc455a 2021-01-15 op goto err;
62 7edc455a 2021-01-15 op }
63 7edc455a 2021-01-15 op
64 7edc455a 2021-01-15 op *end = '/';
65 7edc455a 2021-01-15 op end--;
66 7edc455a 2021-01-15 op }
67 7edc455a 2021-01-15 op
68 7edc455a 2021-01-15 op err:
69 7edc455a 2021-01-15 op if (!start_reply(fds, c, NOT_FOUND, "not found"))
70 7edc455a 2021-01-15 op return 0;
71 7edc455a 2021-01-15 op goodbye(fds, c);
72 7edc455a 2021-01-15 op return 0;
73 7edc455a 2021-01-15 op }
74 7edc455a 2021-01-15 op
75 7edc455a 2021-01-15 op int
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)
78 7edc455a 2021-01-15 op {
79 7edc455a 2021-01-15 op pid_t pid;
80 7edc455a 2021-01-15 op int p[2]; /* read end, write end */
81 7edc455a 2021-01-15 op
82 7edc455a 2021-01-15 op if (pipe(p) == -1)
83 7edc455a 2021-01-15 op goto err;
84 7edc455a 2021-01-15 op
85 7edc455a 2021-01-15 op switch (pid = fork()) {
86 7edc455a 2021-01-15 op case -1:
87 7edc455a 2021-01-15 op goto err;
88 7edc455a 2021-01-15 op
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 };
93 7edc455a 2021-01-15 op int ec;
94 7edc455a 2021-01-15 op
95 7edc455a 2021-01-15 op close(p[0]);
96 7edc455a 2021-01-15 op if (dup2(p[1], 1) == -1)
97 7edc455a 2021-01-15 op goto childerr;
98 7edc455a 2021-01-15 op
99 7edc455a 2021-01-15 op ec = getnameinfo((struct sockaddr*)&c->addr, sizeof(c->addr),
100 7edc455a 2021-01-15 op addr, sizeof(addr),
101 7edc455a 2021-01-15 op NULL, 0,
102 7edc455a 2021-01-15 op NI_NUMERICHOST | NI_NUMERICSERV);
103 7edc455a 2021-01-15 op if (ec != 0)
104 7edc455a 2021-01-15 op goto childerr;
105 7edc455a 2021-01-15 op
106 7edc455a 2021-01-15 op if (asprintf(&portno, "%d", conf.port) == -1)
107 7edc455a 2021-01-15 op goto childerr;
108 7edc455a 2021-01-15 op
109 7edc455a 2021-01-15 op if (asprintf(&ex, "%s/%s", c->host->dir, spath) == -1)
110 7edc455a 2021-01-15 op goto childerr;
111 7edc455a 2021-01-15 op
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;
115 7edc455a 2021-01-15 op
116 7edc455a 2021-01-15 op argv[0] = argv[1] = ex;
117 7edc455a 2021-01-15 op
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);
122 bd726b55 2021-01-15 op
123 bd726b55 2021-01-15 op if (!strcmp(c->host->domain, "*"))
124 bd726b55 2021-01-15 op safe_setenv("SERVER_NAME", c->host->domain)
125 bd726b55 2021-01-15 op
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);
134 7edc455a 2021-01-15 op
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));
140 7edc455a 2021-01-15 op }
141 7edc455a 2021-01-15 op
142 7edc455a 2021-01-15 op execvp(ex, argv);
143 7edc455a 2021-01-15 op goto childerr;
144 7edc455a 2021-01-15 op }
145 7edc455a 2021-01-15 op
146 7edc455a 2021-01-15 op default: /* parent */
147 7edc455a 2021-01-15 op close(p[1]);
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);
154 7edc455a 2021-01-15 op return 0;
155 7edc455a 2021-01-15 op }
156 7edc455a 2021-01-15 op
157 7edc455a 2021-01-15 op err:
158 7edc455a 2021-01-15 op if (!start_reply(fds, c, TEMP_FAILURE, "internal server error"))
159 7edc455a 2021-01-15 op return 0;
160 7edc455a 2021-01-15 op goodbye(fds, c);
161 7edc455a 2021-01-15 op return 0;
162 7edc455a 2021-01-15 op
163 7edc455a 2021-01-15 op childerr:
164 7edc455a 2021-01-15 op dprintf(p[1], "%d internal server error\r\n", TEMP_FAILURE);
165 7edc455a 2021-01-15 op close(p[1]);
166 7edc455a 2021-01-15 op _exit(1);
167 7edc455a 2021-01-15 op }
168 7edc455a 2021-01-15 op
169 7edc455a 2021-01-15 op void
170 7edc455a 2021-01-15 op cgi_poll_on_child(struct pollfd *fds, struct client *c)
171 7edc455a 2021-01-15 op {
172 7edc455a 2021-01-15 op int fd;
173 7edc455a 2021-01-15 op
174 7edc455a 2021-01-15 op if (c->waiting_on_child)
175 7edc455a 2021-01-15 op return;
176 7edc455a 2021-01-15 op c->waiting_on_child = 1;
177 7edc455a 2021-01-15 op
178 7edc455a 2021-01-15 op fds->events = POLLIN;
179 7edc455a 2021-01-15 op
180 7edc455a 2021-01-15 op fd = fds->fd;
181 7edc455a 2021-01-15 op fds->fd = c->fd;
182 7edc455a 2021-01-15 op c->fd = fd;
183 7edc455a 2021-01-15 op }
184 7edc455a 2021-01-15 op
185 7edc455a 2021-01-15 op void
186 7edc455a 2021-01-15 op cgi_poll_on_client(struct pollfd *fds, struct client *c)
187 7edc455a 2021-01-15 op {
188 7edc455a 2021-01-15 op int fd;
189 7edc455a 2021-01-15 op
190 7edc455a 2021-01-15 op if (!c->waiting_on_child)
191 7edc455a 2021-01-15 op return;
192 7edc455a 2021-01-15 op c->waiting_on_child = 0;
193 7edc455a 2021-01-15 op
194 7edc455a 2021-01-15 op fd = fds->fd;
195 7edc455a 2021-01-15 op fds->fd = c->fd;
196 7edc455a 2021-01-15 op c->fd = fd;
197 7edc455a 2021-01-15 op }
198 7edc455a 2021-01-15 op
199 7edc455a 2021-01-15 op void
200 7edc455a 2021-01-15 op handle_cgi(struct pollfd *fds, struct client *c)
201 7edc455a 2021-01-15 op {
202 7edc455a 2021-01-15 op ssize_t r;
203 7edc455a 2021-01-15 op
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);
206 7edc455a 2021-01-15 op
207 7edc455a 2021-01-15 op while (1) {
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)
210 7edc455a 2021-01-15 op goto end;
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);
214 7edc455a 2021-01-15 op return;
215 7edc455a 2021-01-15 op }
216 7edc455a 2021-01-15 op goto end;
217 7edc455a 2021-01-15 op }
218 7edc455a 2021-01-15 op c->len = r;
219 7edc455a 2021-01-15 op c->off = 0;
220 7edc455a 2021-01-15 op }
221 7edc455a 2021-01-15 op
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)) {
224 7edc455a 2021-01-15 op case -1:
225 7edc455a 2021-01-15 op goto end;
226 7edc455a 2021-01-15 op
227 7edc455a 2021-01-15 op case TLS_WANT_POLLOUT:
228 7edc455a 2021-01-15 op fds->events = POLLOUT;
229 7edc455a 2021-01-15 op return;
230 7edc455a 2021-01-15 op
231 7edc455a 2021-01-15 op case TLS_WANT_POLLIN:
232 7edc455a 2021-01-15 op fds->events = POLLIN;
233 7edc455a 2021-01-15 op return;
234 7edc455a 2021-01-15 op
235 7edc455a 2021-01-15 op default:
236 7edc455a 2021-01-15 op c->off += r;
237 7edc455a 2021-01-15 op c->len -= r;
238 7edc455a 2021-01-15 op break;
239 7edc455a 2021-01-15 op }
240 7edc455a 2021-01-15 op }
241 7edc455a 2021-01-15 op }
242 7edc455a 2021-01-15 op
243 7edc455a 2021-01-15 op end:
244 7edc455a 2021-01-15 op goodbye(fds, c);
245 7edc455a 2021-01-15 op }