Blame


1 8ad1c570 2021-05-09 op /*
2 eac9287d 2023-06-24 op * Copyright (c) 2021, 2022, 2023 Omar Polo <op@omarpolo.com>
3 8ad1c570 2021-05-09 op *
4 8ad1c570 2021-05-09 op * Permission to use, copy, modify, and distribute this software for any
5 8ad1c570 2021-05-09 op * purpose with or without fee is hereby granted, provided that the above
6 8ad1c570 2021-05-09 op * copyright notice and this permission notice appear in all copies.
7 8ad1c570 2021-05-09 op *
8 8ad1c570 2021-05-09 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 8ad1c570 2021-05-09 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 8ad1c570 2021-05-09 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 8ad1c570 2021-05-09 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 8ad1c570 2021-05-09 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 8ad1c570 2021-05-09 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 8ad1c570 2021-05-09 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 8ad1c570 2021-05-09 op */
16 8ad1c570 2021-05-09 op
17 8ad1c570 2021-05-09 op #include "gmid.h"
18 8ad1c570 2021-05-09 op
19 8ad1c570 2021-05-09 op #include <assert.h>
20 0f7fdd21 2023-07-01 op #include <ctype.h>
21 8ad1c570 2021-05-09 op #include <errno.h>
22 8ad1c570 2021-05-09 op #include <string.h>
23 df5058c9 2023-06-05 op
24 eae52ad4 2023-06-06 op #include "log.h"
25 8ad1c570 2021-05-09 op
26 8ad1c570 2021-05-09 op struct fcgi_header {
27 8ad1c570 2021-05-09 op unsigned char version;
28 8ad1c570 2021-05-09 op unsigned char type;
29 8ad1c570 2021-05-09 op unsigned char req_id1;
30 8ad1c570 2021-05-09 op unsigned char req_id0;
31 8ad1c570 2021-05-09 op unsigned char content_len1;
32 8ad1c570 2021-05-09 op unsigned char content_len0;
33 8ad1c570 2021-05-09 op unsigned char padding;
34 8ad1c570 2021-05-09 op unsigned char reserved;
35 8ad1c570 2021-05-09 op };
36 8ad1c570 2021-05-09 op
37 8ad1c570 2021-05-09 op /*
38 8ad1c570 2021-05-09 op * number of bytes in a FCGI_HEADER. Future version of the protocol
39 8ad1c570 2021-05-09 op * will not reduce this number.
40 8ad1c570 2021-05-09 op */
41 8ad1c570 2021-05-09 op #define FCGI_HEADER_LEN 8
42 8ad1c570 2021-05-09 op
43 8ad1c570 2021-05-09 op /*
44 8ad1c570 2021-05-09 op * values for the version component
45 8ad1c570 2021-05-09 op */
46 8ad1c570 2021-05-09 op #define FCGI_VERSION_1 1
47 8ad1c570 2021-05-09 op
48 8ad1c570 2021-05-09 op /*
49 8ad1c570 2021-05-09 op * values for the type component
50 8ad1c570 2021-05-09 op */
51 8ad1c570 2021-05-09 op #define FCGI_BEGIN_REQUEST 1
52 8ad1c570 2021-05-09 op #define FCGI_ABORT_REQUEST 2
53 8ad1c570 2021-05-09 op #define FCGI_END_REQUEST 3
54 8ad1c570 2021-05-09 op #define FCGI_PARAMS 4
55 8ad1c570 2021-05-09 op #define FCGI_STDIN 5
56 8ad1c570 2021-05-09 op #define FCGI_STDOUT 6
57 8ad1c570 2021-05-09 op #define FCGI_STDERR 7
58 8ad1c570 2021-05-09 op #define FCGI_DATA 8
59 8ad1c570 2021-05-09 op #define FCGI_GET_VALUES 9
60 8ad1c570 2021-05-09 op #define FCGI_GET_VALUES_RESULT 10
61 8ad1c570 2021-05-09 op #define FCGI_UNKNOWN_TYPE 11
62 8ad1c570 2021-05-09 op #define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
63 8ad1c570 2021-05-09 op
64 8ad1c570 2021-05-09 op struct fcgi_begin_req {
65 8ad1c570 2021-05-09 op unsigned char role1;
66 8ad1c570 2021-05-09 op unsigned char role0;
67 8ad1c570 2021-05-09 op unsigned char flags;
68 8ad1c570 2021-05-09 op unsigned char reserved[5];
69 8ad1c570 2021-05-09 op };
70 8ad1c570 2021-05-09 op
71 8ad1c570 2021-05-09 op struct fcgi_begin_req_record {
72 8ad1c570 2021-05-09 op struct fcgi_header header;
73 8ad1c570 2021-05-09 op struct fcgi_begin_req body;
74 8ad1c570 2021-05-09 op };
75 8ad1c570 2021-05-09 op
76 8ad1c570 2021-05-09 op /*
77 8ad1c570 2021-05-09 op * mask for flags;
78 8ad1c570 2021-05-09 op */
79 8ad1c570 2021-05-09 op #define FCGI_KEEP_CONN 1
80 8ad1c570 2021-05-09 op
81 8ad1c570 2021-05-09 op /*
82 8ad1c570 2021-05-09 op * values for the role
83 8ad1c570 2021-05-09 op */
84 8ad1c570 2021-05-09 op #define FCGI_RESPONDER 1
85 8ad1c570 2021-05-09 op #define FCGI_AUTHORIZER 2
86 8ad1c570 2021-05-09 op #define FCGI_FILTER 3
87 8ad1c570 2021-05-09 op
88 8ad1c570 2021-05-09 op struct fcgi_end_req_body {
89 8ad1c570 2021-05-09 op unsigned char app_status3;
90 8ad1c570 2021-05-09 op unsigned char app_status2;
91 8ad1c570 2021-05-09 op unsigned char app_status1;
92 8ad1c570 2021-05-09 op unsigned char app_status0;
93 8ad1c570 2021-05-09 op unsigned char proto_status;
94 8ad1c570 2021-05-09 op unsigned char reserved[3];
95 8ad1c570 2021-05-09 op };
96 8ad1c570 2021-05-09 op
97 8ad1c570 2021-05-09 op /*
98 8ad1c570 2021-05-09 op * values for proto_status
99 8ad1c570 2021-05-09 op */
100 8ad1c570 2021-05-09 op #define FCGI_REQUEST_COMPLETE 0
101 8ad1c570 2021-05-09 op #define FCGI_CANT_MPX_CONN 1
102 8ad1c570 2021-05-09 op #define FCGI_OVERLOADED 2
103 8ad1c570 2021-05-09 op #define FCGI_UNKNOWN_ROLE 3
104 8ad1c570 2021-05-09 op
105 8ad1c570 2021-05-09 op /*
106 8ad1c570 2021-05-09 op * Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT
107 8ad1c570 2021-05-09 op * records.
108 8ad1c570 2021-05-09 op */
109 8ad1c570 2021-05-09 op #define FCGI_MAX_CONNS "FCGI_MAX_CONNS"
110 8ad1c570 2021-05-09 op #define FCGI_MAX_REQS "FCGI_MAX_REQS"
111 8ad1c570 2021-05-09 op #define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS"
112 8ad1c570 2021-05-09 op
113 8ad1c570 2021-05-09 op static int
114 4cd25209 2021-10-07 op prepare_header(struct fcgi_header *h, int type, size_t size,
115 8ad1c570 2021-05-09 op size_t padding)
116 8ad1c570 2021-05-09 op {
117 4cd25209 2021-10-07 op int id = 1;
118 4cd25209 2021-10-07 op
119 8ad1c570 2021-05-09 op memset(h, 0, sizeof(*h));
120 8ad1c570 2021-05-09 op
121 8ad1c570 2021-05-09 op h->version = FCGI_VERSION_1;
122 4842c72d 2021-10-18 op h->type = type;
123 8ad1c570 2021-05-09 op h->req_id1 = (id >> 8);
124 8ad1c570 2021-05-09 op h->req_id0 = (id & 0xFF);
125 8ad1c570 2021-05-09 op h->content_len1 = (size >> 8);
126 8ad1c570 2021-05-09 op h->content_len0 = (size & 0xFF);
127 8ad1c570 2021-05-09 op h->padding = padding;
128 8ad1c570 2021-05-09 op
129 8ad1c570 2021-05-09 op return 0;
130 8ad1c570 2021-05-09 op }
131 8ad1c570 2021-05-09 op
132 8ad1c570 2021-05-09 op static int
133 4cd25209 2021-10-07 op fcgi_begin_request(struct bufferevent *bev)
134 8ad1c570 2021-05-09 op {
135 8ad1c570 2021-05-09 op struct fcgi_begin_req_record r;
136 8ad1c570 2021-05-09 op
137 8ad1c570 2021-05-09 op memset(&r, 0, sizeof(r));
138 4cd25209 2021-10-07 op prepare_header(&r.header, FCGI_BEGIN_REQUEST, sizeof(r.body), 0);
139 8ad1c570 2021-05-09 op assert(sizeof(r.body) == FCGI_HEADER_LEN);
140 8ad1c570 2021-05-09 op
141 8ad1c570 2021-05-09 op r.body.role1 = 0;
142 8ad1c570 2021-05-09 op r.body.role0 = FCGI_RESPONDER;
143 8ad1c570 2021-05-09 op r.body.flags = FCGI_KEEP_CONN;
144 8ad1c570 2021-05-09 op
145 741b69be 2021-09-26 op if (bufferevent_write(bev, &r, sizeof(r)) == -1)
146 8ad1c570 2021-05-09 op return -1;
147 8ad1c570 2021-05-09 op return 0;
148 8ad1c570 2021-05-09 op }
149 8ad1c570 2021-05-09 op
150 8ad1c570 2021-05-09 op static int
151 4cd25209 2021-10-07 op fcgi_send_param(struct bufferevent *bev, const char *name,
152 741b69be 2021-09-26 op const char *value)
153 8ad1c570 2021-05-09 op {
154 8ad1c570 2021-05-09 op struct fcgi_header h;
155 4842c72d 2021-10-18 op uint32_t namlen, vallen, padlen;
156 8ad1c570 2021-05-09 op uint8_t s[8];
157 8ad1c570 2021-05-09 op size_t size;
158 e5d82d94 2022-03-19 op const char padding[8] = { 0 };
159 8ad1c570 2021-05-09 op
160 8ad1c570 2021-05-09 op namlen = strlen(name);
161 8ad1c570 2021-05-09 op vallen = strlen(value);
162 8ad1c570 2021-05-09 op size = namlen + vallen + 8; /* 4 for the sizes */
163 8ad1c570 2021-05-09 op padlen = (8 - (size & 0x7)) & 0x7;
164 8ad1c570 2021-05-09 op
165 8ad1c570 2021-05-09 op s[0] = ( namlen >> 24) | 0x80;
166 8ad1c570 2021-05-09 op s[1] = ((namlen >> 16) & 0xFF);
167 8ad1c570 2021-05-09 op s[2] = ((namlen >> 8) & 0xFF);
168 8ad1c570 2021-05-09 op s[3] = ( namlen & 0xFF);
169 8ad1c570 2021-05-09 op
170 8ad1c570 2021-05-09 op s[4] = ( vallen >> 24) | 0x80;
171 8ad1c570 2021-05-09 op s[5] = ((vallen >> 16) & 0xFF);
172 8ad1c570 2021-05-09 op s[6] = ((vallen >> 8) & 0xFF);
173 8ad1c570 2021-05-09 op s[7] = ( vallen & 0xFF);
174 8ad1c570 2021-05-09 op
175 4cd25209 2021-10-07 op prepare_header(&h, FCGI_PARAMS, size, padlen);
176 8ad1c570 2021-05-09 op
177 741b69be 2021-09-26 op if (bufferevent_write(bev, &h, sizeof(h)) == -1 ||
178 741b69be 2021-09-26 op bufferevent_write(bev, s, sizeof(s)) == -1 ||
179 741b69be 2021-09-26 op bufferevent_write(bev, name, namlen) == -1 ||
180 741b69be 2021-09-26 op bufferevent_write(bev, value, vallen) == -1 ||
181 741b69be 2021-09-26 op bufferevent_write(bev, padding, padlen) == -1)
182 8ad1c570 2021-05-09 op return -1;
183 8ad1c570 2021-05-09 op
184 8ad1c570 2021-05-09 op return 0;
185 8ad1c570 2021-05-09 op }
186 8ad1c570 2021-05-09 op
187 8ad1c570 2021-05-09 op static int
188 4cd25209 2021-10-07 op fcgi_end_param(struct bufferevent *bev)
189 8ad1c570 2021-05-09 op {
190 8ad1c570 2021-05-09 op struct fcgi_header h;
191 8ad1c570 2021-05-09 op
192 4cd25209 2021-10-07 op prepare_header(&h, FCGI_PARAMS, 0, 0);
193 741b69be 2021-09-26 op if (bufferevent_write(bev, &h, sizeof(h)) == -1)
194 8ad1c570 2021-05-09 op return -1;
195 8ad1c570 2021-05-09 op
196 4cd25209 2021-10-07 op prepare_header(&h, FCGI_STDIN, 0, 0);
197 741b69be 2021-09-26 op if (bufferevent_write(bev, &h, sizeof(h)) == -1)
198 8ad1c570 2021-05-09 op return -1;
199 8ad1c570 2021-05-09 op
200 8ad1c570 2021-05-09 op return 0;
201 8ad1c570 2021-05-09 op }
202 8ad1c570 2021-05-09 op
203 8ad1c570 2021-05-09 op static inline int
204 8ad1c570 2021-05-09 op recid(struct fcgi_header *h)
205 8ad1c570 2021-05-09 op {
206 4cd25209 2021-10-07 op return h->req_id0 + (h->req_id1 << 8);
207 8ad1c570 2021-05-09 op }
208 8ad1c570 2021-05-09 op
209 8ad1c570 2021-05-09 op static inline int
210 8ad1c570 2021-05-09 op reclen(struct fcgi_header *h)
211 8ad1c570 2021-05-09 op {
212 8ad1c570 2021-05-09 op return h->content_len0 + (h->content_len1 << 8);
213 0f7fdd21 2023-07-01 op }
214 0f7fdd21 2023-07-01 op
215 0f7fdd21 2023-07-01 op static void
216 0f7fdd21 2023-07-01 op fcgi_handle_stdout(struct client *c, struct evbuffer *src, size_t len)
217 0f7fdd21 2023-07-01 op {
218 0f7fdd21 2023-07-01 op struct bufferevent *bev = c->cgibev;
219 0f7fdd21 2023-07-01 op char *t;
220 0f7fdd21 2023-07-01 op size_t l;
221 0f7fdd21 2023-07-01 op int code;
222 0f7fdd21 2023-07-01 op
223 0f7fdd21 2023-07-01 op if (c->code == 0) {
224 0f7fdd21 2023-07-01 op l = len;
225 0f7fdd21 2023-07-01 op if (l > sizeof(c->sbuf) - c->soff)
226 0f7fdd21 2023-07-01 op l = sizeof(c->sbuf) - c->soff;
227 0f7fdd21 2023-07-01 op
228 0f7fdd21 2023-07-01 op memcpy(&c->sbuf[c->soff], EVBUFFER_DATA(src), l);
229 0f7fdd21 2023-07-01 op c->soff += l;
230 0f7fdd21 2023-07-01 op evbuffer_drain(src, l);
231 0f7fdd21 2023-07-01 op len -= l;
232 0f7fdd21 2023-07-01 op
233 0f7fdd21 2023-07-01 op if ((t = memmem(c->sbuf, c->soff, "\r\n", 2)) == NULL) {
234 0f7fdd21 2023-07-01 op if (c->soff == sizeof(c->sbuf)) {
235 0f7fdd21 2023-07-01 op log_warnx("FastCGI application is trying to"
236 0f7fdd21 2023-07-01 op " send a header that's too long.");
237 0f7fdd21 2023-07-01 op fcgi_error(bev, EVBUFFER_ERROR, c);
238 0f7fdd21 2023-07-01 op }
239 0f7fdd21 2023-07-01 op
240 0f7fdd21 2023-07-01 op /* wait a bit */
241 0f7fdd21 2023-07-01 op return;
242 0f7fdd21 2023-07-01 op }
243 0f7fdd21 2023-07-01 op *t = '\0';
244 0f7fdd21 2023-07-01 op t += 2; /* skip CRLF */
245 0f7fdd21 2023-07-01 op
246 0f7fdd21 2023-07-01 op if (!isdigit((unsigned char)c->sbuf[0]) ||
247 0f7fdd21 2023-07-01 op !isdigit((unsigned char)c->sbuf[1]) ||
248 0f7fdd21 2023-07-01 op c->sbuf[2] != ' ') {
249 0f7fdd21 2023-07-01 op fcgi_error(bev, EVBUFFER_ERROR, c);
250 0f7fdd21 2023-07-01 op return;
251 0f7fdd21 2023-07-01 op }
252 0f7fdd21 2023-07-01 op
253 0f7fdd21 2023-07-01 op code = (c->sbuf[0] - '0') * 10 + (c->sbuf[1] - '0');
254 0f7fdd21 2023-07-01 op if (code < 10 || code >= 70) {
255 0f7fdd21 2023-07-01 op log_warnx("FastCGI application is trying to send an"
256 0f7fdd21 2023-07-01 op " invalid reply code: %d", code);
257 0f7fdd21 2023-07-01 op fcgi_error(bev, EVBUFFER_ERROR, c);
258 0f7fdd21 2023-07-01 op return;
259 0f7fdd21 2023-07-01 op }
260 0f7fdd21 2023-07-01 op
261 390d312b 2023-08-09 op if (start_reply(c, code, c->sbuf + 3) == -1 ||
262 390d312b 2023-08-09 op c->code < 20 || c->code > 29) {
263 0f7fdd21 2023-07-01 op fcgi_error(bev, EVBUFFER_EOF, c);
264 0f7fdd21 2023-07-01 op return;
265 0f7fdd21 2023-07-01 op }
266 0f7fdd21 2023-07-01 op
267 0f7fdd21 2023-07-01 op bufferevent_write(c->bev, t, &c->sbuf[c->soff] - t);
268 0f7fdd21 2023-07-01 op }
269 0f7fdd21 2023-07-01 op
270 0f7fdd21 2023-07-01 op bufferevent_write(c->bev, EVBUFFER_DATA(src), len);
271 0f7fdd21 2023-07-01 op evbuffer_drain(src, len);
272 8ad1c570 2021-05-09 op }
273 8ad1c570 2021-05-09 op
274 090b8a89 2021-07-06 op void
275 741b69be 2021-09-26 op fcgi_read(struct bufferevent *bev, void *d)
276 8ad1c570 2021-05-09 op {
277 4cd25209 2021-10-07 op struct client *c = d;
278 741b69be 2021-09-26 op struct evbuffer *src = EVBUFFER_INPUT(bev);
279 741b69be 2021-09-26 op struct fcgi_header hdr;
280 8ad1c570 2021-05-09 op struct fcgi_end_req_body end;
281 8ad1c570 2021-05-09 op size_t len;
282 8ad1c570 2021-05-09 op
283 390d312b 2023-08-09 op while (c->type != REQUEST_DONE) {
284 741b69be 2021-09-26 op if (EVBUFFER_LENGTH(src) < sizeof(hdr))
285 741b69be 2021-09-26 op return;
286 090b8a89 2021-07-06 op
287 741b69be 2021-09-26 op memcpy(&hdr, EVBUFFER_DATA(src), sizeof(hdr));
288 8ad1c570 2021-05-09 op
289 4cd25209 2021-10-07 op if (recid(&hdr) != 1) {
290 eae52ad4 2023-06-06 op log_warnx("got invalid client id %d from fcgi backend",
291 4cd25209 2021-10-07 op recid(&hdr));
292 8ad1c570 2021-05-09 op goto err;
293 741b69be 2021-09-26 op }
294 741b69be 2021-09-26 op
295 741b69be 2021-09-26 op len = reclen(&hdr);
296 8ad1c570 2021-05-09 op
297 741b69be 2021-09-26 op if (EVBUFFER_LENGTH(src) < sizeof(hdr) + len + hdr.padding)
298 741b69be 2021-09-26 op return;
299 8ad1c570 2021-05-09 op
300 741b69be 2021-09-26 op evbuffer_drain(src, sizeof(hdr));
301 741b69be 2021-09-26 op
302 741b69be 2021-09-26 op switch (hdr.type) {
303 741b69be 2021-09-26 op case FCGI_END_REQUEST:
304 741b69be 2021-09-26 op if (len != sizeof(end)) {
305 eae52ad4 2023-06-06 op log_warnx("got invalid end request"
306 eae52ad4 2023-06-06 op " record size");
307 741b69be 2021-09-26 op goto err;
308 741b69be 2021-09-26 op }
309 741b69be 2021-09-26 op bufferevent_read(bev, &end, sizeof(end));
310 741b69be 2021-09-26 op
311 741b69be 2021-09-26 op /* TODO: do something with the status? */
312 efe7d180 2021-10-02 op c->type = REQUEST_DONE;
313 390d312b 2023-08-09 op break;
314 741b69be 2021-09-26 op
315 741b69be 2021-09-26 op case FCGI_STDERR:
316 741b69be 2021-09-26 op /* discard stderr (for now) */
317 741b69be 2021-09-26 op evbuffer_drain(src, len);
318 741b69be 2021-09-26 op break;
319 741b69be 2021-09-26 op
320 741b69be 2021-09-26 op case FCGI_STDOUT:
321 0f7fdd21 2023-07-01 op fcgi_handle_stdout(c, src, len);
322 741b69be 2021-09-26 op break;
323 8ad1c570 2021-05-09 op
324 741b69be 2021-09-26 op default:
325 eae52ad4 2023-06-06 op log_warnx("got invalid fcgi record (type=%d)",
326 741b69be 2021-09-26 op hdr.type);
327 741b69be 2021-09-26 op goto err;
328 741b69be 2021-09-26 op }
329 8ad1c570 2021-05-09 op
330 741b69be 2021-09-26 op evbuffer_drain(src, hdr.padding);
331 741b69be 2021-09-26 op }
332 090b8a89 2021-07-06 op
333 741b69be 2021-09-26 op err:
334 4cd25209 2021-10-07 op fcgi_error(bev, EVBUFFER_ERROR, c);
335 390d312b 2023-08-09 op client_write(c->bev, c);
336 741b69be 2021-09-26 op }
337 741b69be 2021-09-26 op
338 741b69be 2021-09-26 op void
339 741b69be 2021-09-26 op fcgi_write(struct bufferevent *bev, void *d)
340 741b69be 2021-09-26 op {
341 741b69be 2021-09-26 op /*
342 741b69be 2021-09-26 op * There's no much use for the write callback.
343 741b69be 2021-09-26 op */
344 8ad1c570 2021-05-09 op return;
345 741b69be 2021-09-26 op }
346 8ad1c570 2021-05-09 op
347 741b69be 2021-09-26 op void
348 741b69be 2021-09-26 op fcgi_error(struct bufferevent *bev, short err, void *d)
349 741b69be 2021-09-26 op {
350 4cd25209 2021-10-07 op struct client *c = d;
351 741b69be 2021-09-26 op
352 0f7fdd21 2023-07-01 op /*
353 0f7fdd21 2023-07-01 op * If we're here it means that some kind of non-recoverable
354 0f7fdd21 2023-07-01 op * error happened.
355 390d312b 2023-08-09 op *
356 390d312b 2023-08-09 op * Don't free bev as we might be called by a function that
357 390d312b 2023-08-09 op * still uses it.
358 0f7fdd21 2023-07-01 op */
359 741b69be 2021-09-26 op
360 390d312b 2023-08-09 op bufferevent_disable(bev, EVBUFFER_READ);
361 0f7fdd21 2023-07-01 op
362 0f7fdd21 2023-07-01 op close(c->pfd);
363 0f7fdd21 2023-07-01 op c->pfd = -1;
364 0f7fdd21 2023-07-01 op
365 0f7fdd21 2023-07-01 op /* EOF and no header */
366 0f7fdd21 2023-07-01 op if (c->code == 0) {
367 4cd25209 2021-10-07 op start_reply(c, CGI_ERROR, "CGI error");
368 0f7fdd21 2023-07-01 op return;
369 0f7fdd21 2023-07-01 op }
370 0f7fdd21 2023-07-01 op
371 0f7fdd21 2023-07-01 op c->type = REQUEST_DONE;
372 8ad1c570 2021-05-09 op }
373 8ad1c570 2021-05-09 op
374 e872053b 2023-08-18 op static void
375 e872053b 2023-08-18 op path_translate(const char *path, struct location *loc, struct location *rloc,
376 e872053b 2023-08-18 op char *buf, size_t len)
377 e872053b 2023-08-18 op {
378 e872053b 2023-08-18 op const char *root, *sufx;
379 e872053b 2023-08-18 op
380 e872053b 2023-08-18 op buf[0] = '\0';
381 e872053b 2023-08-18 op
382 e872053b 2023-08-18 op if (*loc->dir != '\0')
383 e872053b 2023-08-18 op root = loc->dir;
384 e872053b 2023-08-18 op else if (*rloc->dir != '\0')
385 e872053b 2023-08-18 op root = rloc->dir;
386 e872053b 2023-08-18 op else
387 e872053b 2023-08-18 op return;
388 e872053b 2023-08-18 op
389 e872053b 2023-08-18 op sufx = "";
390 e872053b 2023-08-18 op if (*root != '\0')
391 e872053b 2023-08-18 op sufx = root[strlen(root) - 1] == '/' ? "" : "/";
392 e872053b 2023-08-18 op
393 e872053b 2023-08-18 op while (*path == '/')
394 e872053b 2023-08-18 op path++;
395 e872053b 2023-08-18 op
396 e872053b 2023-08-18 op snprintf(buf, len, "%s%s%s", root, sufx, path);
397 e872053b 2023-08-18 op }
398 e872053b 2023-08-18 op
399 8ad1c570 2021-05-09 op void
400 a1ba9650 2023-07-23 op fcgi_req(struct client *c, struct location *loc)
401 8ad1c570 2021-05-09 op {
402 e872053b 2023-08-18 op char buf[22], path[GEMINI_URL_LEN], path_tr[PATH_MAX];
403 a1e159c9 2023-08-08 op char *scriptname, *qs;
404 e872053b 2023-08-18 op const char *stripped, *port;
405 b27dc2b0 2023-08-08 op size_t l;
406 f740b61b 2021-06-11 op time_t tim;
407 f740b61b 2021-06-11 op struct tm tminfo;
408 f740b61b 2021-06-11 op struct envlist *p;
409 d1051bfa 2021-05-15 op
410 a1e159c9 2023-08-08 op fcgi_begin_request(c->cgibev);
411 a1e159c9 2023-08-08 op
412 e872053b 2023-08-18 op stripped = strip_path(c->iri.path, loc->fcgi_strip);
413 e872053b 2023-08-18 op if (*stripped != '/')
414 e872053b 2023-08-18 op snprintf(path, sizeof(path), "/%s", stripped);
415 e872053b 2023-08-18 op else
416 e872053b 2023-08-18 op strlcpy(path, stripped, sizeof(path));
417 e872053b 2023-08-18 op
418 e872053b 2023-08-18 op port = c->iri.host;
419 e872053b 2023-08-18 op if (port == NULL || *port == '\0')
420 e872053b 2023-08-18 op port = "1965";
421 e872053b 2023-08-18 op
422 a1e159c9 2023-08-08 op scriptname = "";
423 b27dc2b0 2023-08-08 op TAILQ_FOREACH(p, &loc->params, envs) {
424 b27dc2b0 2023-08-08 op if (!strcmp(p->name, "SCRIPT_NAME")) {
425 b27dc2b0 2023-08-08 op scriptname = p->value;
426 b27dc2b0 2023-08-08 op break;
427 b27dc2b0 2023-08-08 op }
428 b27dc2b0 2023-08-08 op }
429 b27dc2b0 2023-08-08 op
430 b27dc2b0 2023-08-08 op l = strlen(scriptname);
431 b27dc2b0 2023-08-08 op while (l > 0 && scriptname[l - 1] == '/')
432 b27dc2b0 2023-08-08 op l--;
433 a1e159c9 2023-08-08 op if (!strncmp(scriptname, path, l) && (path[l] == '/' ||
434 a1e159c9 2023-08-08 op path[l] == '\0')) {
435 a1e159c9 2023-08-08 op fcgi_send_param(c->cgibev, "PATH_INFO", &path[l]);
436 e872053b 2023-08-18 op path_translate(&path[l], loc, TAILQ_FIRST(&c->host->locations),
437 e872053b 2023-08-18 op path_tr, sizeof(path_tr));
438 a1e159c9 2023-08-08 op path[l] = '\0';
439 a1e159c9 2023-08-08 op fcgi_send_param(c->cgibev, "SCRIPT_NAME", path);
440 a1e159c9 2023-08-08 op } else {
441 e872053b 2023-08-18 op path_translate(stripped, loc, TAILQ_FIRST(&c->host->locations),
442 e872053b 2023-08-18 op path_tr, sizeof(path_tr));
443 a1e159c9 2023-08-08 op fcgi_send_param(c->cgibev, "PATH_INFO", stripped);
444 a1e159c9 2023-08-08 op fcgi_send_param(c->cgibev, "SCRIPT_NAME", scriptname);
445 a1e159c9 2023-08-08 op }
446 b27dc2b0 2023-08-08 op
447 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "GATEWAY_INTERFACE", "CGI/1.1");
448 e872053b 2023-08-18 op fcgi_send_param(c->cgibev, "PATH_TRANSLATED", path_tr);
449 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "QUERY_STRING", c->iri.query);
450 ed164e72 2023-06-26 op fcgi_send_param(c->cgibev, "REMOTE_ADDR", c->rhost);
451 ed164e72 2023-06-26 op fcgi_send_param(c->cgibev, "REMOTE_HOST", c->rhost);
452 e872053b 2023-08-18 op fcgi_send_param(c->cgibev, "REQUEST_METHOD", "GET");
453 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "SERVER_NAME", c->iri.host);
454 e872053b 2023-08-18 op fcgi_send_param(c->cgibev, "SERVER_PORT", port);
455 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "SERVER_PROTOCOL", "GEMINI");
456 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "SERVER_SOFTWARE", GMID_VERSION);
457 50a8f910 2022-10-30 op
458 e872053b 2023-08-18 op fcgi_send_param(c->cgibev, "GEMINI_URL_PATH", c->iri.path);
459 e872053b 2023-08-18 op
460 97b306cb 2022-11-27 op if (*c->iri.query != '\0' &&
461 97b306cb 2022-11-27 op strchr(c->iri.query, '=') == NULL &&
462 97b306cb 2022-11-27 op (qs = strdup(c->iri.query)) != NULL) {
463 97b306cb 2022-11-27 op pct_decode_str(qs);
464 97b306cb 2022-11-27 op fcgi_send_param(c->cgibev, "GEMINI_SEARCH_STRING", qs);
465 97b306cb 2022-11-27 op free(qs);
466 97b306cb 2022-11-27 op }
467 97b306cb 2022-11-27 op
468 a1ba9650 2023-07-23 op TAILQ_FOREACH(p, &loc->params, envs) {
469 b27dc2b0 2023-08-08 op if (!strcmp(p->name, "SCRIPT_NAME"))
470 b27dc2b0 2023-08-08 op continue;
471 50a8f910 2022-10-30 op fcgi_send_param(c->cgibev, p->name, p->value);
472 50a8f910 2022-10-30 op }
473 f740b61b 2021-06-11 op
474 f740b61b 2021-06-11 op if (tls_peer_cert_provided(c->ctx)) {
475 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "AUTH_TYPE", "CERTIFICATE");
476 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "REMOTE_USER",
477 f740b61b 2021-06-11 op tls_peer_cert_subject(c->ctx));
478 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "TLS_CLIENT_ISSUER",
479 f740b61b 2021-06-11 op tls_peer_cert_issuer(c->ctx));
480 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "TLS_CLIENT_HASH",
481 f740b61b 2021-06-11 op tls_peer_cert_hash(c->ctx));
482 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "TLS_VERSION",
483 f740b61b 2021-06-11 op tls_conn_version(c->ctx));
484 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "TLS_CIPHER",
485 f740b61b 2021-06-11 op tls_conn_cipher(c->ctx));
486 8ad1c570 2021-05-09 op
487 f740b61b 2021-06-11 op snprintf(buf, sizeof(buf), "%d",
488 f740b61b 2021-06-11 op tls_conn_cipher_strength(c->ctx));
489 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "TLS_CIPHER_STRENGTH", buf);
490 f740b61b 2021-06-11 op
491 f740b61b 2021-06-11 op tim = tls_peer_cert_notbefore(c->ctx);
492 f740b61b 2021-06-11 op strftime(buf, sizeof(buf), "%FT%TZ",
493 f740b61b 2021-06-11 op gmtime_r(&tim, &tminfo));
494 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "TLS_CLIENT_NOT_BEFORE", buf);
495 f740b61b 2021-06-11 op
496 f740b61b 2021-06-11 op tim = tls_peer_cert_notafter(c->ctx);
497 f740b61b 2021-06-11 op strftime(buf, sizeof(buf), "%FT%TZ",
498 f740b61b 2021-06-11 op gmtime_r(&tim, &tminfo));
499 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "TLS_CLIENT_NOT_AFTER", buf);
500 f740b61b 2021-06-11 op
501 f740b61b 2021-06-11 op } else
502 4cd25209 2021-10-07 op fcgi_send_param(c->cgibev, "AUTH_TYPE", "");
503 f740b61b 2021-06-11 op
504 4cd25209 2021-10-07 op if (fcgi_end_param(c->cgibev) == -1)
505 4cd25209 2021-10-07 op fcgi_error(c->cgibev, EVBUFFER_ERROR, c);
506 8ad1c570 2021-05-09 op }