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