1 /*
2 * mod_ajp13 - Apache JServ Protocol version 1.3 (AJP13) gateway
3 *
4 * Copyright(c) 2021 Glenn Strauss gstrauss()gluelogic.com All rights reserved
5 * License: BSD 3-clause (same as lighttpd)
6 *
7 * AJPv13 protocol reference:
8 * https://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
9 *
10 * Note: connection pool (and connection reuse) is not implemented
11 */
12 #include "first.h"
13
14 #include <sys/types.h>
15 #include <limits.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 #include "gw_backend.h"
20 typedef gw_plugin_config plugin_config;
21 typedef gw_plugin_data plugin_data;
22 typedef gw_handler_ctx handler_ctx;
23
24 #include "base.h"
25 #include "buffer.h"
26 #include "chunk.h"
27 #include "fdevent.h"
28 #include "http_chunk.h"
29 #include "http_header.h"
30 #include "http_kv.h"
31 #include "log.h"
32
33 #define AJP13_MAX_PACKET_SIZE 8192
34
35
36 static void
mod_ajp13_merge_config_cpv(plugin_config * const pconf,const config_plugin_value_t * const cpv)37 mod_ajp13_merge_config_cpv (plugin_config * const pconf, const config_plugin_value_t * const cpv)
38 {
39 switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
40 case 0: /* ajp13.server */
41 if (cpv->vtype == T_CONFIG_LOCAL) {
42 gw_plugin_config * const gw = cpv->v.v;
43 pconf->exts = gw->exts;
44 pconf->exts_auth = gw->exts_auth;
45 pconf->exts_resp = gw->exts_resp;
46 }
47 break;
48 case 1: /* ajp13.balance */
49 /*if (cpv->vtype == T_CONFIG_LOCAL)*//*always true here for this param*/
50 pconf->balance = (int)cpv->v.u;
51 break;
52 case 2: /* ajp13.debug */
53 pconf->debug = (int)cpv->v.u;
54 break;
55 case 3: /* ajp13.map-extensions */
56 pconf->ext_mapping = cpv->v.a;
57 break;
58 default:/* should not happen */
59 return;
60 }
61 }
62
63
64 static void
mod_ajp13_merge_config(plugin_config * const pconf,const config_plugin_value_t * cpv)65 mod_ajp13_merge_config (plugin_config * const pconf, const config_plugin_value_t *cpv)
66 {
67 do {
68 mod_ajp13_merge_config_cpv(pconf, cpv);
69 } while ((++cpv)->k_id != -1);
70 }
71
72
73 static void
mod_ajp13_patch_config(request_st * const r,plugin_data * const p)74 mod_ajp13_patch_config (request_st * const r, plugin_data * const p)
75 {
76 memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
77 for (int i = 1, used = p->nconfig; i < used; ++i) {
78 if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id))
79 mod_ajp13_merge_config(&p->conf,p->cvlist + p->cvlist[i].v.u2[0]);
80 }
81 }
82
83
SETDEFAULTS_FUNC(mod_ajp13_set_defaults)84 SETDEFAULTS_FUNC(mod_ajp13_set_defaults)
85 {
86 static const config_plugin_keys_t cpk[] = {
87 { CONST_STR_LEN("ajp13.server"),
88 T_CONFIG_ARRAY_KVARRAY,
89 T_CONFIG_SCOPE_CONNECTION }
90 ,{ CONST_STR_LEN("ajp13.balance"),
91 T_CONFIG_STRING,
92 T_CONFIG_SCOPE_CONNECTION }
93 ,{ CONST_STR_LEN("ajp13.debug"),
94 T_CONFIG_INT,
95 T_CONFIG_SCOPE_CONNECTION }
96 ,{ CONST_STR_LEN("ajp13.map-extensions"),
97 T_CONFIG_ARRAY_KVSTRING,
98 T_CONFIG_SCOPE_CONNECTION }
99 ,{ NULL, 0,
100 T_CONFIG_UNSET,
101 T_CONFIG_SCOPE_UNSET }
102 };
103
104 plugin_data * const p = p_d;
105 if (!config_plugin_values_init(srv, p, cpk, "mod_ajp13"))
106 return HANDLER_ERROR;
107
108 /* process and validate config directives
109 * (init i to 0 if global context; to 1 to skip empty global context) */
110 for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
111 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
112 gw_plugin_config *gw = NULL;
113 for (; -1 != cpv->k_id; ++cpv) {
114 switch (cpv->k_id) {
115 case 0:{/* ajp13.server */
116 gw = ck_calloc(1, sizeof(gw_plugin_config));
117 if (!gw_set_defaults_backend(srv, p, cpv->v.a, gw, 0,
118 cpk[cpv->k_id].k)) {
119 gw_plugin_config_free(gw);
120 return HANDLER_ERROR;
121 }
122 cpv->v.v = gw;
123 cpv->vtype = T_CONFIG_LOCAL;
124 break;
125 }
126 case 1: /* ajp13.balance */
127 cpv->v.u = (unsigned int)gw_get_defaults_balance(srv, cpv->v.b);
128 break;
129 case 2: /* ajp13.debug */
130 case 3: /* ajp13.map-extensions */
131 break;
132 default:/* should not happen */
133 break;
134 }
135 }
136
137 /* disable check-local for all exts (default enabled) */
138 if (gw && gw->exts) { /*(check after gw_set_defaults_backend())*/
139 gw_exts_clear_check_local(gw->exts);
140 }
141 }
142
143 /* default is 0 */
144 /*p->defaults.balance = (unsigned int)gw_get_defaults_balance(srv, NULL);*/
145
146 /* initialize p->defaults from global config context */
147 if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
148 const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
149 if (-1 != cpv->k_id)
150 mod_ajp13_merge_config(&p->defaults, cpv);
151 }
152
153 return HANDLER_GO_ON;
154 }
155
156
157 __attribute_pure__
158 static inline uint32_t
ajp13_dec_uint16(const uint8_t * const x)159 ajp13_dec_uint16 (const uint8_t * const x)
160 {
161 return (x[0] << 8) | x[1];
162 }
163
164
165 static inline void
ajp13_enc_uint16_nc(uint8_t * const x,const uint32_t v)166 ajp13_enc_uint16_nc (uint8_t * const x, const uint32_t v)
167 {
168 /*(_nc = no check; caller must check for sufficient space in x)*/
169 x[0] = 0xFF & (v >> 8);
170 x[1] = 0xFF & (v);
171 }
172
173
174 static uint32_t
ajp13_enc_uint16(uint8_t * const x,const uint32_t n,const uint32_t v)175 ajp13_enc_uint16 (uint8_t * const x, const uint32_t n, const uint32_t v)
176 {
177 if (n + 2 > AJP13_MAX_PACKET_SIZE) return 0;
178 ajp13_enc_uint16_nc(x+n, v);
179 return n+2;
180 }
181
182
183 static uint32_t
ajp13_enc_byte(uint8_t * const x,const uint32_t n,const uint32_t v)184 ajp13_enc_byte (uint8_t * const x, const uint32_t n, const uint32_t v)
185 {
186 if (n + 1 > AJP13_MAX_PACKET_SIZE) return 0;
187 x[n] = v;
188 return n+1;
189 }
190
191
192 static uint32_t
ajp13_enc_string(uint8_t * const x,uint32_t n,const char * const s,const uint32_t len)193 ajp13_enc_string (uint8_t * const x, uint32_t n, const char * const s, const uint32_t len)
194 {
195 /*assert(AJP13_MAX_PACKET_SIZE <= UINT16_MAX);*//*(max is 8k in practice)*/
196 if (0 == len || len == UINT16_MAX)
197 return ajp13_enc_uint16(x, n, 0xFFFF);
198
199 if (n + 2 + len + 1 > AJP13_MAX_PACKET_SIZE) return 0;
200 ajp13_enc_uint16_nc(x+n, len);
201 n += 2;
202 memcpy(x+n, s, len);
203 n += len;
204 x[n] = '\0';
205 return n+1;
206 }
207
208
209 static handler_t
ajp13_stdin_append(handler_ctx * const hctx)210 ajp13_stdin_append (handler_ctx * const hctx)
211 {
212 chunkqueue * const req_cq = &hctx->r->reqbody_queue;
213 const off_t req_cqlen = chunkqueue_length(req_cq);
214 const off_t max_bytes = hctx->request_id < req_cqlen
215 ? hctx->request_id < MAX_WRITE_LIMIT ? hctx->request_id : MAX_WRITE_LIMIT
216 : req_cqlen;
217 off_t sent = 0;
218 uint8_t hdr[4] = { 0x12, 0x34, 0, 0 };
219
220 for (off_t dlen; sent < max_bytes; sent += dlen) {
221 dlen = max_bytes - sent > AJP13_MAX_PACKET_SIZE - 4
222 ? AJP13_MAX_PACKET_SIZE - 4
223 : max_bytes - sent;
224
225 if (-1 != hctx->wb_reqlen) {
226 if (hctx->wb_reqlen >= 0)
227 hctx->wb_reqlen += sizeof(hdr);
228 else
229 hctx->wb_reqlen -= sizeof(hdr);
230 }
231
232 ajp13_enc_uint16_nc(hdr+2, (uint32_t)dlen);
233 (chunkqueue_is_empty(&hctx->wb) || hctx->wb.first->type == MEM_CHUNK)
234 /* else FILE_CHUNK for temp file */
235 ? chunkqueue_append_mem(&hctx->wb, (char *)&hdr, sizeof(hdr))
236 : chunkqueue_append_mem_min(&hctx->wb, (char *)&hdr, sizeof(hdr));
237 chunkqueue_steal(&hctx->wb, req_cq, dlen);
238 /*(hctx->wb_reqlen already includes reqbody_length)*/
239 }
240
241 hctx->request_id -= (int)sent;
242 return HANDLER_GO_ON;
243 }
244
245
246 static void
ajp13_stdin_append_n(handler_ctx * const hctx,const uint32_t n)247 ajp13_stdin_append_n (handler_ctx * const hctx, const uint32_t n)
248 {
249 if (hctx->wb.bytes_in == hctx->wb_reqlen) {
250 /*(no additional request body to be sent; send empty packet)*/
251 uint8_t hdr[4] = { 0x12, 0x34, 0, 0 };
252 hctx->wb_reqlen += sizeof(hdr);
253 chunkqueue_append_mem(&hctx->wb, (char *)hdr, sizeof(hdr));
254 }
255
256 /* AJP13 connections can be reused, so server and backend must agree on how
257 * much data is sent for each serialized request, especially if backend
258 * chooses not to read (and use or discard) entire request body from server.
259 * If server sent excess data, data might be interpreted as a subsequent
260 * request, which might be abused for request smuggling (security). */
261
262 /* overload hctx->request_id to track bytes requested by backend.
263 * Value must stay >= 0, since -1 is used to flag end of request */
264 if (n <= (uint32_t)(INT_MAX - hctx->request_id))
265 hctx->request_id += (int)n;
266 else /* unexpected; misbehaving backend sent MANY Get Body Chunk requests */
267 hctx->request_id = INT_MAX; /*(limitation of overloaded struct member)*/
268
269 ajp13_stdin_append(hctx);
270 }
271
272
273 __attribute_pure__
274 static uint8_t
ajp13_method_byte(const http_method_t m)275 ajp13_method_byte (const http_method_t m)
276 {
277 /* map lighttpd http_method_t to ajp13 method byte */
278
279 #if (defined(__STDC_VERSION__) && __STDC_VERSION__-0 >= 199901L) /* C99 */
280
281 static const uint8_t ajp13_methods[] = {
282 [HTTP_METHOD_GET] = 2,
283 [HTTP_METHOD_HEAD] = 3,
284 [HTTP_METHOD_POST] = 4,
285 [HTTP_METHOD_PUT] = 5,
286 [HTTP_METHOD_DELETE] = 6,
287 [HTTP_METHOD_OPTIONS] = 1,
288 [HTTP_METHOD_TRACE] = 7,
289 [HTTP_METHOD_ACL] = 15,
290 [HTTP_METHOD_BASELINE_CONTROL] = 26,
291 [HTTP_METHOD_CHECKIN] = 18,
292 [HTTP_METHOD_CHECKOUT] = 19,
293 [HTTP_METHOD_COPY] = 11,
294 [HTTP_METHOD_LABEL] = 24,
295 [HTTP_METHOD_LOCK] = 13,
296 [HTTP_METHOD_MERGE] = 25,
297 [HTTP_METHOD_MKACTIVITY] = 27,
298 [HTTP_METHOD_MKCOL] = 10,
299 [HTTP_METHOD_MKWORKSPACE] = 22,
300 [HTTP_METHOD_MOVE] = 12,
301 [HTTP_METHOD_PROPFIND] = 8,
302 [HTTP_METHOD_PROPPATCH] = 9,
303 [HTTP_METHOD_REPORT] = 16,
304 [HTTP_METHOD_SEARCH] = 21,
305 [HTTP_METHOD_UNCHECKOUT] = 20,
306 [HTTP_METHOD_UNLOCK] = 14,
307 [HTTP_METHOD_UPDATE] = 23,
308 [HTTP_METHOD_VERSION_CONTROL] = 17
309 };
310
311 return m >= 0 && m < (http_method_t)sizeof(ajp13_methods)
312 ? ajp13_methods[m]
313 : 0;
314
315 #else /*(array position is ajp13 method identifier byte)*/
316
317 static const uint8_t ajp13_methods[] = {
318 0,
319 HTTP_METHOD_OPTIONS,
320 HTTP_METHOD_GET,
321 HTTP_METHOD_HEAD,
322 HTTP_METHOD_POST,
323 HTTP_METHOD_PUT,
324 HTTP_METHOD_DELETE,
325 HTTP_METHOD_TRACE,
326 HTTP_METHOD_PROPFIND,
327 HTTP_METHOD_PROPPATCH,
328 HTTP_METHOD_MKCOL,
329 HTTP_METHOD_COPY,
330 HTTP_METHOD_MOVE,
331 HTTP_METHOD_LOCK,
332 HTTP_METHOD_UNLOCK,
333 HTTP_METHOD_ACL,
334 HTTP_METHOD_REPORT,
335 HTTP_METHOD_VERSION_CONTROL,
336 HTTP_METHOD_CHECKIN,
337 HTTP_METHOD_CHECKOUT,
338 HTTP_METHOD_UNCHECKOUT,
339 HTTP_METHOD_SEARCH,
340 HTTP_METHOD_MKWORKSPACE,
341 HTTP_METHOD_UPDATE,
342 HTTP_METHOD_LABEL,
343 HTTP_METHOD_MERGE,
344 HTTP_METHOD_BASELINE_CONTROL,
345 HTTP_METHOD_MKACTIVITY
346 };
347
348 uint8_t method;
349 for (method = 1; method < sizeof(ajp13_methods); ++method) {
350 if (ajp13_methods[method] == m) break;
351 }
352 return (method < sizeof(ajp13_methods)) ? method : 0;
353
354 #endif
355 }
356
357
358 static uint32_t
ajp13_enc_request_headers(uint8_t * const x,uint32_t n,const request_st * const r)359 ajp13_enc_request_headers (uint8_t * const x, uint32_t n, const request_st * const r)
360 {
361 const array * const rqst_headers = &r->rqst_headers;
362 const int add_content_length =
363 (!light_btst(r->rqst_htags, HTTP_HEADER_CONTENT_LENGTH));
364 /* num_headers */
365 n = ajp13_enc_uint16(x, n, rqst_headers->used + add_content_length);
366 if (0 == n) return n;
367 /* request_headers */
368 if (add_content_length) {
369 /* (gw_backend.c sends 411 Length Required if Content-Length not
370 * provided and request body is being streamed to backend. Add
371 * Content-Length if not provided and request body was collected.) */
372 n = ajp13_enc_uint16(x, n, 0xA008);
373 if (0 == n) return n;
374 char buf[LI_ITOSTRING_LENGTH];
375 n = ajp13_enc_string(x, n, buf,
376 li_itostrn(buf, sizeof(buf), r->reqbody_length));
377 if (0 == n) return n;
378 }
379 for (uint32_t i = 0, num = rqst_headers->used; i < num; ++i) {
380 const data_string * const ds = (data_string *)rqst_headers->data[i];
381 uint8_t code = 0x00;
382 switch (ds->ext) { /* map request header to ajp13 SC_REQ_* code */
383 case HTTP_HEADER_ACCEPT: code = 0x01; break;
384 case HTTP_HEADER_ACCEPT_ENCODING: code = 0x03; break;
385 case HTTP_HEADER_ACCEPT_LANGUAGE: code = 0x04; break;
386 case HTTP_HEADER_AUTHORIZATION: code = 0x05; break;
387 case HTTP_HEADER_CONNECTION: code = 0x06; break;
388 case HTTP_HEADER_CONTENT_TYPE: code = 0x07; break;
389 case HTTP_HEADER_CONTENT_LENGTH: code = 0x08; break;
390 case HTTP_HEADER_COOKIE: code = 0x09; break;
391 case HTTP_HEADER_HOST: code = 0x0B; break;
392 case HTTP_HEADER_PRAGMA: code = 0x0C; break;
393 case HTTP_HEADER_REFERER: code = 0x0D; break;
394 case HTTP_HEADER_USER_AGENT: code = 0x0E; break;
395 case HTTP_HEADER_OTHER:
396 if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Accept-Charset")))
397 code = 0x02;
398 else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Cookie2")))
399 code = 0x0A;
400 break;
401 default:
402 break;
403 }
404
405 n = (code)
406 ? ajp13_enc_uint16(x, n, 0xA000 | code)
407 : ajp13_enc_string(x, n, BUF_PTR_LEN(&ds->key));
408 if (0 == n) return n;
409 n = ajp13_enc_string(x, n, BUF_PTR_LEN(&ds->value));
410 if (0 == n) return n;
411 }
412 return n;
413 }
414
415
416 #if 0
417 static uint32_t
418 ajp13_enc_req_attribute (uint8_t * const x, uint32_t n, const char * const k, const uint32_t klen, const char * const v, const uint32_t vlen)
419 {
420 n = ajp13_enc_byte(x, n, 0x0A);
421 if (0 == n) return n;
422 n = ajp13_enc_string(x, n, k, klen);
423 if (0 == n) return n;
424 return ajp13_enc_string(x, n, v, vlen);
425 }
426 #endif
427
428
429 static uint32_t
ajp13_enc_attribute(uint8_t * const x,uint32_t n,const buffer * const b,uint8_t code)430 ajp13_enc_attribute (uint8_t * const x, uint32_t n, const buffer * const b, uint8_t code)
431 {
432 if (NULL == b) return n;
433 n = ajp13_enc_byte(x, n, code);
434 if (0 == n) return n;
435 return ajp13_enc_string(x, n, BUF_PTR_LEN(b));
436 }
437
438
439 static uint32_t
ajp13_enc_attributes(uint8_t * const x,uint32_t n,request_st * const r)440 ajp13_enc_attributes (uint8_t * const x, uint32_t n, request_st * const r)
441 {
442 const buffer *vb;
443
444 vb = http_header_env_get(r, CONST_STR_LEN("REMOTE_USER"));
445 n = ajp13_enc_attribute(x, n, vb, 0x03);
446 if (0 == n) return n;
447 vb = http_header_env_get(r, CONST_STR_LEN("AUTH_TYPE"));
448 n = ajp13_enc_attribute(x, n, vb, 0x04);
449 if (0 == n) return n;
450
451 if (!buffer_is_blank(&r->uri.query)) {
452 n = ajp13_enc_attribute(x, n, &r->uri.query, 0x05);
453 if (0 == n) return n;
454 }
455
456 if (buffer_is_equal_string(&r->uri.scheme, CONST_STR_LEN("https"))) {
457 /* XXX: might have config to avoid this overhead if not needed */
458
459 r->con->srv->request_env(r);
460
461 vb = http_header_env_get(r, CONST_STR_LEN("SSL_CLIENT_CERT"));
462 n = ajp13_enc_attribute(x, n, vb, 0x07);
463 if (0 == n) return n;
464 vb = http_header_env_get(r, CONST_STR_LEN("SSL_CIPHER"));
465 n = ajp13_enc_attribute(x, n, vb, 0x08);
466 if (0 == n) return n;
467 vb = http_header_env_get(r, CONST_STR_LEN("SSL_CIPHER_USE_KEYSIZE"));
468 n = ajp13_enc_attribute(x, n, vb, 0x0B);
469 if (0 == n) return n;
470 }
471
472 #if 0
473 /* req_attribute */ /*(what is often included by convention?)*/
474 n = ajp13_enc_req_attribute(x, n, CONST_STR_LEN("REDIRECT_URI"),
475 BUF_PTR_LEN(&r->target_orig));
476 if (0 == n) return n;
477 if (!buffer_is_equal(&r->target, &r->target_orig)) {
478 n = ajp13_enc_req_attribute(x, n, CONST_STR_LEN("REDIRECT_URI"),
479 BUF_PTR_LEN(&r->target));
480 if (0 == n) return n;
481 }
482 /* Note: if this is extended to pass all env; must not pass HTTP_PROXY */
483 #endif
484
485 #if 1 /*(experimental) (???) (XXX: create separate config option?)*/
486 /*(use mod_setenv to set value)*/
487 vb = http_header_env_get(r, CONST_STR_LEN("AJP13_SECRET"));
488 n = ajp13_enc_attribute(x, n, vb, 0x0C);
489 if (0 == n) return n;
490 #endif
491
492 return n;
493 }
494
495
496 static uint32_t
ajp13_enc_server_name(uint8_t * const x,const uint32_t n,const request_st * const r)497 ajp13_enc_server_name (uint8_t * const x, const uint32_t n, const request_st * const r)
498 {
499 #if 0
500 const data_string * const ds =
501 array_get_element_klen(cgienv, CONST_STR_LEN("SERVER_NAME"));
502 return (ds)
503 ? ajp13_enc_string(x, n, BUF_PTR_LEN(&ds->value))
504 : ajp13_enc_string(x, n, NULL, 0);
505 #else
506 /* copied and modified from http_cgi.c:http_cgi_headers() */
507 uint32_t len = buffer_clen(r->server_name);
508 if (len) {
509 const char * const ptr = r->server_name->ptr;
510 if (ptr[0] == '[') {
511 const char *colon = strstr(ptr, "]:");
512 if (colon) len = (colon + 1) - ptr;
513 }
514 else {
515 const char *colon = strchr(ptr, ':');
516 if (colon) len = colon - ptr;
517 }
518 return ajp13_enc_string(x, n, ptr, len);
519 }
520 else {
521 /* SERVER_ADDR is generated in http_cgi_headers()
522 * if the listen addr is, for example, a wildcard addr.
523 * XXX: For now, just send an empty string in this case
524 * instead of duplicating that code */
525 return ajp13_enc_string(x, n, NULL, 0);
526 }
527 #endif
528 }
529
530
531 #if 0
532 static int
533 ajp13_env_add (void *venv, const char *k, size_t klen, const char *v, size_t vlen)
534 {
535 /*(might be more efficient to store list rather than lighttpd array)*/
536 array_set_key_value((array *)venv, k, klen, v, vlen);
537 return 0;
538 }
539 #endif
540
541
542 static handler_t
ajp13_create_env(handler_ctx * const hctx)543 ajp13_create_env (handler_ctx * const hctx)
544 {
545 request_st * const r = hctx->r;
546 /* AJP13_MAX_PACKET_SIZE currently matches default 8k chunk_buf_sz */
547 buffer * const b =
548 chunkqueue_prepend_buffer_open_sz(&hctx->wb, AJP13_MAX_PACKET_SIZE);
549
550 #if 0 /*(elide if used only for SERVER_NAME, as is current case)*/
551 /* Note: while it might be slightly more efficient to special-case ajp13
552 * request creation here (reduce string copy), it is not worth duplicating
553 * the logic centralized in http-header-glue.c:http_cgi_headers() */
554 array * const cgienv = array_init(64);
555 #endif
556
557 do {
558 #if 0
559 #if 0 /* XXX: potential future extension */
560 gw_host * const host = hctx->host;
561 http_cgi_opts opts = {
562 (hctx->gw_mode == FCGI_AUTHORIZER),
563 host->break_scriptfilename_for_php,
564 host->docroot,
565 host->strip_request_uri
566 };
567 #else
568 http_cgi_opts opts = { 0, 0, NULL, NULL };
569 #endif
570 if (0 != http_cgi_headers(r, &opts, ajp13_env_add, cgienv)) break;
571 #endif
572
573 uint32_t n = 6;
574 uint8_t * const x = (uint8_t *)b->ptr;
575
576 x[0] = 0x12;
577 x[1] = 0x34;
578 x[2] = 0;
579 x[3] = 0;
580 x[4] = 0x02; /* JK_AJP13_FORWARD_REQUEST */
581 /* method */
582 const uint8_t method_byte = ajp13_method_byte(r->http_method);
583 if (0 == method_byte) break;
584 x[5] = method_byte;
585 /* protocol */
586 const char * const proto = get_http_version_name(r->http_version);
587 n = ajp13_enc_string(x, n, proto, strlen(proto));
588 if (0 == n) break;
589 /* req_uri */
590 n = ajp13_enc_string(x, n, BUF_PTR_LEN(&r->uri.path));
591 if (0 == n) break;
592 /* remote_addr */
593 n = ajp13_enc_string(x, n, BUF_PTR_LEN(r->dst_addr_buf));
594 if (0 == n) break;
595 /* remote_host *//*(skip DNS lookup)*/
596 n = ajp13_enc_string(x, n, NULL, 0);
597 if (0 == n) break;
598 /* server_name */
599 n = ajp13_enc_server_name(x, n, r);
600 if (0 == n) break;
601 /* server_port */
602 unsigned short port = sock_addr_get_port(&r->con->srv_socket->addr);
603 n = ajp13_enc_uint16(x, n, port);
604 if (0 == n) break;
605 /* is_ssl */
606 n = ajp13_enc_byte(x,n,buffer_is_equal_string(&r->uri.scheme,
607 CONST_STR_LEN("https")));
608 if (0 == n) break;
609 /* num_headers */
610 /* request_headers */
611 n = ajp13_enc_request_headers(x, n, r);
612 if (0 == n) break;
613 /* attributes */
614 n = ajp13_enc_attributes(x, n, r);
615 if (0 == n) break;
616 /* request_terminator */
617 n = ajp13_enc_byte(x, n, 0xFF);
618 if (0 == n) break;
619 /* payload length (overwrite in header) */
620 ajp13_enc_uint16_nc(x+2, n-4);
621
622 #if 0
623 array_free(cgienv);
624 #endif
625
626 /* (buffer is reallocated only if n is exactly AJP13_MAX_PACKET_SIZE) */
627 /* (could check for one-off; limit to 8k-1 to avoid resizing buffer) */
628 buffer_extend(b, n);/*(buffer_commit but extend +1 for '\0' as needed)*/
629 chunkqueue_prepend_buffer_commit(&hctx->wb);
630 hctx->wb_reqlen = (off_t)n;
631
632 if (r->reqbody_length) {
633 /*chunkqueue_append_chunkqueue(&hctx->wb, &r->reqbody_queue);*/
634 if (r->reqbody_length > 0)
635 hctx->wb_reqlen += r->reqbody_length;
636 /* (eventual) (minimal) total request size, not necessarily
637 * including all ajp13 framing around content length yet */
638 else /* as-yet-unknown total rqst sz (Transfer-Encoding: chunked)*/
639 hctx->wb_reqlen = -hctx->wb_reqlen;
640 }
641 /* send single data packet, then wait for Get Body Chunk from backend */
642 ajp13_stdin_append_n(hctx, AJP13_MAX_PACKET_SIZE-4);
643 hctx->request_id = 0; /* overloaded value; see ajp13_stdin_append_n() */
644
645 plugin_stats_inc("ajp13.requests");
646 return HANDLER_GO_ON;
647 } while (0);
648
649 #if 0
650 array_free(cgienv);
651 #endif
652
653 r->http_status = 400;
654 r->handler_module = NULL;
655 buffer_clear(b);
656 chunkqueue_remove_finished_chunks(&hctx->wb);
657 return HANDLER_FINISHED;
658 }
659
660
661 static void
ajp13_expand_headers(buffer * const b,handler_ctx * const hctx,uint32_t plen)662 ajp13_expand_headers (buffer * const b, handler_ctx * const hctx, uint32_t plen)
663 {
664 /* hctx->rb must contain at least plen content
665 * and all chunks expected to be MEM_CHUNK */
666 chunkqueue_compact_mem(hctx->rb, plen);
667
668 /* expect all headers in single AJP13 packet;
669 * not handling multiple AJP13_SEND_HEADERS packets
670 * (expecting single MEM_CHUNK <= 8k with AJP13 headers) */
671
672 chunk * const c = hctx->rb->first;
673 uint8_t *ptr =
674 (uint8_t *)c->mem->ptr + c->offset + 5; /* +5 for (4 hdr + 1 type) */
675 plen -= 5;
676
677 /* expand headers into buffer to be parsed by common code for responses
678 * (parsing might be slightly faster if AJP13-specific, but then would have
679 * to duplicate all http_response_parse_headers() policy)*/
680
681 do {
682 uint32_t len;
683 if (plen < 2) break;
684 plen -= 2;
685 buffer_append_string_len(b, CONST_STR_LEN("HTTP/1.1 "));
686 buffer_append_int(b, ajp13_dec_uint16(ptr));
687 ptr += 2;
688
689 if (plen < 2) break;
690 plen -= 2;
691 len = ajp13_dec_uint16(ptr);
692 ptr += 2;
693 if (plen < len+1) break;
694 plen -= len+1; /* include -1 for ending '\0' */
695 buffer_append_char(b, ' ');
696 if (len) buffer_append_string_len(b, (char *)ptr, len);
697 ptr += len+1;
698
699 if (plen < 2) break;
700 plen -= 2;
701 ptr += 2;
702 for (uint32_t nhdrs = ajp13_dec_uint16(ptr); nhdrs; --nhdrs) {
703 if (plen < 2) break;
704 plen -= 2;
705 len = ajp13_dec_uint16(ptr);
706 ptr += 2;
707 if (len >= 0xA000) {
708 if (len == 0xA000 || len > 0xA00B) break;
709 static const struct {
710 const char *h;
711 uint32_t len;
712 } hcode[] = {
713 { CONST_STR_LEN("\nContent-Type: ") }
714 ,{ CONST_STR_LEN("\nContent-Language: ") }
715 ,{ CONST_STR_LEN("\nContent-Length: ") }
716 ,{ CONST_STR_LEN("\nDate: ") }
717 ,{ CONST_STR_LEN("\nLast-Modified: ") }
718 ,{ CONST_STR_LEN("\nLocation: ") }
719 ,{ CONST_STR_LEN("\nSet-Cookie: ") }
720 ,{ CONST_STR_LEN("\nSet-Cookie2: ") }
721 ,{ CONST_STR_LEN("\nServlet-Engine: ") }
722 ,{ CONST_STR_LEN("\nStatus: ") }
723 ,{ CONST_STR_LEN("\nWWW-Authenticate: ") }
724 };
725 const uint32_t idx = (len & 0xF) - 1;
726 buffer_append_string_len(b, hcode[idx].h, hcode[idx].len);
727 }
728 else {
729 if (plen < len+1) break;
730 plen -= len+1;
731 buffer_append_str3(b, CONST_STR_LEN("\n"),
732 (char *)ptr, len,
733 CONST_STR_LEN(": "));
734 ptr += len+1;
735 }
736
737 if (plen < 2) break;
738 plen -= 2;
739 len = ajp13_dec_uint16(ptr);
740 ptr += 2;
741 if (plen < len+1) break;
742 plen -= len+1;
743 buffer_append_string_len(b, (char *)ptr, len);
744 ptr += len+1;
745 }
746 } while (0);
747
748 buffer_append_string_len(b, CONST_STR_LEN("\n\n"));
749 }
750
751
752 enum {
753 AJP13_FORWARD_REQUEST = 2
754 ,AJP13_SEND_BODY_CHUNK = 3
755 ,AJP13_SEND_HEADERS = 4
756 ,AJP13_END_RESPONSE = 5
757 ,AJP13_GET_BODY_CHUNK = 6
758 ,AJP13_SHUTDOWN = 7
759 ,AJP13_PING = 8
760 ,AJP13_CPONG_REPLY = 9
761 ,AJP13_CPING = 10
762 };
763
764
765 __attribute_cold__
766 static handler_t
ajp13_recv_0(const request_st * const r,const handler_ctx * const hctx)767 ajp13_recv_0(const request_st * const r, const handler_ctx * const hctx)
768 {
769 if (-1 == hctx->request_id) /*(flag request ended)*/
770 return HANDLER_FINISHED;
771 if (!(fdevent_fdnode_interest(hctx->fdn) & FDEVENT_IN)
772 && !(r->conf.stream_response_body
773 & FDEVENT_STREAM_RESPONSE_POLLRDHUP))
774 return HANDLER_GO_ON;
775 log_error(r->conf.errh, __FILE__, __LINE__,
776 "unexpected end-of-file (perhaps the ajp13 process died):"
777 "pid: %d socket: %s",
778 hctx->proc->pid, hctx->proc->connection_name->ptr);
779
780 return HANDLER_ERROR;
781 }
782
783
784 static handler_t
ajp13_recv_parse_loop(request_st * const r,handler_ctx * const hctx)785 ajp13_recv_parse_loop (request_st * const r, handler_ctx * const hctx)
786 {
787 log_error_st * const errh = r->conf.errh;
788 int fin = 0;
789 do {
790 uint8_t header[7];
791 const off_t rblen = chunkqueue_length(hctx->rb);
792 if (rblen < 5)
793 break; /* incomplete packet header + min response payload */
794 char *ptr = (char *)&header;
795 uint32_t pklen = 5;
796 if (chunkqueue_peek_data(hctx->rb, &ptr, &pklen, errh) < 0)
797 break;
798 if (pklen != 5)
799 break;
800 if (ptr[0] != 'A' || ptr[1] != 'B') {
801 log_error(errh, __FILE__, __LINE__,
802 "invalid packet prefix sent from container:"
803 "pid: %d socket: %s",
804 hctx->proc->pid, hctx->proc->connection_name->ptr);
805 return HANDLER_ERROR;
806 }
807 uint32_t plen = ajp13_dec_uint16((uint8_t *)ptr+2);
808 if (plen > (unsigned int)rblen - 4)
809 break; /* incomplete packet */
810
811 switch(ptr[4]) {
812 case AJP13_SEND_HEADERS:
813 if (0 == r->resp_body_started) {
814 if (plen < 3) {
815 log_error(errh, __FILE__, __LINE__,
816 "AJP13: headers packet received with invalid length");
817 return HANDLER_FINISHED;
818 }
819
820 buffer *hdrs = hctx->response;
821 if (NULL == hdrs) {
822 hdrs = r->tmp_buf;
823 buffer_clear(hdrs);
824 }
825
826 ajp13_expand_headers(hdrs, hctx, 4 + plen);
827
828 if (HANDLER_GO_ON !=
829 http_response_parse_headers(r, &hctx->opts, hdrs)) {
830 hctx->send_content_body = 0;
831 return HANDLER_FINISHED;
832 }
833 if (0 == r->resp_body_started) {
834 if (!hctx->response) {
835 hctx->response = chunk_buffer_acquire();
836 buffer_copy_buffer(hctx->response, hdrs);
837 }
838 }
839 else if (hctx->gw_mode == GW_AUTHORIZER &&
840 (r->http_status == 0 || r->http_status == 200)) {
841 /* authorizer approved request; ignore the content here */
842 hctx->send_content_body = 0;
843 hctx->opts.authorizer |= /*(save response streaming flags)*/
844 (r->conf.stream_response_body
845 & (FDEVENT_STREAM_RESPONSE
846 |FDEVENT_STREAM_RESPONSE_BUFMIN)) << 1;
847 r->conf.stream_response_body &=
848 ~(FDEVENT_STREAM_RESPONSE|FDEVENT_STREAM_RESPONSE_BUFMIN);
849 }
850 #if 0
851 else if ((r->conf.stream_response_body &
852 (FDEVENT_STREAM_RESPONSE|FDEVENT_STREAM_RESPONSE_BUFMIN))
853 && ( r->http_status == 204
854 || r->http_status == 205
855 || r->http_status == 304
856 || r->http_method == HTTP_METHOD_HEAD)) {
857 /* disable streaming to wait for backend protocol to signal
858 * end of response (prevent http_response_write_prepare()
859 * from short-circuiting and finishing responses without
860 * response body) */
861 r->conf.stream_response_body &=
862 ~(FDEVENT_STREAM_RESPONSE|FDEVENT_STREAM_RESPONSE_BUFMIN);
863 }
864 #endif
865 }
866 else {
867 log_error(errh, __FILE__, __LINE__,
868 "AJP13: headers received after body started");
869 /* ignore; discard packet */
870 }
871 break;
872 case AJP13_SEND_BODY_CHUNK:
873 if (0 == r->resp_body_started) { /* header not finished */
874 log_error(errh, __FILE__, __LINE__,
875 "AJP13: body received before headers");
876 return HANDLER_FINISHED;
877 }
878 else if (hctx->send_content_body) {
879 ptr = (char *)&header;
880 pklen = 7;
881 if (chunkqueue_peek_data(hctx->rb, &ptr, &pklen, errh) < 0)
882 return HANDLER_GO_ON;
883 if (pklen != 7)
884 return HANDLER_GO_ON;
885 uint32_t len = ajp13_dec_uint16((uint8_t *)ptr+5);
886 if (0 == len) break; /*(skip "flush" packet of 0-length data)*/
887 if (len > plen - 3) {
888 log_error(errh, __FILE__, __LINE__,
889 "AJP13: body packet received with invalid length");
890 return HANDLER_FINISHED;
891 }
892 chunkqueue_mark_written(hctx->rb, 7);
893 if (0 == http_response_transfer_cqlen(r, hctx->rb, len)) {
894 if (len != plen - 3)
895 chunkqueue_mark_written(hctx->rb, plen - 3 - len);
896 continue;
897 }
898 else {
899 /* error writing to tempfile;
900 * truncate response or send 500 if nothing sent yet */
901 hctx->send_content_body = 0;
902 return HANDLER_FINISHED;
903 }
904 }
905 else {
906 /* ignore; discard packet */
907 }
908 break;
909 case AJP13_GET_BODY_CHUNK:
910 /*assert(3 == plen);*/
911 ptr = (char *)&header;
912 pklen = 7;
913 if (chunkqueue_peek_data(hctx->rb, &ptr, &pklen, errh) < 0)
914 return HANDLER_GO_ON;
915 if (pklen != 7)
916 return HANDLER_GO_ON;
917 ajp13_stdin_append_n(hctx, ajp13_dec_uint16((uint8_t *)ptr+5));
918 break;
919 case AJP13_END_RESPONSE:
920 /*assert(2 == plen);*/
921 #if 0
922 ptr = (char *)&header;
923 pklen = 6;
924 if (chunkqueue_peek_data(hctx->rb, &ptr, &pklen, errh) < 0)
925 return HANDLER_GO_ON;
926 if (pklen != 6)
927 return HANDLER_GO_ON;
928 if (ptr[5]) {
929 /* future: add connection to pool if 'reuse' flag is set */
930 }
931 #endif
932 hctx->request_id = -1; /*(flag request ended)*/
933 fin = 1;
934 break;
935 case AJP13_CPONG_REPLY:
936 /*assert(1 == plen);*/
937 break;
938 default:
939 log_error(errh, __FILE__, __LINE__,
940 "AJP13: packet type not handled: %d", ptr[4]);
941 /* discard packet */
942 break;
943 }
944
945 chunkqueue_mark_written(hctx->rb, 4 + plen);
946 } while (0 == fin);
947
948 return 0 == fin ? HANDLER_GO_ON : HANDLER_FINISHED;
949 }
950
951
952 static handler_t
ajp13_recv_parse(request_st * const r,struct http_response_opts_t * const opts,buffer * const b,size_t n)953 ajp13_recv_parse (request_st * const r, struct http_response_opts_t * const opts, buffer * const b, size_t n)
954 {
955 handler_ctx * const hctx = (handler_ctx *)opts->pdata;
956 if (0 == n) return ajp13_recv_0(r, hctx);
957 /* future: might try to elide copying if buffer contains full packet(s)
958 * and prior read did not end in a partial packet */
959 chunkqueue_append_buffer(hctx->rb, b);
960 return ajp13_recv_parse_loop(r, hctx);
961 }
962
963
964 static handler_t
ajp13_check_extension(request_st * const r,void * p_d)965 ajp13_check_extension (request_st * const r, void *p_d)
966 {
967 if (NULL != r->handler_module) return HANDLER_GO_ON;
968
969 plugin_data * const p = p_d;
970 mod_ajp13_patch_config(r, p);
971 if (NULL == p->conf.exts) return HANDLER_GO_ON;
972
973 handler_t rc = gw_check_extension(r, p, 1, 0);
974 if (HANDLER_GO_ON != rc) return rc;
975
976 if (r->handler_module == p->self) {
977 handler_ctx *hctx = r->plugin_ctx[p->id];
978 hctx->opts.backend = BACKEND_AJP13;
979 hctx->opts.parse = ajp13_recv_parse;
980 hctx->opts.pdata = hctx;
981 hctx->stdin_append = ajp13_stdin_append;
982 hctx->create_env = ajp13_create_env;
983 if (!hctx->rb)
984 hctx->rb = chunkqueue_init(NULL);
985 else
986 chunkqueue_reset(hctx->rb);
987 }
988
989 return HANDLER_GO_ON;
990 }
991
992
993 __attribute_cold__
994 int mod_ajp13_plugin_init (plugin *p);
mod_ajp13_plugin_init(plugin * p)995 int mod_ajp13_plugin_init (plugin *p)
996 {
997 p->version = LIGHTTPD_VERSION_ID;
998 p->name = "ajp13";
999
1000 p->init = gw_init;
1001 p->cleanup = gw_free;
1002 p->set_defaults = mod_ajp13_set_defaults;
1003 p->handle_request_reset = gw_handle_request_reset;
1004 p->handle_uri_clean = ajp13_check_extension;
1005 p->handle_subrequest = gw_handle_subrequest;
1006 p->handle_trigger = gw_handle_trigger;
1007 p->handle_waitpid = gw_handle_waitpid_cb;
1008
1009 return 0;
1010 }
1011