Blame


1 881a9dd9 2021-01-16 op /*
2 881a9dd9 2021-01-16 op * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
3 881a9dd9 2021-01-16 op *
4 881a9dd9 2021-01-16 op * Permission to use, copy, modify, and distribute this software for any
5 881a9dd9 2021-01-16 op * purpose with or without fee is hereby granted, provided that the above
6 881a9dd9 2021-01-16 op * copyright notice and this permission notice appear in all copies.
7 881a9dd9 2021-01-16 op *
8 881a9dd9 2021-01-16 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 881a9dd9 2021-01-16 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 881a9dd9 2021-01-16 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 881a9dd9 2021-01-16 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 881a9dd9 2021-01-16 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 881a9dd9 2021-01-16 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 881a9dd9 2021-01-16 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 881a9dd9 2021-01-16 op */
16 881a9dd9 2021-01-16 op
17 881a9dd9 2021-01-16 op #include <err.h>
18 881a9dd9 2021-01-16 op #include <errno.h>
19 881a9dd9 2021-01-16 op
20 881a9dd9 2021-01-16 op #include <fcntl.h>
21 881a9dd9 2021-01-16 op #include <signal.h>
22 881a9dd9 2021-01-16 op #include <string.h>
23 881a9dd9 2021-01-16 op
24 881a9dd9 2021-01-16 op #include "gmid.h"
25 881a9dd9 2021-01-16 op
26 881a9dd9 2021-01-16 op int
27 881a9dd9 2021-01-16 op send_string(int fd, const char *str)
28 881a9dd9 2021-01-16 op {
29 881a9dd9 2021-01-16 op ssize_t len;
30 881a9dd9 2021-01-16 op
31 881a9dd9 2021-01-16 op if (str == NULL)
32 881a9dd9 2021-01-16 op len = 0;
33 881a9dd9 2021-01-16 op else
34 881a9dd9 2021-01-16 op len = strlen(str);
35 881a9dd9 2021-01-16 op
36 881a9dd9 2021-01-16 op if (write(fd, &len, sizeof(len)) != sizeof(len))
37 881a9dd9 2021-01-16 op return 0;
38 881a9dd9 2021-01-16 op
39 881a9dd9 2021-01-16 op if (len != 0)
40 881a9dd9 2021-01-16 op if (write(fd, str, len) != len)
41 881a9dd9 2021-01-16 op return 0;
42 881a9dd9 2021-01-16 op
43 881a9dd9 2021-01-16 op return 1;
44 881a9dd9 2021-01-16 op }
45 881a9dd9 2021-01-16 op
46 881a9dd9 2021-01-16 op int
47 881a9dd9 2021-01-16 op recv_string(int fd, char **ret)
48 881a9dd9 2021-01-16 op {
49 881a9dd9 2021-01-16 op ssize_t len;
50 881a9dd9 2021-01-16 op
51 881a9dd9 2021-01-16 op if (read(fd, &len, sizeof(len)) != sizeof(len))
52 881a9dd9 2021-01-16 op return 0;
53 881a9dd9 2021-01-16 op
54 881a9dd9 2021-01-16 op if (len == 0) {
55 881a9dd9 2021-01-16 op *ret = NULL;
56 881a9dd9 2021-01-16 op return 1;
57 881a9dd9 2021-01-16 op }
58 881a9dd9 2021-01-16 op
59 881a9dd9 2021-01-16 op if ((*ret = calloc(1, len+1)) == NULL)
60 881a9dd9 2021-01-16 op return 0;
61 881a9dd9 2021-01-16 op
62 881a9dd9 2021-01-16 op if (read(fd, *ret, len) != len)
63 881a9dd9 2021-01-16 op return 0;
64 881a9dd9 2021-01-16 op return 1;
65 881a9dd9 2021-01-16 op }
66 881a9dd9 2021-01-16 op
67 881a9dd9 2021-01-16 op int
68 881a9dd9 2021-01-16 op send_vhost(int fd, struct vhost *vhost)
69 881a9dd9 2021-01-16 op {
70 881a9dd9 2021-01-16 op ssize_t n;
71 881a9dd9 2021-01-16 op
72 881a9dd9 2021-01-16 op if (vhost < hosts || vhost > hosts + HOSTSLEN)
73 881a9dd9 2021-01-16 op return 0;
74 881a9dd9 2021-01-16 op
75 881a9dd9 2021-01-16 op n = hosts - vhost;
76 881a9dd9 2021-01-16 op return write(fd, &n, sizeof(n)) == sizeof(n);
77 881a9dd9 2021-01-16 op }
78 881a9dd9 2021-01-16 op
79 881a9dd9 2021-01-16 op int
80 881a9dd9 2021-01-16 op recv_vhost(int fd, struct vhost **vhost)
81 881a9dd9 2021-01-16 op {
82 881a9dd9 2021-01-16 op ssize_t n;
83 881a9dd9 2021-01-16 op
84 881a9dd9 2021-01-16 op if (read(fd, &n, sizeof(n)) != sizeof(n))
85 881a9dd9 2021-01-16 op return 0;
86 881a9dd9 2021-01-16 op
87 881a9dd9 2021-01-16 op if (n < 0 || n > HOSTSLEN)
88 881a9dd9 2021-01-16 op return 0;
89 881a9dd9 2021-01-16 op
90 881a9dd9 2021-01-16 op *vhost = &hosts[n];
91 881a9dd9 2021-01-16 op if ((*vhost)->domain == NULL)
92 881a9dd9 2021-01-16 op return 0;
93 881a9dd9 2021-01-16 op return 1;
94 881a9dd9 2021-01-16 op }
95 881a9dd9 2021-01-16 op
96 881a9dd9 2021-01-16 op /* send d though fd. see /usr/src/usr.sbin/syslogd/privsep_fdpass.c
97 881a9dd9 2021-01-16 op * for an example */
98 881a9dd9 2021-01-16 op int
99 881a9dd9 2021-01-16 op send_fd(int fd, int d)
100 881a9dd9 2021-01-16 op {
101 881a9dd9 2021-01-16 op struct msghdr msg;
102 881a9dd9 2021-01-16 op union {
103 881a9dd9 2021-01-16 op struct cmsghdr hdr;
104 881a9dd9 2021-01-16 op unsigned char buf[CMSG_SPACE(sizeof(int))];
105 881a9dd9 2021-01-16 op } cmsgbuf;
106 881a9dd9 2021-01-16 op struct cmsghdr *cmsg;
107 881a9dd9 2021-01-16 op struct iovec vec;
108 881a9dd9 2021-01-16 op int result = 1;
109 881a9dd9 2021-01-16 op ssize_t n;
110 881a9dd9 2021-01-16 op
111 881a9dd9 2021-01-16 op memset(&msg, 0, sizeof(msg));
112 881a9dd9 2021-01-16 op
113 881a9dd9 2021-01-16 op if (d >= 0) {
114 881a9dd9 2021-01-16 op msg.msg_control = &cmsgbuf.buf;
115 881a9dd9 2021-01-16 op msg.msg_controllen = sizeof(cmsgbuf.buf);
116 881a9dd9 2021-01-16 op cmsg = CMSG_FIRSTHDR(&msg);
117 881a9dd9 2021-01-16 op cmsg->cmsg_len = CMSG_LEN(sizeof(int));
118 881a9dd9 2021-01-16 op cmsg->cmsg_level = SOL_SOCKET;
119 881a9dd9 2021-01-16 op cmsg->cmsg_type = SCM_RIGHTS;
120 881a9dd9 2021-01-16 op *(int*)CMSG_DATA(cmsg) = d;
121 881a9dd9 2021-01-16 op } else
122 881a9dd9 2021-01-16 op result = 0;
123 881a9dd9 2021-01-16 op
124 881a9dd9 2021-01-16 op vec.iov_base = &result;
125 881a9dd9 2021-01-16 op vec.iov_len = sizeof(int);
126 881a9dd9 2021-01-16 op msg.msg_iov = &vec;
127 881a9dd9 2021-01-16 op msg.msg_iovlen = 1;
128 881a9dd9 2021-01-16 op
129 881a9dd9 2021-01-16 op if ((n = sendmsg(fd, &msg, 0)) == -1 || n != sizeof(int)) {
130 881a9dd9 2021-01-16 op fprintf(stderr, "sendmsg: got %zu but wanted %zu: (errno) %s",
131 881a9dd9 2021-01-16 op n, sizeof(int), strerror(errno));
132 881a9dd9 2021-01-16 op return 0;
133 881a9dd9 2021-01-16 op }
134 881a9dd9 2021-01-16 op return 1;
135 881a9dd9 2021-01-16 op }
136 881a9dd9 2021-01-16 op
137 881a9dd9 2021-01-16 op /* receive a descriptor via fd */
138 881a9dd9 2021-01-16 op int
139 881a9dd9 2021-01-16 op recv_fd(int fd)
140 881a9dd9 2021-01-16 op {
141 881a9dd9 2021-01-16 op struct msghdr msg;
142 881a9dd9 2021-01-16 op union {
143 881a9dd9 2021-01-16 op struct cmsghdr hdr;
144 881a9dd9 2021-01-16 op char buf[CMSG_SPACE(sizeof(int))];
145 881a9dd9 2021-01-16 op } cmsgbuf;
146 881a9dd9 2021-01-16 op struct cmsghdr *cmsg;
147 881a9dd9 2021-01-16 op struct iovec vec;
148 881a9dd9 2021-01-16 op ssize_t n;
149 881a9dd9 2021-01-16 op int result;
150 881a9dd9 2021-01-16 op
151 881a9dd9 2021-01-16 op memset(&msg, 0, sizeof(msg));
152 881a9dd9 2021-01-16 op vec.iov_base = &result;
153 881a9dd9 2021-01-16 op vec.iov_len = sizeof(int);
154 881a9dd9 2021-01-16 op msg.msg_iov = &vec;
155 881a9dd9 2021-01-16 op msg.msg_iovlen = 1;
156 881a9dd9 2021-01-16 op msg.msg_control = &cmsgbuf.buf;
157 881a9dd9 2021-01-16 op msg.msg_controllen = sizeof(cmsgbuf.buf);
158 881a9dd9 2021-01-16 op
159 881a9dd9 2021-01-16 op if ((n = recvmsg(fd, &msg, 0)) != sizeof(int)) {
160 881a9dd9 2021-01-16 op fprintf(stderr, "read %zu bytes bu wanted %zu\n", n, sizeof(int));
161 881a9dd9 2021-01-16 op return -1;
162 881a9dd9 2021-01-16 op }
163 881a9dd9 2021-01-16 op
164 881a9dd9 2021-01-16 op if (result) {
165 881a9dd9 2021-01-16 op cmsg = CMSG_FIRSTHDR(&msg);
166 881a9dd9 2021-01-16 op if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS)
167 881a9dd9 2021-01-16 op return -1;
168 881a9dd9 2021-01-16 op return (*(int *)CMSG_DATA(cmsg));
169 881a9dd9 2021-01-16 op } else
170 881a9dd9 2021-01-16 op return -1;
171 881a9dd9 2021-01-16 op }
172 881a9dd9 2021-01-16 op
173 881a9dd9 2021-01-16 op static inline void
174 881a9dd9 2021-01-16 op safe_setenv(const char *name, const char *val)
175 881a9dd9 2021-01-16 op {
176 881a9dd9 2021-01-16 op if (val == NULL)
177 881a9dd9 2021-01-16 op val = "";
178 881a9dd9 2021-01-16 op setenv(name, val, 1);
179 881a9dd9 2021-01-16 op }
180 881a9dd9 2021-01-16 op
181 881a9dd9 2021-01-16 op /* fd or -1 on error */
182 881a9dd9 2021-01-16 op static int
183 881a9dd9 2021-01-16 op launch_cgi(const char *spath, const char *relpath, const char *query,
184 881a9dd9 2021-01-16 op const char *addr, const char *ruser, const char *cissuer, const char *chash,
185 881a9dd9 2021-01-16 op struct vhost *vhost)
186 881a9dd9 2021-01-16 op {
187 881a9dd9 2021-01-16 op int p[2]; /* read end, write end */
188 881a9dd9 2021-01-16 op
189 881a9dd9 2021-01-16 op if (pipe2(p, O_NONBLOCK) == -1)
190 881a9dd9 2021-01-16 op return -1;
191 881a9dd9 2021-01-16 op
192 881a9dd9 2021-01-16 op switch (fork()) {
193 881a9dd9 2021-01-16 op case -1:
194 881a9dd9 2021-01-16 op return -1;
195 881a9dd9 2021-01-16 op
196 881a9dd9 2021-01-16 op case 0: { /* child */
197 881a9dd9 2021-01-16 op char *portno, *ex, *requri;
198 881a9dd9 2021-01-16 op char *argv[] = { NULL, NULL, NULL };
199 881a9dd9 2021-01-16 op
200 881a9dd9 2021-01-16 op close(p[0]);
201 881a9dd9 2021-01-16 op if (dup2(p[1], 1) == -1)
202 881a9dd9 2021-01-16 op goto childerr;
203 881a9dd9 2021-01-16 op
204 881a9dd9 2021-01-16 op if (asprintf(&portno, "%d", conf.port) == -1)
205 881a9dd9 2021-01-16 op goto childerr;
206 881a9dd9 2021-01-16 op
207 881a9dd9 2021-01-16 op if (asprintf(&ex, "%s/%s", vhost->dir, spath) == -1)
208 881a9dd9 2021-01-16 op goto childerr;
209 881a9dd9 2021-01-16 op
210 881a9dd9 2021-01-16 op if (asprintf(&requri, "%s%s%s", spath,
211 568a09c2 2021-01-18 op (relpath != NULL && *relpath == '\0') ? "" : "/",
212 568a09c2 2021-01-18 op (relpath != NULL ? relpath : "")) == -1)
213 881a9dd9 2021-01-16 op goto childerr;
214 881a9dd9 2021-01-16 op
215 881a9dd9 2021-01-16 op argv[0] = argv[1] = ex;
216 881a9dd9 2021-01-16 op
217 881a9dd9 2021-01-16 op safe_setenv("GATEWAY_INTERFACE", "CGI/1.1");
218 28ec6178 2021-01-24 op safe_setenv("SERVER_PROTOCOL", "GEMINI");
219 881a9dd9 2021-01-16 op safe_setenv("SERVER_SOFTWARE", "gmid");
220 881a9dd9 2021-01-16 op safe_setenv("SERVER_PORT", portno);
221 881a9dd9 2021-01-16 op
222 881a9dd9 2021-01-16 op if (!strcmp(vhost->domain, "*"))
223 881a9dd9 2021-01-16 op safe_setenv("SERVER_NAME", vhost->domain);
224 881a9dd9 2021-01-16 op
225 881a9dd9 2021-01-16 op safe_setenv("SCRIPT_NAME", spath);
226 881a9dd9 2021-01-16 op safe_setenv("SCRIPT_EXECUTABLE", ex);
227 881a9dd9 2021-01-16 op safe_setenv("REQUEST_URI", requri);
228 881a9dd9 2021-01-16 op safe_setenv("REQUEST_RELATIVE", relpath);
229 881a9dd9 2021-01-16 op safe_setenv("QUERY_STRING", query);
230 881a9dd9 2021-01-16 op safe_setenv("REMOTE_HOST", addr);
231 881a9dd9 2021-01-16 op safe_setenv("REMOTE_ADDR", addr);
232 881a9dd9 2021-01-16 op safe_setenv("DOCUMENT_ROOT", vhost->dir);
233 881a9dd9 2021-01-16 op
234 881a9dd9 2021-01-16 op if (ruser != NULL) {
235 881a9dd9 2021-01-16 op safe_setenv("AUTH_TYPE", "Certificate");
236 881a9dd9 2021-01-16 op safe_setenv("REMOTE_USER", ruser);
237 881a9dd9 2021-01-16 op safe_setenv("TLS_CLIENT_ISSUER", cissuer);
238 881a9dd9 2021-01-16 op safe_setenv("TLS_CLIENT_HASH", chash);
239 881a9dd9 2021-01-16 op }
240 05748e49 2021-01-24 op
241 0baf6bed 2021-01-24 op fchdir(vhost->dirfd);
242 881a9dd9 2021-01-16 op
243 881a9dd9 2021-01-16 op execvp(ex, argv);
244 881a9dd9 2021-01-16 op goto childerr;
245 881a9dd9 2021-01-16 op }
246 881a9dd9 2021-01-16 op
247 881a9dd9 2021-01-16 op default:
248 881a9dd9 2021-01-16 op close(p[1]);
249 881a9dd9 2021-01-16 op return p[0];
250 881a9dd9 2021-01-16 op }
251 881a9dd9 2021-01-16 op
252 881a9dd9 2021-01-16 op childerr:
253 881a9dd9 2021-01-16 op dprintf(p[1], "%d internal server error\r\n", TEMP_FAILURE);
254 881a9dd9 2021-01-16 op _exit(1);
255 881a9dd9 2021-01-16 op }
256 881a9dd9 2021-01-16 op
257 881a9dd9 2021-01-16 op int
258 881a9dd9 2021-01-16 op executor_main(int fd)
259 881a9dd9 2021-01-16 op {
260 881a9dd9 2021-01-16 op char *spath, *relpath, *query, *addr, *ruser, *cissuer, *chash;
261 881a9dd9 2021-01-16 op struct vhost *vhost;
262 881a9dd9 2021-01-16 op int d;
263 881a9dd9 2021-01-16 op
264 881a9dd9 2021-01-16 op #ifdef __OpenBSD__
265 881a9dd9 2021-01-16 op pledge("stdio sendfd proc exec", NULL);
266 881a9dd9 2021-01-16 op #endif
267 881a9dd9 2021-01-16 op
268 881a9dd9 2021-01-16 op for (;;) {
269 881a9dd9 2021-01-16 op if (!recv_string(fd, &spath)
270 881a9dd9 2021-01-16 op || !recv_string(fd, &relpath)
271 881a9dd9 2021-01-16 op || !recv_string(fd, &query)
272 881a9dd9 2021-01-16 op || !recv_string(fd, &addr)
273 881a9dd9 2021-01-16 op || !recv_string(fd, &ruser)
274 881a9dd9 2021-01-16 op || !recv_string(fd, &cissuer)
275 881a9dd9 2021-01-16 op || !recv_string(fd, &chash)
276 881a9dd9 2021-01-16 op || !recv_vhost(fd, &vhost))
277 881a9dd9 2021-01-16 op break;
278 881a9dd9 2021-01-16 op
279 881a9dd9 2021-01-16 op d = launch_cgi(spath, relpath, query,
280 881a9dd9 2021-01-16 op addr, ruser, cissuer, chash, vhost);
281 881a9dd9 2021-01-16 op if (!send_fd(fd, d))
282 881a9dd9 2021-01-16 op break;
283 710a71b2 2021-01-19 op close(d);
284 881a9dd9 2021-01-16 op
285 881a9dd9 2021-01-16 op free(spath);
286 881a9dd9 2021-01-16 op free(relpath);
287 881a9dd9 2021-01-16 op free(query);
288 881a9dd9 2021-01-16 op free(addr);
289 881a9dd9 2021-01-16 op free(ruser);
290 881a9dd9 2021-01-16 op free(cissuer);
291 881a9dd9 2021-01-16 op free(chash);
292 881a9dd9 2021-01-16 op }
293 881a9dd9 2021-01-16 op
294 881a9dd9 2021-01-16 op /* kill all process in my group. This means the listener and
295 881a9dd9 2021-01-16 op * every pending CGI script. */
296 881a9dd9 2021-01-16 op kill(0, SIGINT);
297 881a9dd9 2021-01-16 op return 1;
298 881a9dd9 2021-01-16 op }