xref: /lighttpd1.4/src/mod_ajp13.c (revision 3a8fc4bc)
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