1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 /***************************************************************************
19  * Description: Apache 2 plugin for Tomcat                                 *
20  * Author:      Gal Shachor <shachor@il.ibm.com>                           *
21  *              Henri Gomez <hgomez@apache.org>                            *
22  ***************************************************************************/
23 
24 /*
25  * mod_jk: keeps all servlet related ramblings together.
26  */
27 
28 #include "ap_config.h"
29 #include "apr_lib.h"
30 #include "apr_date.h"
31 #include "apr_file_info.h"
32 #include "apr_file_io.h"
33 #include "httpd.h"
34 #include "http_config.h"
35 #include "http_request.h"
36 #include "http_core.h"
37 #include "http_protocol.h"
38 #include "http_main.h"
39 #include "http_log.h"
40 #include "util_script.h"
41 #include "ap_mpm.h"
42 
43 #if defined(AS400) && !defined(AS400_UTF8)
44 #include "ap_charset.h"
45 #include "util_charset.h"       /* ap_hdrs_from_ascii */
46 #endif
47 
48 /* deprecated with apr 0.9.3 */
49 
50 #include "apr_version.h"
51 #if (APR_MAJOR_VERSION == 0) && \
52     (APR_MINOR_VERSION <= 9) && \
53     (APR_PATCH_VERSION < 3)
54 #define apr_filepath_name_get apr_filename_of_pathname
55 #endif
56 
57 #include "apr_strings.h"
58 
59 /* Yes; sorta sucks - with luck we will clean this up before httpd-2.2
60  * ships, leaving AP_NEED_SET_MUTEX_PERMS def'd as 1 or 0 on all platforms.
61  */
62 #ifdef AP_NEED_SET_MUTEX_PERMS
63 # define JK_NEED_SET_MUTEX_PERMS AP_NEED_SET_MUTEX_PERMS
64 #else
65   /* A special case for httpd-2.0 */
66 # if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(AS400)
67 #  define JK_NEED_SET_MUTEX_PERMS 1
68 # else
69 #  define JK_NEED_SET_MUTEX_PERMS 0
70 # endif
71 #endif
72 
73 #if JK_NEED_SET_MUTEX_PERMS
74 #include "unixd.h"      /* for unixd_set_global_mutex_perms */
75 #endif
76 /*
77  * jk_ include files
78  */
79 #include "jk_global.h"
80 #include "jk_ajp13.h"
81 #include "jk_logger.h"
82 #include "jk_map.h"
83 #include "jk_pool.h"
84 #include "jk_service.h"
85 #include "jk_uri_worker_map.h"
86 #include "jk_util.h"
87 #include "jk_worker.h"
88 #include "jk_shm.h"
89 #include "jk_url.h"
90 
91 #define JK_LOG_DEF_FILE             ("logs/mod_jk.log")
92 #define JK_SHM_DEF_FILE             ("logs/jk-runtime-status")
93 #define JK_ENV_REMOTE_ADDR          ("JK_REMOTE_ADDR")
94 #define JK_ENV_REMOTE_PORT          ("JK_REMOTE_PORT")
95 #define JK_ENV_REMOTE_HOST          ("JK_REMOTE_HOST")
96 #define JK_ENV_REMOTE_USER          ("JK_REMOTE_USER")
97 #define JK_ENV_AUTH_TYPE            ("JK_AUTH_TYPE")
98 #define JK_ENV_LOCAL_NAME           ("JK_LOCAL_NAME")
99 #define JK_ENV_LOCAL_ADDR           ("JK_LOCAL_ADDR")
100 #define JK_ENV_LOCAL_PORT           ("JK_LOCAL_PORT")
101 #define JK_ENV_IGNORE_CL            ("JK_IGNORE_CL")
102 #define JK_ENV_HTTPS                ("HTTPS")
103 #define JK_ENV_SSL_PROTOCOL         ("SSL_PROTOCOL")
104 #define JK_ENV_CERTS                ("SSL_CLIENT_CERT")
105 #define JK_ENV_CIPHER               ("SSL_CIPHER")
106 #define JK_ENV_SESSION              ("SSL_SESSION_ID")
107 #define JK_ENV_KEY_SIZE             ("SSL_CIPHER_USEKEYSIZE")
108 #define JK_ENV_CERTCHAIN_PREFIX     ("SSL_CLIENT_CERT_CHAIN_")
109 #define JK_ENV_REPLY_TIMEOUT        ("JK_REPLY_TIMEOUT")
110 #define JK_ENV_STICKY_IGNORE        ("JK_STICKY_IGNORE")
111 #define JK_ENV_STATELESS            ("JK_STATELESS")
112 #define JK_ENV_ROUTE                ("JK_ROUTE")
113 #define JK_ENV_WORKER_NAME          ("JK_WORKER_NAME")
114 #define JK_NOTE_WORKER_NAME         ("JK_WORKER_NAME")
115 #define JK_NOTE_WORKER_TYPE         ("JK_WORKER_TYPE")
116 #define JK_NOTE_REQUEST_DURATION    ("JK_REQUEST_DURATION")
117 #define JK_NOTE_WORKER_ROUTE        ("JK_WORKER_ROUTE")
118 #define JK_HANDLER          ("jakarta-servlet")
119 #define JK_MAGIC_TYPE       ("application/x-jakarta-servlet")
120 #define NULL_FOR_EMPTY(x)   ((x && !strlen(x)) ? NULL : x)
121 #define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)")
122 #define JK_LOG_LOCK_KEY     ("jk_log_lock_key")
123 #define JKLOG_MARK          __FILE__,__LINE__
124 
125 /*
126  * If you are not using SSL, comment out the following line. It will make
127  * apache run faster.
128  *
129  * Personally, I (DM), think this may be a lie.
130  */
131 #define ADD_SSL_INFO
132 
133 /* Needed for Apache 2.3/2.4 per-module log config */
134 #ifdef APLOG_USE_MODULE
135 APLOG_USE_MODULE(jk);
136 #endif
137 
138 /* module MODULE_VAR_EXPORT jk_module; */
139 AP_MODULE_DECLARE_DATA module jk_module;
140 
141 /*
142  * Environment variable forward object
143  */
144 typedef struct
145 {
146     int has_default;
147     char *name;
148     char *value;
149 } envvar_item;
150 
151 /*
152  * Configuration object for the mod_jk module.
153  */
154 typedef struct
155 {
156 
157     /*
158      * Log stuff
159      */
160     char *log_file;
161     int log_level;
162     jk_logger_t *log;
163 
164     /*
165      * Mount stuff
166      */
167     char *mount_file;
168     int mount_file_reload;
169     jk_map_t *uri_to_context;
170 
171     int mountcopy;
172 
173     jk_uri_worker_map_t *uw_map;
174 
175     int was_initialized;
176 
177     /*
178      * Automatic context path apache alias
179      */
180     char *alias_dir;
181 
182     /*
183      * Request Logging
184      */
185 
186     char *stamp_format_string;
187     char *format_string;
188     apr_array_header_t *format;
189 
190     /*
191      * Setting target worker via environment
192      */
193     char *worker_indicator;
194 
195     /*
196      * Configurable environment variables to overwrite
197      * request information using meta data send by a
198      * proxy in front of us.
199      */
200     char *remote_addr_indicator;
201     char *remote_port_indicator;
202     char *remote_host_indicator;
203     char *remote_user_indicator;
204     char *auth_type_indicator;
205     char *local_name_indicator;
206     char *local_addr_indicator;
207     char *local_port_indicator;
208 
209     /*
210      * Configurable environment variable to force
211      * ignoring a request Content-Length header
212      * (useful to make mod_deflate request inflation
213      * compatible with mod_jk).
214      */
215     char *ignore_cl_indicator;
216 
217     /*
218      * SSL Support
219      */
220     int ssl_enable;
221     char *https_indicator;
222     char *ssl_protocol_indicator;
223     char *certs_indicator;
224     char *cipher_indicator;
225     char *session_indicator;    /* Servlet API 2.3 requirement */
226     char *key_size_indicator;   /* Servlet API 2.3 requirement */
227     char *certchain_prefix;     /* Client certificate chain prefix */
228 
229     /*
230      * Jk Options
231      */
232     int options;
233     int exclude_options;
234 
235     int strip_session;
236     char *strip_session_name;
237     /*
238      * Environment variables support
239      */
240     int envvars_has_own;
241     apr_table_t *envvars;
242     apr_table_t *envvars_def;
243     apr_array_header_t *envvar_items;
244 
245     server_rec *s;
246 } jk_server_conf_t;
247 
248 /*
249  * Request specific configuration
250  */
251 struct jk_request_conf
252 {
253     rule_extension_t *rule_extensions;
254     char *orig_uri;
255     int jk_handled;
256 };
257 
258 typedef struct jk_request_conf jk_request_conf_t;
259 
260 struct apache_private_data
261 {
262     jk_pool_t p;
263 
264     int read_body_started;
265     request_rec *r;
266 };
267 typedef struct apache_private_data apache_private_data_t;
268 
269 static server_rec *main_server = NULL;
270 static jk_logger_t *main_log = NULL;
271 static apr_hash_t *jk_log_fps = NULL;
272 static jk_worker_env_t worker_env;
273 static apr_global_mutex_t *jk_log_lock = NULL;
274 static char *jk_shm_file = NULL;
275 static int jk_shm_size = 0;
276 static int jk_shm_size_set = 0;
277 static volatile int jk_watchdog_interval = 0;
278 static volatile int jk_watchdog_running  = 0;
279 
280 /*
281  * Worker stuff
282 */
283 static jk_map_t *jk_worker_properties = NULL;
284 static char *jk_worker_file = NULL;
285 static int jk_mount_copy_all = JK_FALSE;
286 
287 static int JK_METHOD ws_start_response(jk_ws_service_t *s,
288                                        int status,
289                                        const char *reason,
290                                        const char *const *header_names,
291                                        const char *const *header_values,
292                                        unsigned num_of_headers);
293 
294 static int JK_METHOD ws_read(jk_ws_service_t *s,
295                              void *b, unsigned len, unsigned *actually_read);
296 
297 static int init_jk(apr_pool_t * pconf, jk_server_conf_t * conf,
298                     server_rec * s);
299 
300 static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned l);
301 
302 static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
303                                        const char *const *log_names,
304                                        const char *const *log_values,
305                                        unsigned num_of_log_items);
306 
307 static void * JK_METHOD ws_next_vhost(void *d);
308 
309 static void JK_METHOD ws_vhost_to_text(void *d, char *buf, size_t len);
310 
311 static jk_uri_worker_map_t * JK_METHOD ws_vhost_to_uw_map(void *d);
312 
313 /* ========================================================================= */
314 /* JK Service step callbacks                                                 */
315 /* ========================================================================= */
316 
ws_start_response(jk_ws_service_t * s,int status,const char * reason,const char * const * header_names,const char * const * header_values,unsigned num_of_headers)317 static int JK_METHOD ws_start_response(jk_ws_service_t *s,
318                                        int status,
319                                        const char *reason,
320                                        const char *const *header_names,
321                                        const char *const *header_values,
322                                        unsigned num_of_headers)
323 {
324     unsigned h;
325     apache_private_data_t *p = s->ws_private;
326     request_rec *r = p->r;
327 
328     /* If we use proxy error pages, still pass
329      * through context headers needed for special status codes.
330      */
331     if (s->extension.use_server_error_pages &&
332         status >= s->extension.use_server_error_pages) {
333         if (status == HTTP_UNAUTHORIZED) {
334             int found = JK_FALSE;
335             for (h = 0; h < num_of_headers; h++) {
336                 if (!strcasecmp(header_names[h], "WWW-Authenticate")) {
337                     char *tmp = apr_pstrdup(r->pool, header_values[h]);
338                     apr_table_set(r->err_headers_out,
339                                   "WWW-Authenticate", tmp);
340                     found = JK_TRUE;
341                 }
342             }
343             if (found == JK_FALSE) {
344                 jk_server_conf_t *xconf = (jk_server_conf_t *)
345                                            ap_get_module_config(r->server->module_config,
346                                                                 &jk_module);
347                 jk_log(xconf->log, JK_LOG_INFO,
348                        "origin server sent 401 without"
349                        " WWW-Authenticate header");
350             }
351         }
352         return JK_TRUE;
353     }
354 
355     /* If there is no reason given (or an empty one),
356      * we'll try to guess a good one.
357      */
358     if (!reason || *reason == '\0') {
359         /* We ask Apache httpd about a good reason phrase. */
360         reason = ap_get_status_line(status);
361         /* Unfortunately it returns with a 500 reason phrase,
362          * whenever it does not know about the given status code,
363          * e.g. in the case of custom status codes.
364          */
365         if (status != 500 && !strncmp(reason, "500 ", 4)) {
366             reason = "Unknown Reason";
367         }
368         else {
369             /* Apache httpd returns a full status line,
370              * but we only want a reason phrase, so skip
371              * the prepended status code.
372              */
373             reason = reason + 4;
374         }
375     }
376     r->status = status;
377     r->status_line = apr_psprintf(r->pool, "%d %s", status, reason);
378 
379     for (h = 0; h < num_of_headers; h++) {
380         if (!strcasecmp(header_names[h], "Content-type")) {
381             char *tmp = apr_pstrdup(r->pool, header_values[h]);
382             ap_content_type_tolower(tmp);
383             /* It should be done like this in Apache 2.0 */
384             /* This way, Apache 2.0 will be able to set the output filter */
385             /* and it make jk usable with deflate using */
386             /* AddOutputFilterByType DEFLATE text/html */
387             ap_set_content_type(r, tmp);
388         }
389         else if (!strcasecmp(header_names[h], "Location")) {
390 #if defined(AS400) && !defined(AS400_UTF8)
391             /* Fix escapes in Location Header URL */
392             ap_fixup_escapes((char *)header_values[h],
393                              strlen(header_values[h]), ap_hdrs_from_ascii);
394 #endif
395             apr_table_set(r->headers_out, header_names[h], header_values[h]);
396         }
397         else if (!strcasecmp(header_names[h], "Content-Length")) {
398             ap_set_content_length(r, apr_atoi64(header_values[h]));
399         }
400         else if (!strcasecmp(header_names[h], "Transfer-Encoding")) {
401             apr_table_set(r->headers_out, header_names[h], header_values[h]);
402         }
403         else if (!strcasecmp(header_names[h], "Last-Modified")) {
404             /*
405              * If the script gave us a Last-Modified header, we can't just
406              * pass it on blindly because of restrictions on future values.
407              */
408             ap_update_mtime(r, apr_date_parse_http(header_values[h]));
409             ap_set_last_modified(r);
410         }
411         else {
412             apr_table_add(r->headers_out, header_names[h], header_values[h]);
413         }
414     }
415 
416     /* this NOP function was removed in apache 2.0 alpha14 */
417     /* ap_send_http_header(r); */
418     s->response_started = JK_TRUE;
419 
420     return JK_TRUE;
421 }
422 
423 /*
424  * Read a chunk of the request body into a buffer.  Attempt to read len
425  * bytes into the buffer.  Write the number of bytes actually read into
426  * actually_read.
427  *
428  * Think of this function as a method of the apache1.3-specific subclass of
429  * the jk_ws_service class.  Think of the *s param as a "this" or "self"
430  * pointer.
431  */
ws_read(jk_ws_service_t * s,void * b,unsigned len,unsigned * actually_read)432 static int JK_METHOD ws_read(jk_ws_service_t *s,
433                              void *b, unsigned len, unsigned *actually_read)
434 {
435     if (s && s->ws_private && b && actually_read) {
436         apache_private_data_t *p = s->ws_private;
437         if (!p->read_body_started) {
438             if (ap_should_client_block(p->r)) {
439                 p->read_body_started = JK_TRUE;
440             }
441         }
442 
443         if (p->read_body_started) {
444 #if defined(AS400) && !defined(AS400_UTF8)
445             int long rv = OK;
446             if (rv = ap_change_request_body_xlate(p->r, 65535, 65535)) {        /* turn off request body translation */
447                 ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT, 0, NULL,
448                              "mod_jk: Error on ap_change_request_body_xlate, rc=%d",
449                              rv);
450                 return JK_FALSE;
451             }
452 #else
453             long rv;
454 #endif
455 
456             if ((rv = ap_get_client_block(p->r, b, len)) < 0) {
457                 return JK_FALSE;
458             }
459             else {
460                 *actually_read = (unsigned)rv;
461             }
462             return JK_TRUE;
463         }
464     }
465     return JK_FALSE;
466 }
467 
ws_flush(jk_ws_service_t * s)468 static void JK_METHOD ws_flush(jk_ws_service_t *s)
469 {
470 #if ! (defined(AS400) && !defined(AS400_UTF8))
471     if (s && s->ws_private) {
472         apache_private_data_t *p = s->ws_private;
473         ap_rflush(p->r);
474     }
475 #endif
476 }
477 
ws_done(jk_ws_service_t * s)478 static void JK_METHOD ws_done(jk_ws_service_t *s)
479 {
480 #if ! (defined(AS400) && !defined(AS400_UTF8))
481     if (s && s->ws_private) {
482         apache_private_data_t *p = s->ws_private;
483         ap_finalize_request_protocol(p->r);
484     }
485 #endif
486 }
487 
488 /*
489  * Write a chunk of response data back to the browser.  If the headers
490  * haven't yet been sent over, send over default header values (Status =
491  * 200, basically).
492  *
493  * Write len bytes from buffer b.
494  *
495  * Think of this function as a method of the apache1.3-specific subclass of
496  * the jk_ws_service class.  Think of the *s param as a "this" or "self"
497  * pointer.
498  */
499 
ws_write(jk_ws_service_t * s,const void * b,unsigned int l)500 static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned int l)
501 {
502 #if defined(AS400) && !defined(AS400_UTF8)
503     int rc;
504 #endif
505 
506     if (s && s->ws_private && b) {
507         apache_private_data_t *p = s->ws_private;
508 
509         if (l) {
510             /* BUFF *bf = p->r->connection->client; */
511             int r = 0;
512             int ll = l;
513             const char *bb = (const char *)b;
514 
515             if (!s->response_started) {
516                 if (main_log)
517                     jk_log(main_log, JK_LOG_INFO,
518                            "Write without start, starting with defaults");
519                 if (!s->start_response(s, 200, NULL, NULL, NULL, 0)) {
520                     return JK_FALSE;
521                 }
522             }
523             if (p->r->header_only) {
524 #if ! (defined(AS400) && !defined(AS400_UTF8))
525                 ap_rflush(p->r);
526 #endif
527                 return JK_TRUE;
528             }
529 #if defined(AS400) && !defined(AS400_UTF8)
530             /* turn off response body translation */
531             rc = ap_change_response_body_xlate(p->r, 65535, 65535);
532             if (rc) {
533                 ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT, 0, NULL,
534                              "mod_jk: Error on ap_change_response_body_xlate, rc=%d",
535                              rc);
536                 return JK_FALSE;
537             }
538 #endif
539 
540             while (ll > 0 && !p->r->connection->aborted) {
541                 r = ap_rwrite(bb, ll, p->r);
542                 if (JK_IS_DEBUG_LEVEL(main_log))
543                     jk_log(main_log, JK_LOG_DEBUG,
544                            "written %d out of %d", r, ll);
545 
546                 if (r < 0)
547                     return JK_FALSE;
548                 ll -= r;
549                 bb += r;
550             }
551             if (ll && p->r->connection->aborted) {
552                 /* Fail if there is something left to send and
553                  * the connection was aborted by the client
554                  */
555                 return JK_FALSE;
556             }
557         }
558 
559         return JK_TRUE;
560     }
561     return JK_FALSE;
562 }
563 
ws_add_log_items(jk_ws_service_t * s,const char * const * log_names,const char * const * log_values,unsigned num_of_log_items)564 static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
565                                        const char *const *log_names,
566                                        const char *const *log_values,
567                                        unsigned num_of_log_items)
568 {
569     unsigned h;
570     apache_private_data_t *p = s->ws_private;
571     request_rec *r = p->r;
572 
573     for (h = 0; h < num_of_log_items; h++) {
574         if (log_names[h] && log_values[h]) {
575             apr_table_set(r->notes, log_names[h], log_values[h]);
576         }
577     }
578 }
579 
ws_next_vhost(void * d)580 static void * JK_METHOD ws_next_vhost(void *d)
581 {
582     server_rec *s = (server_rec *)d;
583     if (s == NULL)
584         return main_server;
585     return s->next;
586 }
587 
ws_vhost_to_text(void * d,char * buf,size_t len)588 static void JK_METHOD ws_vhost_to_text(void *d, char *buf, size_t len)
589 {
590     server_rec *s = (server_rec *)d;
591     size_t used = 0;
592 
593     if (s->server_hostname) {
594         used += strlen(s->server_hostname);
595     }
596     if (!s->is_virtual) {
597         if (s->port)
598             used += strlen(":XXXXX");
599     }
600     else if (s->addrs) {
601         used += strlen(" [");
602         if (s->addrs->virthost)
603             used += strlen(s->addrs->virthost);
604         if (s->addrs->host_port)
605             used += strlen(":XXXXX");
606         used += strlen("]");
607     }
608 
609     if (len < used && len > strlen("XXX")) {
610         strcpy(buf, "XXX");
611         return;
612     }
613 
614     used = 0;
615 
616     if (s->server_hostname) {
617         strcpy(buf + used, s->server_hostname);
618         used += strlen(s->server_hostname);
619     }
620     if (!s->is_virtual) {
621         if (s->port) {
622             sprintf(buf + used, ":%hu", s->port);
623             used = strlen(buf);
624         }
625     }
626     else if (s->addrs) {
627         strcpy(buf + used, " [");
628         used += strlen(" [");
629         if (s->addrs->virthost) {
630             strcpy(buf + used, s->addrs->virthost);
631             used += strlen(s->addrs->virthost);
632         }
633         if (s->addrs->host_port) {
634             sprintf(buf + used, ":%hu", s->addrs->host_port);
635             used = strlen(buf);
636         }
637         strcpy(buf + used, "]");
638         used += strlen("]");
639     }
640 }
641 
ws_vhost_to_uw_map(void * d)642 static jk_uri_worker_map_t * JK_METHOD ws_vhost_to_uw_map(void *d)
643 {
644     server_rec *s = (server_rec *)d;
645     jk_server_conf_t *conf = NULL;
646     if (s == NULL)
647         return NULL;
648     conf = (jk_server_conf_t *) ap_get_module_config(s->module_config,
649                                                      &jk_module);
650     return conf->uw_map;
651 }
652 
653 /* ========================================================================= */
654 /* Utility functions                                                         */
655 /* ========================================================================= */
656 
dump_options(server_rec * srv,apr_pool_t * p)657 static void dump_options(server_rec *srv, apr_pool_t *p)
658 {
659     char server_name[80];
660     jk_server_conf_t *conf = (jk_server_conf_t *)ap_get_module_config(srv->module_config,
661                                                                       &jk_module);
662     int options = conf->options;
663     ws_vhost_to_text(srv, server_name, 80);
664     if (options & JK_OPT_FWDURICOMPAT)
665         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
666                "ForwardURICompat", server_name,
667                JK_OPT_DEFAULT & JK_OPT_FWDURICOMPAT ? " (default)" : "");
668     if (options & JK_OPT_FWDURICOMPATUNPARSED)
669         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
670                "ForwardURICompatUnparsed", server_name,
671                JK_OPT_DEFAULT & JK_OPT_FWDURICOMPATUNPARSED ? " (default)" : "");
672     if (options & JK_OPT_FWDURIESCAPED)
673         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
674                "ForwardURIEscaped", server_name,
675                JK_OPT_DEFAULT & JK_OPT_FWDURIESCAPED ? " (default)" : "");
676     if (options & JK_OPT_FWDURIPROXY)
677         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
678                "ForwardURIProxy", server_name,
679                JK_OPT_DEFAULT & JK_OPT_FWDURIPROXY ? " (default)" : "");
680     if (options & JK_OPT_FWDDIRS)
681         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
682                "ForwardDirectories", server_name,
683                JK_OPT_DEFAULT & JK_OPT_FWDDIRS ? " (default)" : "");
684     if (options & JK_OPT_FWDLOCAL)
685         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
686                "ForwardLocalAddress", server_name,
687                JK_OPT_DEFAULT & JK_OPT_FWDLOCAL ? " (default)" : "");
688     if (options & JK_OPT_FWDPHYSICAL)
689         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
690                "ForwardPhysicalAddress", server_name,
691                JK_OPT_DEFAULT & JK_OPT_FWDPHYSICAL ? " (default)" : "");
692     if (options & JK_OPT_FWDCERTCHAIN)
693         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
694                "ForwardSSLCertChain", server_name,
695                JK_OPT_DEFAULT & JK_OPT_FWDCERTCHAIN ? " (default)" : "");
696     if (options & JK_OPT_FWDKEYSIZE)
697         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
698                "ForwardKeySize", server_name,
699                JK_OPT_DEFAULT & JK_OPT_FWDKEYSIZE ? " (default)" : "");
700     if (options & JK_OPT_FLUSHPACKETS)
701         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
702                "FlushPackets", server_name,
703                JK_OPT_DEFAULT & JK_OPT_FLUSHPACKETS ? " (default)" : "");
704     if (options & JK_OPT_FLUSHEADER)
705         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
706                "FlushHeader", server_name,
707                JK_OPT_DEFAULT & JK_OPT_FLUSHEADER ? " (default)" : "");
708     if (options & JK_OPT_DISABLEREUSE)
709         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
710                "DisableReuse", server_name,
711                JK_OPT_DEFAULT & JK_OPT_DISABLEREUSE ? " (default)" : "");
712     if (options & JK_OPT_REJECTUNSAFE)
713         jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
714                "RejectUnsafeURI", server_name,
715                JK_OPT_DEFAULT & JK_OPT_REJECTUNSAFE ? " (default)" : "");
716 }
717 
718 /* ========================================================================= */
719 /* Log something to Jk log file then exit */
jk_error_exit(const char * file,int line,int level,const server_rec * s,apr_pool_t * p,const char * fmt,...)720 static void jk_error_exit(const char *file,
721                           int line,
722                           int level,
723                           const server_rec * s,
724                           apr_pool_t * p, const char *fmt, ...)
725 {
726     va_list ap;
727     char *res;
728     char *ch;
729 
730     va_start(ap, fmt);
731     res = apr_pvsprintf(s->process->pool, fmt, ap);
732     va_end(ap);
733     /* Replace all format characters in the resulting message */
734     /* because we feed the message to ap_log_error(). */
735     ch = res;
736     while (*ch) {
737         if (*ch == '%') {
738             *ch = '#';
739         }
740         ch++;
741     }
742 
743 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20100606)
744     ap_log_error(file, line, APLOG_MODULE_INDEX, level, 0, s, "%s", res);
745 #else
746     ap_log_error(file, line, level, 0, s, "%s", res);
747 #endif
748     if ( s ) {
749 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20100606)
750         ap_log_error(file, line, APLOG_MODULE_INDEX, level, 0, NULL, "%s", res);
751 #else
752         ap_log_error(file, line, level, 0, NULL, "%s", res);
753 #endif
754     }
755 
756     /* Exit process */
757     exit(1);
758 }
759 
get_content_length(request_rec * r)760 static jk_uint64_t get_content_length(request_rec * r)
761 {
762     if (r->main == NULL || r->main == r) {
763         char *lenp = (char *)apr_table_get(r->headers_in, "Content-Length");
764 
765         if (lenp) {
766             jk_uint64_t rc = 0;
767             if (sscanf(lenp, "%" JK_UINT64_T_FMT, &rc) > 0 && rc > 0) {
768                 return rc;
769             }
770         }
771     }
772 
773     return 0;
774 }
775 
776 /* Retrieve string value from env var, use default if env var does not exist. */
get_env_string(request_rec * r,const char * def,char * env,int null_for_empty)777 static const char *get_env_string(request_rec *r, const char *def,
778                                   char *env, int null_for_empty)
779 {
780     char *value = (char *)apr_table_get(r->subprocess_env, env);
781     if (value)
782         return null_for_empty ? NULL_FOR_EMPTY(value) : value;
783     return null_for_empty ? NULL_FOR_EMPTY(def) : def;
784 }
785 
786 /* Retrieve integer value from env var, use default if env var does not exist. */
get_env_int(request_rec * r,int def,char * env)787 static int get_env_int(request_rec *r, int def, char *env)
788 {
789     char *value = (char *)apr_table_get(r->subprocess_env, env);
790     if (value)
791         return atoi(value);
792     return def;
793 }
794 
init_ws_service(apache_private_data_t * private_data,jk_ws_service_t * s,jk_server_conf_t * conf)795 static int init_ws_service(apache_private_data_t * private_data,
796                            jk_ws_service_t *s, jk_server_conf_t * conf)
797 {
798     int size;
799     request_rec *r = private_data->r;
800     char *ssl_temp = NULL;
801     char *uri = NULL;
802     const char *reply_timeout = NULL;
803     const char *sticky_ignore = NULL;
804     const char *stateless = NULL;
805     const char *route = NULL;
806     rule_extension_t *e;
807     jk_request_conf_t *rconf;
808 
809     /* Copy in function pointers (which are really methods) */
810     s->start_response = ws_start_response;
811     s->read = ws_read;
812     s->write = ws_write;
813     s->flush = ws_flush;
814     s->done = ws_done;
815     s->add_log_items = ws_add_log_items;
816     s->next_vhost = ws_next_vhost;
817     s->vhost_to_text = ws_vhost_to_text;
818     s->vhost_to_uw_map = ws_vhost_to_uw_map;
819 
820     s->auth_type = get_env_string(r, r->ap_auth_type,
821                                   conf->auth_type_indicator, 1);
822     s->remote_user = get_env_string(r, r->user,
823                                     conf->remote_user_indicator, 1);
824 
825     s->protocol = r->protocol;
826     s->remote_host = (char *)ap_get_remote_host(r->connection,
827                                                 r->per_dir_config,
828                                                 REMOTE_HOST, NULL);
829     s->remote_host = get_env_string(r, s->remote_host,
830                                     conf->remote_host_indicator, 1);
831     if (conf->options & JK_OPT_FWDLOCAL) {
832         s->remote_addr = r->connection->local_ip;
833         /* We don't know the client port of the backend connection. */
834         s->remote_port = "0";
835     }
836     else {
837 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20111130)
838         if (conf->options & JK_OPT_FWDPHYSICAL) {
839             s->remote_addr = r->connection->client_ip;
840             s->remote_port = apr_itoa(r->pool, r->connection->client_addr->port);
841         } else {
842             s->remote_addr = r->useragent_ip;
843             s->remote_port = apr_itoa(r->pool, r->useragent_addr->port);
844         }
845 #else
846         s->remote_addr = r->connection->remote_ip;
847         s->remote_port = apr_itoa(r->pool, r->connection->remote_addr->port);
848 #endif
849     }
850     s->remote_addr = get_env_string(r, s->remote_addr,
851                                     conf->remote_addr_indicator, 1);
852     s->remote_port = get_env_string(r, s->remote_port,
853                                     conf->remote_port_indicator, 1);
854 
855     if (conf->options & JK_OPT_FLUSHPACKETS)
856         s->flush_packets = 1;
857     if (conf->options & JK_OPT_FLUSHEADER)
858         s->flush_header = 1;
859 
860     rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config, &jk_module);
861 
862     e = rconf->rule_extensions;
863     if (e) {
864         s->extension.reply_timeout = e->reply_timeout;
865         s->extension.sticky_ignore = e->sticky_ignore;
866         s->extension.stateless = e->stateless;
867         s->extension.use_server_error_pages = e->use_server_error_pages;
868         if (e->activation) {
869             s->extension.activation = apr_palloc(r->pool, e->activation_size * sizeof(int));
870             memcpy(s->extension.activation, e->activation, e->activation_size * sizeof(int));
871         }
872         if (e->fail_on_status_size > 0) {
873             s->extension.fail_on_status_size = e->fail_on_status_size;
874             s->extension.fail_on_status = apr_palloc(r->pool, e->fail_on_status_size * sizeof(int));
875             memcpy(s->extension.fail_on_status, e->fail_on_status, e->fail_on_status_size * sizeof(int));
876         }
877         if (e->session_cookie) {
878             s->extension.session_cookie = apr_pstrdup(r->pool, e->session_cookie);
879         }
880         if (e->session_path) {
881             s->extension.session_path = apr_pstrdup(r->pool, e->session_path);
882         }
883         if (e->set_session_cookie) {
884             s->extension.set_session_cookie = e->set_session_cookie;
885         }
886         if (e->session_cookie_path) {
887             s->extension.session_cookie_path = apr_pstrdup(r->pool, e->session_cookie_path);
888         }
889     }
890     reply_timeout = apr_table_get(r->subprocess_env, JK_ENV_REPLY_TIMEOUT);
891     if (reply_timeout) {
892         int r = atoi(reply_timeout);
893         if (r >= 0)
894             s->extension.reply_timeout = r;
895     }
896 
897     sticky_ignore = apr_table_get(r->subprocess_env, JK_ENV_STICKY_IGNORE);
898     if (sticky_ignore) {
899         if (*sticky_ignore == '\0') {
900             s->extension.sticky_ignore = JK_TRUE;
901         }
902         else {
903             int r = atoi(sticky_ignore);
904             if (r) {
905                 s->extension.sticky_ignore = JK_TRUE;
906             }
907             else {
908                 s->extension.sticky_ignore = JK_FALSE;
909             }
910         }
911     }
912 
913     stateless = apr_table_get(r->subprocess_env, JK_ENV_STATELESS);
914     if (stateless) {
915         if (*stateless == '\0') {
916             s->extension.stateless = JK_TRUE;
917         }
918         else {
919             int r = atoi(stateless);
920             if (r) {
921                 s->extension.stateless = JK_TRUE;
922             }
923             else {
924                 s->extension.stateless = JK_FALSE;
925             }
926         }
927     }
928 
929     if (conf->options & JK_OPT_DISABLEREUSE)
930         s->disable_reuse = 1;
931 
932     /* get route if known */
933     route = apr_table_get(r->subprocess_env, JK_ENV_ROUTE);
934     if (route && *route) {
935         s->route = route;
936     }
937 
938     /* get server name */
939     s->server_name = get_env_string(r, (char *)ap_get_server_name(r),
940                                     conf->local_name_indicator, 0);
941 
942     /* get the local IP address */
943     s->local_addr = get_env_string(r, r->connection->local_ip,
944                                    conf->local_addr_indicator, 0);
945 
946     /* get the real port (otherwise redirect failed) */
947     /* XXX: use apache API for getting server port
948      *
949      * Pre 1.2.7 versions used:
950      * s->server_port = r->connection->local_addr->port;
951      */
952     s->server_port = get_env_int(r, ap_get_server_port(r),
953                                  conf->local_port_indicator);
954 
955 #if ((AP_MODULE_MAGIC_AT_LEAST(20051115,4)) && !defined(API_COMPATIBILITY)) || (MODULE_MAGIC_NUMBER_MAJOR >= 20060905)
956     s->server_software = (char *)ap_get_server_description();
957 #else
958     s->server_software = (char *)ap_get_server_version();
959 #endif
960     s->method = (char *)r->method;
961     s->content_length = get_content_length(r);
962     s->is_chunked = r->read_chunked;
963     if (s->content_length > 0 &&
964         get_env_string(r, NULL, conf->ignore_cl_indicator, 0) != NULL) {
965         s->content_length = 0;
966         s->is_chunked = 1;
967     }
968     s->no_more_chunks = 0;
969 #if defined(AS400) && !defined(AS400_UTF8)
970     /* Get the query string that is not translated to EBCDIC  */
971     s->query_string = ap_get_original_query_string(r);
972 #else
973     s->query_string = r->args;
974 #endif
975 
976     /*
977      * The 2.2 servlet spec errata says the uri from
978      * HttpServletRequest.getRequestURI() should remain encoded.
979      * [http://java.sun.com/products/servlet/errata_042700.html]
980      *
981      * We use JkOptions to determine which method to be used
982      *
983      * ap_escape_uri is the latest recommended but require
984      *               some java decoding (in TC 3.3 rc2)
985      *
986      * unparsed_uri is used for strict compliance with spec and
987      *              old Tomcat (3.2.3 for example)
988      *
989      * uri is use for compatibility with mod_rewrite with old Tomcats
990      */
991 
992     uri = rconf->orig_uri ? rconf->orig_uri : r->uri;
993 
994     switch (conf->options & JK_OPT_FWDURIMASK) {
995 
996     case JK_OPT_FWDURICOMPATUNPARSED:
997         s->req_uri = r->unparsed_uri;
998         if (s->req_uri != NULL) {
999             char *query_str = strchr(s->req_uri, '?');
1000             if (query_str != NULL) {
1001                 *query_str = 0;
1002             }
1003         }
1004 
1005         break;
1006 
1007     case JK_OPT_FWDURICOMPAT:
1008         s->req_uri = uri;
1009         break;
1010 
1011     case JK_OPT_FWDURIPROXY:
1012         size = 3 * (int)strlen(uri) + 1;
1013         s->req_uri = apr_palloc(r->pool, size);
1014         jk_canonenc(uri, s->req_uri, size);
1015         break;
1016 
1017     case JK_OPT_FWDURIESCAPED:
1018         s->req_uri = ap_escape_uri(r->pool, uri);
1019         break;
1020 
1021     default:
1022         return JK_FALSE;
1023     }
1024 
1025     if (conf->ssl_enable || conf->envvars) {
1026         ap_add_common_vars(r);
1027 
1028         if (conf->ssl_enable) {
1029             ssl_temp =
1030                 (char *)apr_table_get(r->subprocess_env,
1031                                       conf->https_indicator);
1032             if (ssl_temp && !strcasecmp(ssl_temp, "on")) {
1033                 s->is_ssl = JK_TRUE;
1034                 s->ssl_cert =
1035                     (char *)apr_table_get(r->subprocess_env,
1036                                           conf->certs_indicator);
1037 
1038                 if (conf->options & JK_OPT_FWDCERTCHAIN) {
1039                     const apr_array_header_t *t = apr_table_elts(r->subprocess_env);
1040                     if (t && t->nelts) {
1041                         int i;
1042                         const apr_table_entry_t *elts = (const apr_table_entry_t *) t->elts;
1043                         apr_array_header_t *certs = apr_array_make(r->pool, 1, sizeof(char *));
1044                         *(const char **)apr_array_push(certs) = s->ssl_cert;
1045                         for (i = 0; i < t->nelts; i++) {
1046                             if (!elts[i].key)
1047                                 continue;
1048                             if (!strncasecmp(elts[i].key, conf->certchain_prefix,
1049                                              strlen(conf->certchain_prefix)))
1050                                 *(const char **)apr_array_push(certs) = elts[i].val;
1051                         }
1052                         s->ssl_cert = apr_array_pstrcat(r->pool, certs, '\0');
1053                     }
1054                 }
1055 
1056                 if (s->ssl_cert) {
1057                     s->ssl_cert_len = (unsigned int)strlen(s->ssl_cert);
1058                     if (JK_IS_DEBUG_LEVEL(conf->log)) {
1059                         jk_log(conf->log, JK_LOG_DEBUG,
1060                                "SSL client certificate (%d bytes): %s",
1061                                s->ssl_cert_len, s->ssl_cert);
1062                     }
1063                 }
1064                 s->ssl_protocol =
1065                     (char *)apr_table_get(r->subprocess_env,
1066                                           conf->ssl_protocol_indicator);
1067                 /* Servlet 2.3 API */
1068                 s->ssl_cipher =
1069                     (char *)apr_table_get(r->subprocess_env,
1070                                           conf->cipher_indicator);
1071                 s->ssl_session =
1072                     (char *)apr_table_get(r->subprocess_env,
1073                                           conf->session_indicator);
1074 
1075                 if (conf->options & JK_OPT_FWDKEYSIZE) {
1076                     /* Servlet 2.3 API */
1077                     ssl_temp = (char *)apr_table_get(r->subprocess_env,
1078                                                      conf->
1079                                                      key_size_indicator);
1080                     if (ssl_temp)
1081                         s->ssl_key_size = atoi(ssl_temp);
1082                 }
1083 
1084 
1085             }
1086         }
1087 
1088         if (conf->envvars) {
1089             const apr_array_header_t *t = conf->envvar_items;
1090             if (t && t->nelts) {
1091                 int i;
1092                 int j = 0;
1093                 envvar_item *elts = (envvar_item *) t->elts;
1094                 s->attributes_names = apr_palloc(r->pool,
1095                                                  sizeof(char *) * t->nelts);
1096                 s->attributes_values = apr_palloc(r->pool,
1097                                                   sizeof(char *) * t->nelts);
1098 
1099                 for (i = 0; i < t->nelts; i++) {
1100                     s->attributes_names[i - j] = elts[i].name;
1101                     s->attributes_values[i - j] =
1102                         (char *)apr_table_get(r->subprocess_env, elts[i].name);
1103                     if (!s->attributes_values[i - j]) {
1104                         if (elts[i].has_default) {
1105                             s->attributes_values[i - j] = elts[i].value;
1106                         }
1107                         else {
1108                             s->attributes_values[i - j] = "";
1109                             s->attributes_names[i - j] = "";
1110                             j++;
1111                         }
1112                     }
1113                 }
1114 
1115                 s->num_attributes = t->nelts - j;
1116             }
1117         }
1118     }
1119 
1120     if (r->headers_in && apr_table_elts(r->headers_in)) {
1121         int need_content_length_header = (!s->is_chunked
1122                                           && s->content_length ==
1123                                           0) ? JK_TRUE : JK_FALSE;
1124         const apr_array_header_t *t = apr_table_elts(r->headers_in);
1125         if (t && t->nelts) {
1126             int i;
1127             int off = 0;
1128             apr_table_entry_t *elts = (apr_table_entry_t *) t->elts;
1129             s->num_headers = t->nelts;
1130             /* allocate an extra header slot in case we need to add a content-length header */
1131             s->headers_names =
1132                 apr_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
1133             s->headers_values =
1134                 apr_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
1135             if (!s->headers_names || !s->headers_values)
1136                 return JK_FALSE;
1137             for (i = 0; i < t->nelts; i++) {
1138                 char *hname = apr_pstrdup(r->pool, elts[i].key);
1139                 if (!strcasecmp(hname, "content-length")) {
1140                     if (need_content_length_header) {
1141                         need_content_length_header = JK_FALSE;
1142                     } else if (s->is_chunked) {
1143                         s->num_headers--;
1144                         off++;
1145                         continue;
1146                     }
1147                 }
1148                 s->headers_values[i - off] = apr_pstrdup(r->pool, elts[i].val);
1149                 s->headers_names[i - off] = hname;
1150             }
1151             /* Add a content-length = 0 header if needed.
1152              * Ajp13 assumes an absent content-length header means an unknown,
1153              * but non-zero length body.
1154              */
1155             if (need_content_length_header) {
1156                 s->headers_names[s->num_headers] = "content-length";
1157                 s->headers_values[s->num_headers] = "0";
1158                 s->num_headers++;
1159             }
1160         }
1161         /* Add a content-length = 0 header if needed. */
1162         else if (need_content_length_header) {
1163             s->headers_names = apr_palloc(r->pool, sizeof(char *));
1164             s->headers_values = apr_palloc(r->pool, sizeof(char *));
1165             if (!s->headers_names || !s->headers_values)
1166                 return JK_FALSE;
1167             s->headers_names[0] = "content-length";
1168             s->headers_values[0] = "0";
1169             s->num_headers++;
1170         }
1171     }
1172     s->uw_map = conf->uw_map;
1173 
1174     /* Dump all connection param so we can trace what's going to
1175      * the remote tomcat
1176      */
1177     if (JK_IS_DEBUG_LEVEL(conf->log)) {
1178         jk_log(conf->log, JK_LOG_DEBUG,
1179                "Service protocol=%s method=%s ssl=%s host=%s addr=%s name=%s port=%d auth=%s user=%s laddr=%s raddr=%s uaddr=%s uri=%s",
1180                STRNULL_FOR_NULL(s->protocol),
1181                STRNULL_FOR_NULL(s->method),
1182                s->is_ssl ? "true" : "false",
1183                STRNULL_FOR_NULL(s->remote_host),
1184                STRNULL_FOR_NULL(s->remote_addr),
1185                STRNULL_FOR_NULL(s->server_name),
1186                s->server_port,
1187                STRNULL_FOR_NULL(s->auth_type),
1188                STRNULL_FOR_NULL(s->remote_user),
1189                STRNULL_FOR_NULL(r->connection->local_ip),
1190 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20111130)
1191                STRNULL_FOR_NULL(r->connection->client_ip),
1192                STRNULL_FOR_NULL(r->useragent_ip),
1193 #else
1194                STRNULL_FOR_NULL(r->connection->remote_ip),
1195                STRNULL_FOR_NULL(r->connection->remote_ip),
1196 #endif
1197                STRNULL_FOR_NULL(s->req_uri));
1198     }
1199 
1200     return JK_TRUE;
1201 }
1202 
1203 /*
1204  * The JK module command processors
1205  *
1206  * The below are all installed so that Apache calls them while it is
1207  * processing its config files.  This allows configuration info to be
1208  * copied into a jk_server_conf_t object, which is then used for request
1209  * filtering/processing.
1210  *
1211  * See jk_cmds definition below for explanations of these options.
1212  */
1213 
1214 /*
1215  * JkMountCopy directive handling
1216  *
1217  * JkMountCopy On/Off/All
1218  */
1219 
jk_set_mountcopy(cmd_parms * cmd,void * dummy,const char * mount_copy)1220 static const char *jk_set_mountcopy(cmd_parms * cmd,
1221                                     void *dummy, const char *mount_copy)
1222 {
1223     server_rec *s = cmd->server;
1224     jk_server_conf_t *conf =
1225         (jk_server_conf_t *) ap_get_module_config(s->module_config,
1226                                                   &jk_module);
1227 
1228     if (! strcasecmp(mount_copy, "all")) {
1229         const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1230         if (err_string != NULL) {
1231             return err_string;
1232         }
1233         jk_mount_copy_all = JK_TRUE;
1234     }
1235     else if (strcasecmp(mount_copy, "on") && strcasecmp(mount_copy, "off")) {
1236         return "JkMountCopy must be All, On or Off";
1237     }
1238     else {
1239         conf->mountcopy = strcasecmp(mount_copy, "off") ? JK_TRUE : JK_FALSE;
1240     }
1241 
1242     return NULL;
1243 }
1244 
1245 /*
1246  * JkMount directive handling
1247  *
1248  * JkMount URI(context) worker
1249  */
1250 
jk_mount_context(cmd_parms * cmd,void * dummy,const char * context,const char * worker)1251 static const char *jk_mount_context(cmd_parms * cmd,
1252                                     void *dummy,
1253                                     const char *context,
1254                                     const char *worker)
1255 {
1256     server_rec *s = cmd->server;
1257     jk_server_conf_t *conf =
1258         (jk_server_conf_t *) ap_get_module_config(s->module_config,
1259                                                   &jk_module);
1260     const char *c, *w;
1261 
1262     if (worker != NULL && cmd->path == NULL ) {
1263         c = context;
1264         w = worker;
1265     }
1266     else if (worker == NULL && cmd->path != NULL) {
1267         c = cmd->path;
1268         w = context;
1269     }
1270     else {
1271         if (worker == NULL)
1272             return "JkMount needs a path when not defined in a location";
1273         else
1274             return "JkMount can not have a path when defined in a location";
1275     }
1276 
1277     if (c[0] != '/')
1278         return "JkMount context should start with /";
1279 
1280     if (!conf->uri_to_context) {
1281         if (!jk_map_alloc(&(conf->uri_to_context))) {
1282             return "JkMount Memory error";
1283         }
1284     }
1285     /*
1286      * Add the new worker to the alias map.
1287      */
1288     jk_map_put(conf->uri_to_context, c, w, NULL);
1289     return NULL;
1290 }
1291 
1292 /*
1293  * JkUnMount directive handling
1294  *
1295  * JkUnMount URI(context) worker
1296  */
1297 
jk_unmount_context(cmd_parms * cmd,void * dummy,const char * context,const char * worker)1298 static const char *jk_unmount_context(cmd_parms * cmd,
1299                                       void *dummy,
1300                                       const char *context,
1301                                       const char *worker)
1302 {
1303     server_rec *s = cmd->server;
1304     jk_server_conf_t *conf =
1305         (jk_server_conf_t *) ap_get_module_config(s->module_config,
1306                                                   &jk_module);
1307     char *uri;
1308     const char *c, *w;
1309 
1310     if (worker != NULL && cmd->path == NULL ) {
1311         c = context;
1312         w = worker;
1313     }
1314     else if (worker == NULL && cmd->path != NULL) {
1315         c = cmd->path;
1316         w = context;
1317     }
1318     else {
1319         if (worker == NULL)
1320             return "JkUnMount needs a path when not defined in a location";
1321         else
1322             return "JkUnMount can not have a path when defined in a location";
1323     }
1324 
1325     if (c[0] != '/')
1326         return "JkUnMount context should start with /";
1327 
1328     uri = apr_pstrcat(cmd->temp_pool, "!", c, NULL);
1329 
1330     if (!conf->uri_to_context) {
1331         if (!jk_map_alloc(&(conf->uri_to_context))) {
1332             return "JkUnMount Memory error";
1333         }
1334     }
1335     /*
1336      * Add the new worker to the alias map.
1337      */
1338     jk_map_put(conf->uri_to_context, uri, w, NULL);
1339     return NULL;
1340 }
1341 
1342 
1343 /*
1344  * JkWorkersFile Directive Handling
1345  *
1346  * JkWorkersFile file
1347  */
1348 
jk_set_worker_file(cmd_parms * cmd,void * dummy,const char * worker_file)1349 static const char *jk_set_worker_file(cmd_parms * cmd,
1350                                       void *dummy, const char *worker_file)
1351 {
1352     const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1353     if (err_string != NULL) {
1354         return err_string;
1355     }
1356 
1357     if (jk_worker_file != NULL)
1358         return "JkWorkersFile only allowed once";
1359 
1360     /* we need an absolute path (ap_server_root_relative does the ap_pstrdup) */
1361     jk_worker_file = ap_server_root_relative(cmd->pool, worker_file);
1362 
1363     if (jk_worker_file == NULL)
1364         return "JkWorkersFile file name invalid";
1365 
1366     if (jk_file_exists(jk_worker_file) != JK_TRUE)
1367         return "JkWorkersFile: Can't find the workers file specified";
1368 
1369     return NULL;
1370 }
1371 
1372 /*
1373  * JkMountFile Directive Handling
1374  *
1375  * JkMountFile file
1376  */
1377 
jk_set_mount_file(cmd_parms * cmd,void * dummy,const char * mount_file)1378 static const char *jk_set_mount_file(cmd_parms * cmd,
1379                                      void *dummy, const char *mount_file)
1380 {
1381     server_rec *s = cmd->server;
1382 
1383     jk_server_conf_t *conf =
1384         (jk_server_conf_t *) ap_get_module_config(s->module_config,
1385                                                   &jk_module);
1386 
1387     /* we need an absolute path (ap_server_root_relative does the ap_pstrdup) */
1388     conf->mount_file = ap_server_root_relative(cmd->pool, mount_file);
1389 
1390     if (conf->mount_file == NULL)
1391         return "JkMountFile file name invalid";
1392 
1393     if (jk_file_exists(conf->mount_file) != JK_TRUE)
1394         return "JkMountFile: Can't find the mount file specified";
1395 
1396     if (!conf->uri_to_context) {
1397         if (!jk_map_alloc(&(conf->uri_to_context))) {
1398             return "JkMountFile Memory error";
1399         }
1400     }
1401 
1402     return NULL;
1403 }
1404 
1405 /*
1406  * JkMountFileReload Directive Handling
1407  *
1408  * JkMountFileReload seconds
1409  */
1410 
jk_set_mount_file_reload(cmd_parms * cmd,void * dummy,const char * mount_file_reload)1411 static const char *jk_set_mount_file_reload(cmd_parms * cmd,
1412                                             void *dummy, const char *mount_file_reload)
1413 {
1414     server_rec *s = cmd->server;
1415     int interval;
1416 
1417     jk_server_conf_t *conf =
1418         (jk_server_conf_t *) ap_get_module_config(s->module_config,
1419                                                   &jk_module);
1420 
1421     interval = atoi(mount_file_reload);
1422     if (interval < 0) {
1423         interval = 0;
1424     }
1425 
1426     conf->mount_file_reload = interval;
1427 
1428     return NULL;
1429 }
1430 
1431 /*
1432  * JkWatchdogInterval Directive Handling
1433  *
1434  * JkWatchdogInterval seconds
1435  */
1436 
jk_set_watchdog_interval(cmd_parms * cmd,void * dummy,const char * watchdog_interval)1437 static const char *jk_set_watchdog_interval(cmd_parms * cmd,
1438                                             void *dummy, const char *watchdog_interval)
1439 {
1440     const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1441     if (err_string != NULL) {
1442         return err_string;
1443     }
1444 
1445 #if APR_HAS_THREADS
1446     jk_watchdog_interval = atoi(watchdog_interval);
1447     if (jk_watchdog_interval < 0) {
1448         jk_watchdog_interval = 0;
1449     }
1450     return NULL;
1451 #else
1452     return "JkWatchdogInterval: APR was compiled without threading support. Cannot create watchdog thread";
1453 #endif
1454 }
1455 
1456 /*
1457  * JkLogFile Directive Handling
1458  *
1459  * JkLogFile file
1460  */
1461 
jk_set_log_file(cmd_parms * cmd,void * dummy,const char * log_file)1462 static const char *jk_set_log_file(cmd_parms * cmd,
1463                                    void *dummy, const char *log_file)
1464 {
1465     server_rec *s = cmd->server;
1466     jk_server_conf_t *conf =
1467         (jk_server_conf_t *) ap_get_module_config(s->module_config,
1468                                                   &jk_module);
1469 
1470     /* we need an absolute path */
1471     if (*log_file != '|')
1472         conf->log_file = ap_server_root_relative(cmd->pool, log_file);
1473     else
1474         conf->log_file = apr_pstrdup(cmd->pool, log_file);
1475 
1476     if (conf->log_file == NULL)
1477         return "JkLogFile file name invalid";
1478 
1479     return NULL;
1480 }
1481 
1482 /*
1483  * JkShmFile Directive Handling
1484  *
1485  * JkShmFile file
1486  */
1487 
jk_set_shm_file(cmd_parms * cmd,void * dummy,const char * shm_file)1488 static const char *jk_set_shm_file(cmd_parms * cmd,
1489                                    void *dummy, const char *shm_file)
1490 {
1491     const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1492     if (err_string != NULL) {
1493         return err_string;
1494     }
1495 
1496     /* we need an absolute path */
1497     jk_shm_file = ap_server_root_relative(cmd->pool, shm_file);
1498     if (jk_shm_file == NULL)
1499         return "JkShmFile file name invalid";
1500 
1501     return NULL;
1502 }
1503 
1504 /*
1505  * JkShmSize Directive Handling
1506  *
1507  * JkShmSize size in kilobytes
1508  */
1509 
jk_set_shm_size(cmd_parms * cmd,void * dummy,const char * shm_size)1510 static const char *jk_set_shm_size(cmd_parms * cmd,
1511                                    void *dummy, const char *shm_size)
1512 {
1513     int sz = 0;
1514     const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1515     if (err_string != NULL) {
1516         return err_string;
1517     }
1518 
1519     sz = atoi(shm_size) * 1024;
1520     if (sz < JK_SHM_MIN_SIZE)
1521         sz = JK_SHM_MIN_SIZE;
1522     else
1523         sz = JK_SHM_ALIGN(sz);
1524     jk_shm_size = sz;
1525     if (jk_shm_size)
1526         jk_shm_size_set = 1;
1527     return NULL;
1528 }
1529 
1530 /*
1531  * JkLogLevel Directive Handling
1532  *
1533  * JkLogLevel debug/info/error/emerg
1534  */
1535 
jk_set_log_level(cmd_parms * cmd,void * dummy,const char * log_level)1536 static const char *jk_set_log_level(cmd_parms * cmd,
1537                                     void *dummy, const char *log_level)
1538 {
1539     server_rec *s = cmd->server;
1540     jk_server_conf_t *conf =
1541         (jk_server_conf_t *) ap_get_module_config(s->module_config,
1542                                                   &jk_module);
1543 
1544     conf->log_level = jk_parse_log_level(log_level);
1545 
1546     return NULL;
1547 }
1548 
1549 /*
1550  * JkLogStampFormat Directive Handling
1551  *
1552  * JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
1553  */
1554 
jk_set_log_fmt(cmd_parms * cmd,void * dummy,const char * log_format)1555 static const char *jk_set_log_fmt(cmd_parms * cmd,
1556                                   void *dummy, const char *log_format)
1557 {
1558     server_rec *s = cmd->server;
1559     jk_server_conf_t *conf =
1560         (jk_server_conf_t *) ap_get_module_config(s->module_config,
1561                                                   &jk_module);
1562 
1563     conf->stamp_format_string = apr_pstrdup(cmd->pool, log_format);
1564 
1565     return NULL;
1566 }
1567 
1568 
1569 /*
1570  * JkAutoAlias Directive Handling
1571  *
1572  * JkAutoAlias application directory
1573  */
1574 
jk_set_auto_alias(cmd_parms * cmd,void * dummy,const char * directory)1575 static const char *jk_set_auto_alias(cmd_parms * cmd,
1576                                      void *dummy, const char *directory)
1577 {
1578     server_rec *s = cmd->server;
1579     jk_server_conf_t *conf =
1580         (jk_server_conf_t *) ap_get_module_config(s->module_config,
1581                                                   &jk_module);
1582 
1583     conf->alias_dir = apr_pstrdup(cmd->pool, directory);
1584 
1585     if (conf->alias_dir == NULL)
1586         return "JkAutoAlias directory invalid";
1587 
1588     return NULL;
1589 }
1590 
1591 /*
1592  * JkStripSession directive handling
1593  *
1594  * JkStripSession On/Off [session path identifier]
1595  */
1596 
jk_set_strip_session(cmd_parms * cmd,void * dummy,const char * flag,const char * name)1597 static const char *jk_set_strip_session(cmd_parms * cmd, void *dummy,
1598                                         const char *flag, const char *name)
1599 {
1600     server_rec *s = cmd->server;
1601     jk_server_conf_t *conf =
1602         (jk_server_conf_t *) ap_get_module_config(s->module_config,
1603                                                   &jk_module);
1604 
1605     if (strcasecmp(flag, "on") && strcasecmp(flag, "off")) {
1606         return "JkStripSession must be On or Off";
1607     }
1608     else {
1609         conf->strip_session = strcasecmp(flag, "off") ? JK_TRUE : JK_FALSE;
1610     }
1611 
1612     /* Check for optional path value */
1613     if (name)
1614         conf->strip_session_name = apr_pstrdup(cmd->pool, name);
1615     else
1616         conf->strip_session_name = apr_pstrdup(cmd->pool, JK_PATH_SESSION_IDENTIFIER);
1617 
1618     return NULL;
1619 }
1620 
1621 /*****************************************************************
1622  *
1623  * Actually logging.
1624  */
1625 
1626 typedef const char *(*item_key_func) (request_rec *, char *);
1627 
1628 typedef struct
1629 {
1630     item_key_func func;
1631     char *arg;
1632 } request_log_format_item;
1633 
process_item(request_rec * r,request_log_format_item * item)1634 static const char *process_item(request_rec * r,
1635                                 request_log_format_item * item)
1636 {
1637     const char *cp;
1638 
1639     cp = (*item->func) (r, item->arg);
1640     return cp ? cp : "-";
1641 }
1642 
request_log_transaction(request_rec * r)1643 static int request_log_transaction(request_rec * r)
1644 {
1645     request_log_format_item *items;
1646     char *str, *s;
1647     int i;
1648     int len = 0;
1649     const char **strs;
1650     int *strl;
1651     jk_server_conf_t *conf;
1652     jk_request_conf_t *rconf;
1653     apr_array_header_t *format;
1654 
1655     conf = (jk_server_conf_t *) ap_get_module_config(r->server->module_config,
1656                                                      &jk_module);
1657     format = conf->format;
1658     if (format == NULL) {
1659         return DECLINED;
1660     }
1661     rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config,
1662                                                       &jk_module);
1663     if (rconf == NULL || rconf->jk_handled == JK_FALSE) {
1664         return DECLINED;
1665     }
1666 
1667     strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts));
1668     strl = apr_palloc(r->pool, sizeof(int) * (format->nelts));
1669     items = (request_log_format_item *) format->elts;
1670     for (i = 0; i < format->nelts; ++i) {
1671         strs[i] = process_item(r, &items[i]);
1672     }
1673     for (i = 0; i < format->nelts; ++i) {
1674         len += strl[i] = (int)strlen(strs[i]);
1675     }
1676     str = apr_palloc(r->pool, len + 1);
1677     for (i = 0, s = str; i < format->nelts; ++i) {
1678         memcpy(s, strs[i], strl[i]);
1679         s += strl[i];
1680     }
1681     *s = 0;
1682 
1683     jk_log(conf->log, JK_LOG_REQUEST, "%s", str);
1684     return OK;
1685 
1686 }
1687 
1688 /*****************************************************************
1689  *
1690  * Parsing the log format string
1691  */
1692 
format_integer(apr_pool_t * p,int i)1693 static char *format_integer(apr_pool_t * p, int i)
1694 {
1695     return apr_psprintf(p, "%d", i);
1696 }
1697 
pfmt(apr_pool_t * p,int i)1698 static char *pfmt(apr_pool_t * p, int i)
1699 {
1700     if (i <= 0) {
1701         return "-";
1702     }
1703     else {
1704         return format_integer(p, i);
1705     }
1706 }
1707 
constant_item(request_rec * dummy,char * stuff)1708 static const char *constant_item(request_rec * dummy, char *stuff)
1709 {
1710     return stuff;
1711 }
1712 
log_worker_name(request_rec * r,char * a)1713 static const char *log_worker_name(request_rec * r, char *a)
1714 {
1715     return apr_table_get(r->notes, JK_NOTE_WORKER_NAME);
1716 }
1717 
log_worker_route(request_rec * r,char * a)1718 static const char *log_worker_route(request_rec * r, char *a)
1719 {
1720     return apr_table_get(r->notes, JK_NOTE_WORKER_ROUTE);
1721 }
1722 
1723 
log_request_duration(request_rec * r,char * a)1724 static const char *log_request_duration(request_rec * r, char *a)
1725 {
1726     return apr_table_get(r->notes, JK_NOTE_REQUEST_DURATION);
1727 }
1728 
log_request_line(request_rec * r,char * a)1729 static const char *log_request_line(request_rec * r, char *a)
1730 {
1731     /* NOTE: If the original request contained a password, we
1732      * re-write the request line here to contain XXXXXX instead:
1733      * (note the truncation before the protocol string for HTTP/0.9 requests)
1734      * (note also that r->the_request contains the unmodified request)
1735      */
1736     return (r->parsed_uri.password) ? apr_pstrcat(r->pool, r->method, " ",
1737                                                   apr_uri_unparse(r->pool,
1738                                                                   &r->
1739                                                                   parsed_uri,
1740                                                                   0),
1741                                                   r->
1742                                                   assbackwards ? NULL : " ",
1743                                                   r->protocol, NULL)
1744         : r->the_request;
1745 }
1746 
1747 /* These next two routines use the canonical name:port so that log
1748  * parsers don't need to duplicate all the vhost parsing crud.
1749  */
log_virtual_host(request_rec * r,char * a)1750 static const char *log_virtual_host(request_rec * r, char *a)
1751 {
1752     return r->server->server_hostname;
1753 }
1754 
log_server_port(request_rec * r,char * a)1755 static const char *log_server_port(request_rec * r, char *a)
1756 {
1757     return apr_psprintf(r->pool, "%u",
1758                         r->server->port ? r->server->
1759                         port : ap_default_port(r));
1760 }
1761 
1762 /* This respects the setting of UseCanonicalName so that
1763  * the dynamic mass virtual hosting trick works better.
1764  */
log_server_name(request_rec * r,char * a)1765 static const char *log_server_name(request_rec * r, char *a)
1766 {
1767     return ap_get_server_name(r);
1768 }
1769 
log_request_uri(request_rec * r,char * a)1770 static const char *log_request_uri(request_rec * r, char *a)
1771 {
1772     return r->uri;
1773 }
log_request_method(request_rec * r,char * a)1774 static const char *log_request_method(request_rec * r, char *a)
1775 {
1776     return r->method;
1777 }
1778 
log_request_protocol(request_rec * r,char * a)1779 static const char *log_request_protocol(request_rec * r, char *a)
1780 {
1781     return r->protocol;
1782 }
log_request_query(request_rec * r,char * a)1783 static const char *log_request_query(request_rec * r, char *a)
1784 {
1785     return (r->args != NULL) ? apr_pstrcat(r->pool, "?", r->args, NULL)
1786         : "";
1787 }
log_status(request_rec * r,char * a)1788 static const char *log_status(request_rec * r, char *a)
1789 {
1790     return pfmt(r->pool, r->status);
1791 }
1792 
clf_log_bytes_sent(request_rec * r,char * a)1793 static const char *clf_log_bytes_sent(request_rec * r, char *a)
1794 {
1795     if (!r->sent_bodyct) {
1796         return "-";
1797     }
1798     else {
1799         return apr_off_t_toa(r->pool, r->bytes_sent);
1800     }
1801 }
1802 
log_bytes_sent(request_rec * r,char * a)1803 static const char *log_bytes_sent(request_rec * r, char *a)
1804 {
1805     if (!r->sent_bodyct) {
1806         return "0";
1807     }
1808     else {
1809         return apr_psprintf(r->pool, "%" APR_OFF_T_FMT, r->bytes_sent);
1810     }
1811 }
1812 
1813 static struct log_item_list
1814 {
1815     char ch;
1816     item_key_func func;
1817 } log_item_keys[] = {
1818     { 'T', log_request_duration },
1819     { 'r', log_request_line },
1820     { 'U', log_request_uri },
1821     { 's', log_status },
1822     { 'b', clf_log_bytes_sent },
1823     { 'B', log_bytes_sent },
1824     { 'V', log_server_name },
1825     { 'v', log_virtual_host },
1826     { 'p', log_server_port },
1827     { 'H', log_request_protocol },
1828     { 'm', log_request_method },
1829     { 'q', log_request_query },
1830     { 'w', log_worker_name },
1831     { 'R', log_worker_route},
1832     { '\0', NULL }
1833 };
1834 
find_log_func(char k)1835 static struct log_item_list *find_log_func(char k)
1836 {
1837     int i;
1838 
1839     for (i = 0; log_item_keys[i].ch; ++i)
1840         if (k == log_item_keys[i].ch) {
1841             return &log_item_keys[i];
1842         }
1843 
1844     return NULL;
1845 }
1846 
parse_request_log_misc_string(apr_pool_t * p,request_log_format_item * it,const char ** sa)1847 static char *parse_request_log_misc_string(apr_pool_t * p,
1848                                            request_log_format_item * it,
1849                                            const char **sa)
1850 {
1851     const char *s;
1852     char *d;
1853 
1854     it->func = constant_item;
1855 
1856     s = *sa;
1857     while (*s && *s != '%') {
1858         s++;
1859     }
1860     /*
1861      * This might allocate a few chars extra if there's a backslash
1862      * escape in the format string.
1863      */
1864     it->arg = apr_palloc(p, s - *sa + 1);
1865 
1866     d = it->arg;
1867     s = *sa;
1868     while (*s && *s != '%') {
1869         if (*s != '\\') {
1870             *d++ = *s++;
1871         }
1872         else {
1873             s++;
1874             switch (*s) {
1875             case '\\':
1876                 *d++ = '\\';
1877                 s++;
1878                 break;
1879             case 'n':
1880                 *d++ = '\n';
1881                 s++;
1882                 break;
1883             case 't':
1884                 *d++ = '\t';
1885                 s++;
1886                 break;
1887             default:
1888                 /* copy verbatim */
1889                 *d++ = '\\';
1890                 /*
1891                  * Allow the loop to deal with this *s in the normal
1892                  * fashion so that it handles end of string etc.
1893                  * properly.
1894                  */
1895                 break;
1896             }
1897         }
1898     }
1899     *d = '\0';
1900 
1901     *sa = s;
1902     return NULL;
1903 }
1904 
parse_request_log_item(apr_pool_t * p,request_log_format_item * it,const char ** sa)1905 static char *parse_request_log_item(apr_pool_t * p,
1906                                     request_log_format_item * it,
1907                                     const char **sa)
1908 {
1909     const char *s = *sa;
1910     struct log_item_list *l;
1911 
1912     if (*s != '%') {
1913         return parse_request_log_misc_string(p, it, sa);
1914     }
1915 
1916     ++s;
1917     it->arg = "";               /* For safety's sake... */
1918 
1919     l = find_log_func(*s++);
1920     if (!l) {
1921         char dummy[2];
1922 
1923         dummy[0] = s[-1];
1924         dummy[1] = '\0';
1925         return apr_pstrcat(p, "Unrecognized JkRequestLogFormat directive %",
1926                            dummy, NULL);
1927     }
1928     it->func = l->func;
1929     *sa = s;
1930     return NULL;
1931 }
1932 
parse_request_log_string(apr_pool_t * p,const char * s,const char ** err)1933 static apr_array_header_t *parse_request_log_string(apr_pool_t * p,
1934                                                     const char *s,
1935                                                     const char **err)
1936 {
1937     apr_array_header_t *a =
1938         apr_array_make(p, 0, sizeof(request_log_format_item));
1939     char *res;
1940 
1941     while (*s) {
1942         if ((res =
1943              parse_request_log_item(p,
1944                                     (request_log_format_item *)
1945                                     apr_array_push(a), &s))) {
1946             *err = res;
1947             return NULL;
1948         }
1949     }
1950 
1951     return a;
1952 }
1953 
1954 /*
1955  * JkRequestLogFormat Directive Handling
1956  *
1957  * JkRequestLogFormat format string
1958  *
1959  * %b - Bytes sent, excluding HTTP headers. In CLF format
1960  * %B - Bytes sent, excluding HTTP headers.
1961  * %H - The request protocol
1962  * %m - The request method
1963  * %p - The canonical Port of the server serving the request
1964  * %q - The query string (prepended with a ? if a query string exists,
1965  *      otherwise an empty string)
1966  * %r - First line of request
1967  * %s - request HTTP status code
1968  * %T - Request duration, elapsed time to handle request in seconds '.' micro seconds
1969  * %U - The URL path requested, not including any query string.
1970  * %v - The canonical ServerName of the server serving the request.
1971  * %V - The server name according to the UseCanonicalName setting.
1972  * %w - Tomcat worker name
1973  */
1974 
jk_set_request_log_format(cmd_parms * cmd,void * dummy,const char * format)1975 static const char *jk_set_request_log_format(cmd_parms * cmd,
1976                                              void *dummy, const char *format)
1977 {
1978     server_rec *s = cmd->server;
1979     jk_server_conf_t *conf =
1980         (jk_server_conf_t *) ap_get_module_config(s->module_config,
1981                                                   &jk_module);
1982 
1983     conf->format_string = apr_pstrdup(cmd->pool, format);
1984 
1985     return NULL;
1986 }
1987 
1988 
1989 /*
1990  * JkWorkerIndicator Directive Handling
1991  *
1992  * JkWorkerIndicator JkWorker
1993  */
1994 
jk_set_worker_indicator(cmd_parms * cmd,void * dummy,const char * indicator)1995 static const char *jk_set_worker_indicator(cmd_parms * cmd,
1996                                            void *dummy, const char *indicator)
1997 {
1998     server_rec *s = cmd->server;
1999     jk_server_conf_t *conf =
2000         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2001                                                   &jk_module);
2002 
2003     conf->worker_indicator = apr_pstrdup(cmd->pool, indicator);
2004 
2005     return NULL;
2006 }
2007 
2008 /*
2009  * Directives Handling for setting various environment names
2010  * used to overwrite the following request information:
2011  * - remote_addr
2012  * - remote_port
2013  * - remote_host
2014  * - remote_user
2015  * - auth_type
2016  * - server_name
2017  * - server_port
2018  */
jk_set_remote_addr_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2019 static const char *jk_set_remote_addr_indicator(cmd_parms * cmd,
2020                                                 void *dummy, const char *indicator)
2021 {
2022     server_rec *s = cmd->server;
2023     jk_server_conf_t *conf =
2024         (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2025     conf->remote_addr_indicator = apr_pstrdup(cmd->pool, indicator);
2026     return NULL;
2027 }
2028 
jk_set_remote_port_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2029 static const char *jk_set_remote_port_indicator(cmd_parms * cmd,
2030                                                 void *dummy, const char *indicator)
2031 {
2032     server_rec *s = cmd->server;
2033     jk_server_conf_t *conf =
2034         (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2035     conf->remote_port_indicator = apr_pstrdup(cmd->pool, indicator);
2036     return NULL;
2037 }
2038 
jk_set_remote_host_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2039 static const char *jk_set_remote_host_indicator(cmd_parms * cmd,
2040                                                 void *dummy, const char *indicator)
2041 {
2042     server_rec *s = cmd->server;
2043     jk_server_conf_t *conf =
2044         (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2045     conf->remote_host_indicator = apr_pstrdup(cmd->pool, indicator);
2046     return NULL;
2047 }
2048 
jk_set_remote_user_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2049 static const char *jk_set_remote_user_indicator(cmd_parms * cmd,
2050                                                 void *dummy, const char *indicator)
2051 {
2052     server_rec *s = cmd->server;
2053     jk_server_conf_t *conf =
2054         (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2055     conf->remote_user_indicator = apr_pstrdup(cmd->pool, indicator);
2056     return NULL;
2057 }
2058 
jk_set_auth_type_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2059 static const char *jk_set_auth_type_indicator(cmd_parms * cmd,
2060                                               void *dummy, const char *indicator)
2061 {
2062     server_rec *s = cmd->server;
2063     jk_server_conf_t *conf =
2064         (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2065     conf->auth_type_indicator = apr_pstrdup(cmd->pool, indicator);
2066     return NULL;
2067 }
2068 
jk_set_local_name_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2069 static const char *jk_set_local_name_indicator(cmd_parms * cmd,
2070                                                void *dummy, const char *indicator)
2071 {
2072     server_rec *s = cmd->server;
2073     jk_server_conf_t *conf =
2074         (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2075     conf->local_name_indicator = apr_pstrdup(cmd->pool, indicator);
2076     return NULL;
2077 }
2078 
jk_set_local_addr_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2079 static const char *jk_set_local_addr_indicator(cmd_parms * cmd,
2080                                                void *dummy, const char *indicator)
2081 {
2082     server_rec *s = cmd->server;
2083     jk_server_conf_t *conf =
2084         (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2085     conf->local_addr_indicator = apr_pstrdup(cmd->pool, indicator);
2086     return NULL;
2087 }
2088 
jk_set_local_port_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2089 static const char *jk_set_local_port_indicator(cmd_parms * cmd,
2090                                                void *dummy, const char *indicator)
2091 {
2092     server_rec *s = cmd->server;
2093     jk_server_conf_t *conf =
2094         (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2095     conf->local_port_indicator = apr_pstrdup(cmd->pool, indicator);
2096     return NULL;
2097 }
2098 
jk_set_ignore_cl_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2099 static const char *jk_set_ignore_cl_indicator(cmd_parms * cmd,
2100                                               void *dummy, const char *indicator)
2101 {
2102     server_rec *s = cmd->server;
2103     jk_server_conf_t *conf =
2104         (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2105     conf->ignore_cl_indicator = apr_pstrdup(cmd->pool, indicator);
2106     return NULL;
2107 }
2108 
2109 /*
2110  * JkExtractSSL Directive Handling
2111  *
2112  * JkExtractSSL On/Off
2113  */
2114 
jk_set_enable_ssl(cmd_parms * cmd,void * dummy,int flag)2115 static const char *jk_set_enable_ssl(cmd_parms * cmd, void *dummy, int flag)
2116 {
2117     server_rec *s = cmd->server;
2118     jk_server_conf_t *conf =
2119         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2120                                                   &jk_module);
2121 
2122     /* Set up our value */
2123     conf->ssl_enable = flag ? JK_TRUE : JK_FALSE;
2124 
2125     return NULL;
2126 }
2127 
2128 /*
2129  * JkHTTPSIndicator Directive Handling
2130  *
2131  * JkHTTPSIndicator HTTPS
2132  */
2133 
jk_set_https_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2134 static const char *jk_set_https_indicator(cmd_parms * cmd,
2135                                           void *dummy, const char *indicator)
2136 {
2137     server_rec *s = cmd->server;
2138     jk_server_conf_t *conf =
2139         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2140                                                   &jk_module);
2141 
2142     conf->https_indicator = apr_pstrdup(cmd->pool, indicator);
2143 
2144     return NULL;
2145 }
2146 
2147 /*
2148  * JkSSLPROTOCOLIndicator Directive Handling
2149  *
2150  * JkSSLPROTOCOLIndicator SSL_PROTOCOL
2151  */
2152 
jk_set_ssl_protocol_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2153 static const char *jk_set_ssl_protocol_indicator(cmd_parms * cmd,
2154                                                  void *dummy, const char *indicator)
2155 {
2156     server_rec *s = cmd->server;
2157     jk_server_conf_t *conf =
2158         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2159                                                   &jk_module);
2160 
2161     conf->ssl_protocol_indicator = apr_pstrdup(cmd->pool, indicator);
2162 
2163     return NULL;
2164 }
2165 
2166 /*
2167  * JkCERTSIndicator Directive Handling
2168  *
2169  * JkCERTSIndicator SSL_CLIENT_CERT
2170  */
2171 
jk_set_certs_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2172 static const char *jk_set_certs_indicator(cmd_parms * cmd,
2173                                           void *dummy, const char *indicator)
2174 {
2175     server_rec *s = cmd->server;
2176     jk_server_conf_t *conf =
2177         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2178                                                   &jk_module);
2179 
2180     conf->certs_indicator = apr_pstrdup(cmd->pool, indicator);
2181 
2182     return NULL;
2183 }
2184 
2185 /*
2186  * JkCIPHERIndicator Directive Handling
2187  *
2188  * JkCIPHERIndicator SSL_CIPHER
2189  */
2190 
jk_set_cipher_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2191 static const char *jk_set_cipher_indicator(cmd_parms * cmd,
2192                                            void *dummy, const char *indicator)
2193 {
2194     server_rec *s = cmd->server;
2195     jk_server_conf_t *conf =
2196         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2197                                                   &jk_module);
2198 
2199     conf->cipher_indicator = apr_pstrdup(cmd->pool, indicator);
2200 
2201     return NULL;
2202 }
2203 
2204 /*
2205  * JkCERTCHAINPrefix Directive Handling
2206  *
2207  * JkCERTCHAINPrefix SSL_CLIENT_CERT_CHAIN_
2208  */
2209 
jk_set_certchain_prefix(cmd_parms * cmd,void * dummy,const char * prefix)2210 static const char *jk_set_certchain_prefix(cmd_parms * cmd,
2211                                            void *dummy, const char *prefix)
2212 {
2213     server_rec *s = cmd->server;
2214     jk_server_conf_t *conf =
2215         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2216                                                   &jk_module);
2217 
2218     conf->certchain_prefix = apr_pstrdup(cmd->pool, prefix);
2219 
2220     return NULL;
2221 }
2222 
2223 /*
2224  * JkSESSIONIndicator Directive Handling
2225  *
2226  * JkSESSIONIndicator SSL_SESSION_ID
2227  */
2228 
jk_set_session_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2229 static const char *jk_set_session_indicator(cmd_parms * cmd,
2230                                             void *dummy,
2231                                             const char *indicator)
2232 {
2233     server_rec *s = cmd->server;
2234     jk_server_conf_t *conf =
2235         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2236                                                   &jk_module);
2237 
2238     conf->session_indicator = apr_pstrdup(cmd->pool, indicator);
2239 
2240     return NULL;
2241 }
2242 
2243 /*
2244  * JkKEYSIZEIndicator Directive Handling
2245  *
2246  * JkKEYSIZEIndicator SSL_CIPHER_USEKEYSIZE
2247  */
2248 
jk_set_key_size_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2249 static const char *jk_set_key_size_indicator(cmd_parms * cmd,
2250                                              void *dummy,
2251                                              const char *indicator)
2252 {
2253     server_rec *s = cmd->server;
2254     jk_server_conf_t *conf =
2255         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2256                                                   &jk_module);
2257 
2258     conf->key_size_indicator = apr_pstrdup(cmd->pool, indicator);
2259 
2260     return NULL;
2261 }
2262 
2263 /*
2264  * JkOptions Directive Handling
2265  *
2266  *
2267  * +ForwardSSLKeySize        => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
2268  * -ForwardSSLKeySize        => Don't Forward SSL Key Size, will make mod_jk works with all TC release
2269  *  ForwardURICompat         => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
2270  *  ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
2271  *  ForwardURIEscaped        => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
2272  *  ForwardDirectories       => Forward all directory requests with no index files to Tomcat
2273  * +ForwardSSLCertChain      => Forward SSL Cert Chain
2274  * -ForwardSSLCertChain      => Don't Forward SSL Cert Chain (default)
2275  */
2276 
jk_set_options(cmd_parms * cmd,void * dummy,const char * line)2277 static const char *jk_set_options(cmd_parms * cmd, void *dummy,
2278                                   const char *line)
2279 {
2280     int opt = 0;
2281     int mask = 0;
2282     char action;
2283     char *w;
2284 
2285     server_rec *s = cmd->server;
2286     jk_server_conf_t *conf =
2287         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2288                                                   &jk_module);
2289 
2290     while (line[0] != 0) {
2291         w = ap_getword_conf(cmd->pool, &line);
2292         action = 0;
2293 
2294         if (*w == '+' || *w == '-') {
2295             action = *(w++);
2296         }
2297 
2298         mask = 0;
2299 
2300         if (action == '-' &&
2301             (!strncasecmp(w, "ForwardURI", strlen("ForwardURI")))) {
2302             return apr_pstrcat(cmd->pool, "JkOptions: Illegal option '-", w,
2303                                "': option can not be disabled", NULL);
2304         }
2305         if (!strcasecmp(w, "ForwardURICompat")) {
2306             opt = JK_OPT_FWDURICOMPAT;
2307             mask = JK_OPT_FWDURIMASK;
2308         }
2309         else if (!strcasecmp(w, "ForwardURICompatUnparsed")) {
2310             opt = JK_OPT_FWDURICOMPATUNPARSED;
2311             mask = JK_OPT_FWDURIMASK;
2312         }
2313         else if (!strcasecmp(w, "ForwardURIEscaped")) {
2314             opt = JK_OPT_FWDURIESCAPED;
2315             mask = JK_OPT_FWDURIMASK;
2316         }
2317         else if (!strcasecmp(w, "ForwardURIProxy")) {
2318             opt = JK_OPT_FWDURIPROXY;
2319             mask = JK_OPT_FWDURIMASK;
2320         }
2321         else if (!strcasecmp(w, "CollapseSlashesAll")) {
2322             opt = JK_OPT_COLLAPSEALL;
2323             mask = JK_OPT_COLLAPSEMASK;
2324         }
2325         else if (!strcasecmp(w, "CollapseSlashesNone")) {
2326             opt = JK_OPT_COLLAPSENONE;
2327             mask = JK_OPT_COLLAPSEMASK;
2328         }
2329         else if (!strcasecmp(w, "CollapseSlashesUnmount")) {
2330             opt = JK_OPT_COLLAPSEUNMOUNT;
2331             mask = JK_OPT_COLLAPSEMASK;
2332         }
2333         else if (!strcasecmp(w, "ForwardDirectories")) {
2334             opt = JK_OPT_FWDDIRS;
2335         }
2336         else if (!strcasecmp(w, "ForwardLocalAddress")) {
2337             opt = JK_OPT_FWDLOCAL;
2338             mask = JK_OPT_FWDADDRMASK;
2339         }
2340         else if (!strcasecmp(w, "ForwardPhysicalAddress")) {
2341             opt = JK_OPT_FWDPHYSICAL;
2342             mask = JK_OPT_FWDADDRMASK;
2343         }
2344         else if (!strcasecmp(w, "FlushPackets")) {
2345             opt = JK_OPT_FLUSHPACKETS;
2346         }
2347         else if (!strcasecmp(w, "FlushHeader")) {
2348             opt = JK_OPT_FLUSHEADER;
2349         }
2350         else if (!strcasecmp(w, "DisableReuse")) {
2351             opt = JK_OPT_DISABLEREUSE;
2352         }
2353         else if (!strcasecmp(w, "ForwardSSLCertChain")) {
2354             opt = JK_OPT_FWDCERTCHAIN;
2355         }
2356         else if (!strcasecmp(w, "ForwardKeySize")) {
2357             opt = JK_OPT_FWDKEYSIZE;
2358         }
2359         else if (!strcasecmp(w, "RejectUnsafeURI")) {
2360             opt = JK_OPT_REJECTUNSAFE;
2361         }
2362         else
2363             return apr_pstrcat(cmd->pool, "JkOptions: Illegal option '", w,
2364                                "'", NULL);
2365 
2366         conf->options &= ~mask;
2367 
2368         if (action == '-') {
2369             conf->exclude_options |= opt;
2370         }
2371         else if (action == '+') {
2372             conf->options |= opt;
2373         }
2374         else {                  /* for now +Opt == Opt */
2375             conf->options |= opt;
2376         }
2377     }
2378     return NULL;
2379 }
2380 
2381 /*
2382  * JkEnvVar Directive Handling
2383  *
2384  * JkEnvVar MYOWNDIR
2385  */
2386 
jk_add_env_var(cmd_parms * cmd,void * dummy,const char * env_name,const char * default_value)2387 static const char *jk_add_env_var(cmd_parms * cmd,
2388                                   void *dummy,
2389                                   const char *env_name,
2390                                   const char *default_value)
2391 {
2392     server_rec *s = cmd->server;
2393     jk_server_conf_t *conf =
2394         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2395                                                   &jk_module);
2396 
2397     conf->envvars_has_own = JK_TRUE;
2398     if (!conf->envvars) {
2399         conf->envvars      = apr_table_make(cmd->pool, 0);
2400         conf->envvars_def  = apr_table_make(cmd->pool, 0);
2401         conf->envvar_items = apr_array_make(cmd->pool, 0,
2402                                             sizeof(envvar_item));
2403     }
2404 
2405     /* env_name is mandatory, default_value is optional.
2406      * No value means send the attribute only, if the env var is set during runtime.
2407      */
2408     apr_table_setn(conf->envvars, env_name, default_value ? default_value : "");
2409     apr_table_setn(conf->envvars_def, env_name, default_value ? "1" : "0");
2410 
2411     return NULL;
2412 }
2413 
2414 /*
2415  * JkWorkerProperty Directive Handling
2416  *
2417  * JkWorkerProperty name=value
2418  */
2419 
jk_set_worker_property(cmd_parms * cmd,void * dummy,const char * line)2420 static const char *jk_set_worker_property(cmd_parms * cmd,
2421                                           void *dummy,
2422                                           const char *line)
2423 {
2424     server_rec *s = cmd->server;
2425     jk_server_conf_t *conf =
2426         (jk_server_conf_t *) ap_get_module_config(s->module_config,
2427                                                   &jk_module);
2428 
2429     const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2430     if (err_string != NULL) {
2431         return err_string;
2432     }
2433 
2434     if (!jk_worker_properties)
2435         jk_map_alloc(&jk_worker_properties);
2436     if (jk_map_read_property(jk_worker_properties, NULL, line,
2437                              JK_MAP_HANDLE_DUPLICATES, conf->log) == JK_FALSE)
2438         return apr_pstrcat(cmd->temp_pool, "Invalid JkWorkerProperty ", line, NULL);
2439 
2440     return NULL;
2441 }
2442 
2443 static const command_rec jk_cmds[] = {
2444     /*
2445      * JkWorkersFile specifies a full path to the location of the worker
2446      * properties file.
2447      *
2448      * This file defines the different workers used by apache to redirect
2449      * servlet requests.
2450      */
2451     AP_INIT_TAKE1("JkWorkersFile", jk_set_worker_file, NULL, RSRC_CONF,
2452                   "The name of a worker file for the Tomcat servlet containers"),
2453 
2454     /*
2455      * JkMountFile specifies a full path to the location of the
2456      * uriworker properties file.
2457      *
2458      * This file defines the different mapping for workers used by apache
2459      * to redirect servlet requests.
2460      */
2461     AP_INIT_TAKE1("JkMountFile", jk_set_mount_file, NULL, RSRC_CONF,
2462                   "The name of a mount file for the Tomcat servlet uri mapping"),
2463 
2464     /*
2465      * JkMountFileReload specifies the reload check interval for the
2466      * uriworker properties file.
2467      *
2468      * Default value is: JK_URIMAP_DEF_RELOAD
2469      */
2470     AP_INIT_TAKE1("JkMountFileReload", jk_set_mount_file_reload, NULL, RSRC_CONF,
2471                   "The reload check interval of the mount file"),
2472 
2473     /*
2474      * JkWatchdogInterval specifies the maintain interval for the
2475      * watchdog thread.
2476      *
2477      * Default value is: 0 meaning watchdog thread will not be created
2478      */
2479     AP_INIT_TAKE1("JkWatchdogInterval", jk_set_watchdog_interval, NULL, RSRC_CONF,
2480                   "The maintain interval of the watchdog thread"),
2481 
2482     /*
2483      * JkMount mounts a url prefix to a worker (the worker need to be
2484      * defined in the worker properties file.
2485      */
2486     AP_INIT_TAKE12("JkMount", jk_mount_context, NULL, RSRC_CONF|ACCESS_CONF,
2487                    "A mount point from a context to a Tomcat worker"),
2488 
2489     /*
2490      * JkUnMount unmounts a url prefix to a worker (the worker need to be
2491      * defined in the worker properties file.
2492      */
2493     AP_INIT_TAKE12("JkUnMount", jk_unmount_context, NULL, RSRC_CONF|ACCESS_CONF,
2494                    "A no mount point from a context to a Tomcat worker"),
2495 
2496     /*
2497      * JkMountCopy specifies if mod_jk should copy the mount points
2498      * from the main server to the virtual servers.
2499      */
2500     AP_INIT_TAKE1("JkMountCopy", jk_set_mountcopy, NULL, RSRC_CONF,
2501                   "Should the base server mounts be copied to the virtual server"),
2502 
2503     /*
2504      * JkStripSession specifies if mod_jk should strip the ;jsessionid
2505      * from the unmapped urls
2506      */
2507     AP_INIT_TAKE12("JkStripSession", jk_set_strip_session, NULL, RSRC_CONF,
2508                    "Should the server strip the jsessionid from unmapped URLs"),
2509 
2510     /*
2511      * JkLogFile & JkLogLevel specifies to where should the plugin log
2512      * its information and how much.
2513      * JkLogStampFormat specify the time-stamp to be used on log
2514      */
2515     AP_INIT_TAKE1("JkLogFile", jk_set_log_file, NULL, RSRC_CONF,
2516                   "Full path to the Tomcat module log file"),
2517 
2518     AP_INIT_TAKE1("JkShmFile", jk_set_shm_file, NULL, RSRC_CONF,
2519                   "Full path to the Tomcat module shared memory file"),
2520 
2521     AP_INIT_TAKE1("JkShmSize", jk_set_shm_size, NULL, RSRC_CONF,
2522                   "Size of the shared memory file in KBytes"),
2523 
2524     AP_INIT_TAKE1("JkLogLevel", jk_set_log_level, NULL, RSRC_CONF,
2525                   "The Tomcat module log level, can be debug, "
2526                   "info, error or emerg"),
2527     AP_INIT_TAKE1("JkLogStampFormat", jk_set_log_fmt, NULL, RSRC_CONF,
2528                   "The Tomcat module log format, follow strftime syntax"),
2529     AP_INIT_TAKE1("JkRequestLogFormat", jk_set_request_log_format, NULL,
2530                   RSRC_CONF,
2531                   "The mod_jk module request log format string"),
2532 
2533     /*
2534      * Automatically Alias webapp context directories into the Apache
2535      * document space.
2536      */
2537     AP_INIT_TAKE1("JkAutoAlias", jk_set_auto_alias, NULL, RSRC_CONF,
2538                   "The mod_jk module automatic context apache alias directory"),
2539 
2540     /*
2541      * Enable worker name to be set in an environment variable.
2542      * This way one can use LocationMatch together with mod_env,
2543      * mod_setenvif and mod_rewrite to set the target worker.
2544      * Use this in combination with SetHandler jakarta-servlet to
2545      * make mod_jk the handler for the request.
2546      *
2547      */
2548     AP_INIT_TAKE1("JkWorkerIndicator", jk_set_worker_indicator, NULL, RSRC_CONF,
2549                   "Name of the Apache environment that contains the worker name"),
2550 
2551     /*
2552      * Environment variables used to overwrite the following
2553      * request information which gets forwarded:
2554      * - remote_addr
2555      * - remote_port
2556      * - remote_host
2557      * - remote_user
2558      * - auth_type
2559      * - server_name
2560      * - server_port
2561      */
2562     AP_INIT_TAKE1("JkRemoteAddrIndicator", jk_set_remote_addr_indicator, NULL, RSRC_CONF,
2563                   "Name of the Apache environment that contains the remote address"),
2564     AP_INIT_TAKE1("JkRemotePortIndicator", jk_set_remote_port_indicator, NULL, RSRC_CONF,
2565                   "Name of the Apache environment that contains the remote port"),
2566     AP_INIT_TAKE1("JkRemoteHostIndicator", jk_set_remote_host_indicator, NULL, RSRC_CONF,
2567                   "Name of the Apache environment that contains the remote host name"),
2568     AP_INIT_TAKE1("JkRemoteUserIndicator", jk_set_remote_user_indicator, NULL, RSRC_CONF,
2569                   "Name of the Apache environment that contains the remote user name"),
2570     AP_INIT_TAKE1("JkAuthTypeIndicator", jk_set_auth_type_indicator, NULL, RSRC_CONF,
2571                   "Name of the Apache environment that contains the type of authentication"),
2572     AP_INIT_TAKE1("JkLocalNameIndicator", jk_set_local_name_indicator, NULL, RSRC_CONF,
2573                   "Name of the Apache environment that contains the local name"),
2574     AP_INIT_TAKE1("JkLocalAddrIndicator", jk_set_local_addr_indicator, NULL, RSRC_CONF,
2575                   "Name of the Apache environment that contains the local IP address"),
2576     AP_INIT_TAKE1("JkLocalPortIndicator", jk_set_local_port_indicator, NULL, RSRC_CONF,
2577                   "Name of the Apache environment that contains the local port"),
2578     AP_INIT_TAKE1("JkIgnoreCLIndicator", jk_set_ignore_cl_indicator, NULL, RSRC_CONF,
2579                   "Name of the Apache environment that forces to ignore a request "
2580                   "Content-Length header"),
2581 
2582     /*
2583      * Apache has multiple SSL modules (for example apache_ssl, stronghold
2584      * IHS ...). Each of these can have a different SSL environment names
2585      * The following properties let the administrator specify the envoiroment
2586      * variables names.
2587      *
2588      * HTTPS - indication for SSL
2589      * CERTS - Base64-Der-encoded client certificates.
2590      * CIPHER - A string specifing the ciphers suite in use.
2591      * KEYSIZE - Size of Key used in dialogue (#bits are secure)
2592      * SESSION - A string specifing the current SSL session.
2593      */
2594     AP_INIT_TAKE1("JkHTTPSIndicator", jk_set_https_indicator, NULL, RSRC_CONF,
2595                   "Name of the Apache environment that contains SSL indication"),
2596     AP_INIT_TAKE1("JkSSLPROTOCOLIndicator", jk_set_ssl_protocol_indicator, NULL, RSRC_CONF,
2597                   "Name of the Apache environment that contains the SSL protocol name"),
2598     AP_INIT_TAKE1("JkCERTSIndicator", jk_set_certs_indicator, NULL, RSRC_CONF,
2599                   "Name of the Apache environment that contains SSL client certificates"),
2600     AP_INIT_TAKE1("JkCIPHERIndicator", jk_set_cipher_indicator, NULL,
2601                   RSRC_CONF,
2602                   "Name of the Apache environment that contains SSL client cipher"),
2603     AP_INIT_TAKE1("JkSESSIONIndicator", jk_set_session_indicator, NULL,
2604                   RSRC_CONF,
2605                   "Name of the Apache environment that contains SSL session"),
2606     AP_INIT_TAKE1("JkKEYSIZEIndicator", jk_set_key_size_indicator, NULL,
2607                   RSRC_CONF,
2608                   "Name of the Apache environment that contains SSL key size in use"),
2609     AP_INIT_TAKE1("JkCERTCHAINPrefix", jk_set_certchain_prefix, NULL, RSRC_CONF,
2610                   "Name of the Apache environment (prefix) that contains SSL client chain certificates"),
2611     AP_INIT_FLAG("JkExtractSSL", jk_set_enable_ssl, NULL, RSRC_CONF,
2612                  "Turns on SSL processing and information gathering by mod_jk"),
2613 
2614     /*
2615      * Options to tune mod_jk configuration
2616      * for now we understand :
2617      * +ForwardSSLKeySize        => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
2618      * -ForwardSSLKeySize        => Don't Forward SSL Key Size, will make mod_jk works with all TC release
2619      *  ForwardURICompat         => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
2620      *  ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
2621      *  ForwardURIEscaped        => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
2622      * +ForwardSSLCertChain      => Forward SSL certificate chain
2623      * -ForwardSSLCertChain      => Don't forward SSL certificate chain
2624      */
2625     AP_INIT_RAW_ARGS("JkOptions", jk_set_options, NULL, RSRC_CONF,
2626                      "Set one of more options to configure the mod_jk module"),
2627 
2628     /*
2629      * JkEnvVar let user defines envs var passed from WebServer to
2630      * Servlet Engine
2631      */
2632     AP_INIT_TAKE12("JkEnvVar", jk_add_env_var, NULL, RSRC_CONF,
2633                    "Adds a name of environment variable and an optional value "
2634                    "that should be sent to servlet-engine"),
2635 
2636     AP_INIT_RAW_ARGS("JkWorkerProperty", jk_set_worker_property,
2637                      NULL, RSRC_CONF,
2638                      "Set workers.properties formated directive"),
2639 
2640     {NULL}
2641 };
2642 
2643 /* ========================================================================= */
2644 /* The JK module handlers                                                    */
2645 /* ========================================================================= */
2646 
2647 /** Util - cleanup for all processes.
2648  */
jk_cleanup_proc(void * data)2649 static apr_status_t jk_cleanup_proc(void *data)
2650 {
2651     /* If the main log is piped, we need to make sure
2652      * it is no longer used. The external log process
2653      * (e.g. rotatelogs) will be gone now and the pipe will
2654      * block, once the buffer gets full. NULLing
2655      * jklogfp makes logging switch to error log.
2656      */
2657     jk_logger_t *l = (jk_logger_t *)data;
2658     if (l && l->logger_private) {
2659         jk_file_logger_t *p = l->logger_private;
2660         if (p && p->is_piped == JK_TRUE) {
2661             p->jklogfp = NULL;
2662             p->is_piped = JK_FALSE;
2663         }
2664     }
2665     jk_shm_close(l);
2666     return APR_SUCCESS;
2667 }
2668 
2669 /** Util - cleanup for child processes.
2670  */
jk_cleanup_child(void * data)2671 static apr_status_t jk_cleanup_child(void *data)
2672 {
2673     /* If the main log is piped, we need to make sure
2674      * it is no longer used. The external log process
2675      * (e.g. rotatelogs) will be gone now and the pipe will
2676      * block, once the buffer gets full. NULLing
2677      * jklogfp makes logging switch to error log.
2678      */
2679     jk_logger_t *l = (jk_logger_t *)data;
2680     if (l && l->logger_private) {
2681         jk_file_logger_t *p = l->logger_private;
2682         if (p && p->is_piped == JK_TRUE) {
2683             p->jklogfp = NULL;
2684             p->is_piped = JK_FALSE;
2685         }
2686     }
2687     /* Force the watchdog thread exit */
2688     if (jk_watchdog_interval > 0) {
2689         jk_watchdog_interval = 0;
2690         while (jk_watchdog_running)
2691             apr_sleep(apr_time_from_sec(1));
2692     }
2693     wc_shutdown(l);
2694     return jk_cleanup_proc(data);
2695 }
2696 
2697 /** Main service method, called to forward a request to tomcat
2698  */
jk_handler(request_rec * r)2699 static int jk_handler(request_rec * r)
2700 {
2701     const char *worker_name;
2702     jk_server_conf_t *xconf;
2703     jk_request_conf_t *rconf;
2704     int rc, dmt = 1;
2705     int worker_name_extension = JK_FALSE;
2706 
2707     /* We do DIR_MAGIC_TYPE here to make sure TC gets all requests, even
2708      * if they are directory requests, in case there are no static files
2709      * visible to Apache and/or DirectoryIndex was not used. This is only
2710      * used when JkOptions has ForwardDirectories set. */
2711     /* Not for me, try next handler */
2712     if (strcmp(r->handler, JK_HANDLER)
2713         && (dmt = strcmp(r->handler, DIR_MAGIC_TYPE)))
2714         return DECLINED;
2715 
2716     xconf = (jk_server_conf_t *) ap_get_module_config(r->server->module_config,
2717                                                       &jk_module);
2718     JK_TRACE_ENTER(xconf->log);
2719     if (apr_table_get(r->subprocess_env, "no-jk")) {
2720         if (JK_IS_DEBUG_LEVEL(xconf->log))
2721             jk_log(xconf->log, JK_LOG_DEBUG,
2722                    "Into handler no-jk env var detected for uri=%s, declined",
2723                    r->uri);
2724 
2725         JK_TRACE_EXIT(xconf->log);
2726         return DECLINED;
2727     }
2728 
2729     /* Was the option to forward directories to Tomcat set? */
2730     if (!dmt && !(xconf->options & JK_OPT_FWDDIRS)) {
2731         JK_TRACE_EXIT(xconf->log);
2732         return DECLINED;
2733     }
2734 
2735     rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config, &jk_module);
2736     if (rconf == NULL) {
2737         rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t));
2738         rconf->jk_handled = JK_FALSE;
2739         rconf->rule_extensions = NULL;
2740         rconf->orig_uri = NULL;
2741         ap_set_module_config(r->request_config, &jk_module, rconf);
2742     }
2743 
2744     worker_name = apr_table_get(r->notes, JK_NOTE_WORKER_NAME);
2745 
2746     if (worker_name == NULL) {
2747         /* we may be here because of a manual directive ( that overrides
2748            translate and
2749            sets the handler directly ). We still need to know the worker.
2750          */
2751         worker_name = apr_table_get(r->subprocess_env, xconf->worker_indicator);
2752         if (worker_name) {
2753           /* The JkWorkerIndicator environment variable has
2754            * been used to explicitly set the worker without JkMount.
2755            * This is useful in combination with LocationMatch or mod_rewrite.
2756            */
2757             if (JK_IS_DEBUG_LEVEL(xconf->log))
2758                 jk_log(xconf->log, JK_LOG_DEBUG,
2759                        "Retrieved worker (%s) from env %s for %s",
2760                        worker_name, xconf->worker_indicator, r->uri);
2761             if (ap_strchr_c(worker_name, ';')) {
2762                 rule_extension_t *e = apr_palloc(r->pool, sizeof(rule_extension_t));
2763                 char *w = apr_pstrdup(r->pool, worker_name);
2764                 worker_name_extension = JK_TRUE;
2765                 parse_rule_extensions(w, e, xconf->log);
2766                 worker_name = w;
2767                 rconf->rule_extensions = e;
2768             }
2769         }
2770         else if (worker_env.num_of_workers == 1) {
2771           /** We have a single worker ( the common case ).
2772               ( lb is a bit special, it should count as a single worker but
2773               I'm not sure how ). We also have a manual config directive that
2774               explicitly give control to us. */
2775             worker_name = worker_env.worker_list[0];
2776             if (JK_IS_DEBUG_LEVEL(xconf->log))
2777                 jk_log(xconf->log, JK_LOG_DEBUG,
2778                        "Single worker (%s) configuration for %s",
2779                        worker_name, r->uri);
2780         }
2781         else {
2782             if (!xconf->uw_map) {
2783                 if (JK_IS_DEBUG_LEVEL(xconf->log))
2784                     jk_log(xconf->log, JK_LOG_DEBUG,
2785                            "missing uri map for %s:%s",
2786                            xconf->s->server_hostname ? xconf->s->server_hostname : "_default_",
2787                            r->uri);
2788             }
2789             else {
2790                 rule_extension_t *e;
2791                 char *clean_uri;
2792                 clean_uri = apr_pstrdup(r->pool, r->uri);
2793                 rc = jk_servlet_normalize(clean_uri, xconf->log);
2794                 if (rc != 0) {
2795                     JK_TRACE_EXIT(xconf->log);
2796                     return HTTP_BAD_REQUEST;
2797                 }
2798 
2799                 worker_name = map_uri_to_worker_ext(xconf->uw_map, clean_uri,
2800                                                     NULL, &e, NULL, xconf->log);
2801                 if (worker_name) {
2802                     rconf->rule_extensions = e;
2803                     rconf->orig_uri = r->uri;
2804                     r->uri = clean_uri;
2805                 }
2806             }
2807 
2808             if (worker_name == NULL && worker_env.num_of_workers) {
2809                 worker_name = worker_env.worker_list[0];
2810                 if (JK_IS_DEBUG_LEVEL(xconf->log))
2811                     jk_log(xconf->log, JK_LOG_DEBUG,
2812                            "Using first worker (%s) from %d workers for %s",
2813                            worker_name, worker_env.num_of_workers, r->uri);
2814             }
2815         }
2816         if (worker_name)
2817             apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker_name);
2818     }
2819 
2820     if (JK_IS_DEBUG_LEVEL(xconf->log))
2821        jk_log(xconf->log, JK_LOG_DEBUG, "Into handler %s worker=%s"
2822               " r->proxyreq=%d",
2823               r->handler, STRNULL_FOR_NULL(worker_name), r->proxyreq);
2824 
2825     rconf->jk_handled = JK_TRUE;
2826 
2827     /* If this is a proxy request, we'll notify an error */
2828     if (r->proxyreq) {
2829         jk_log(xconf->log, JK_LOG_INFO, "Proxy request for worker=%s"
2830               " is not allowed",
2831               STRNULL_FOR_NULL(worker_name));
2832         JK_TRACE_EXIT(xconf->log);
2833         return HTTP_INTERNAL_SERVER_ERROR;
2834     }
2835 
2836     /* Set up r->read_chunked flags for chunked encoding, if present */
2837     if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != APR_SUCCESS) {
2838         JK_TRACE_EXIT(xconf->log);
2839         return rc;
2840     }
2841 
2842     if (worker_name) {
2843         jk_worker_t *worker = wc_get_worker_for_name(worker_name, xconf->log);
2844 
2845         /* If the remote client has aborted, just ignore the request */
2846         if (r->connection->aborted) {
2847             jk_log(xconf->log, JK_LOG_INFO, "Client connection aborted for"
2848                    " worker=%s",
2849                    worker_name);
2850             JK_TRACE_EXIT(xconf->log);
2851             return OK;
2852         }
2853 
2854         if (worker) {
2855             long micro, seconds;
2856             char *duration = NULL;
2857             apr_time_t rd;
2858             apr_time_t request_begin = 0;
2859             int is_error = HTTP_INTERNAL_SERVER_ERROR;
2860             int rc = JK_FALSE;
2861             apache_private_data_t private_data;
2862             jk_ws_service_t s;
2863             jk_pool_atom_t buf[SMALL_POOL_SIZE];
2864             jk_open_pool(&private_data.p, buf, sizeof(buf));
2865 
2866             private_data.read_body_started = JK_FALSE;
2867             private_data.r = r;
2868 
2869             if (worker_name_extension == JK_TRUE) {
2870                 extension_fix(&private_data.p, worker_name,
2871                               rconf->rule_extensions, xconf->log);
2872             }
2873 
2874             /* Maintain will be done by watchdog thread */
2875             if (!jk_watchdog_interval)
2876                 wc_maintain(xconf->log);
2877             jk_init_ws_service(&s);
2878             s.ws_private = &private_data;
2879             s.pool = &private_data.p;
2880             apr_table_setn(r->notes, JK_NOTE_WORKER_TYPE,
2881                            wc_get_name_for_type(worker->type, xconf->log));
2882 
2883             request_begin = apr_time_now();
2884 
2885             if (init_ws_service(&private_data, &s, xconf)) {
2886                 jk_endpoint_t *end = NULL;
2887 
2888                 /* Use per/thread pool ( or "context" ) to reuse the
2889                    endpoint. It's a bit faster, but I don't know
2890                    how to deal with load balancing - but it's usefull for JNI
2891                  */
2892 
2893                 /* worker->get_endpoint might fail if we are out of memory so check */
2894                 /* and handle it */
2895                 if (worker->get_endpoint(worker, &end, xconf->log)) {
2896                     rc = end->service(end, &s, xconf->log,
2897                                       &is_error);
2898                     end->done(&end, xconf->log);
2899                     if ((s.content_read < s.content_length ||
2900                         (s.is_chunked && !s.no_more_chunks)) &&
2901                         /* This case aborts the connection below and typically
2902                          * means the request body reading already timed out,
2903                          * so lets not try to read again here. */
2904                         !(rc == JK_CLIENT_ERROR && is_error == HTTP_BAD_REQUEST)) {
2905                         /*
2906                          * If the servlet engine didn't consume all of the
2907                          * request data, consume and discard all further
2908                          * characters left to read from client
2909                          */
2910                         char *buff = apr_palloc(r->pool, 2048);
2911                         int consumed = 0;
2912                         if (buff != NULL) {
2913                             int rd;
2914                             while ((rd =
2915                                     ap_get_client_block(r, buff, 2048)) > 0) {
2916                                 s.content_read += rd;
2917                                 consumed += rd;
2918                             }
2919                         }
2920                         if (JK_IS_DEBUG_LEVEL(xconf->log)) {
2921                            jk_log(xconf->log, JK_LOG_DEBUG,
2922                                   "Consumed %d bytes of remaining request data for worker=%s",
2923                                   consumed, STRNULL_FOR_NULL(worker_name));
2924                         }
2925                     }
2926                 }
2927                 else {            /* this means we couldn't get an endpoint */
2928                     jk_log(xconf->log, JK_LOG_ERROR, "Could not get endpoint"
2929                            " for worker=%s",
2930                            worker_name);
2931                     rc = 0;       /* just to make sure that we know we've failed */
2932                     is_error = HTTP_SERVICE_UNAVAILABLE;
2933                 }
2934             }
2935             else {
2936                 jk_log(xconf->log, JK_LOG_ERROR, "Could not init service"
2937                        " for worker=%s",
2938                        worker_name);
2939                 jk_close_pool(&private_data.p);
2940                 JK_TRACE_EXIT(xconf->log);
2941                 return HTTP_INTERNAL_SERVER_ERROR;
2942             }
2943             rd = apr_time_now() - request_begin;
2944             seconds = (long)apr_time_sec(rd);
2945             micro = (long)(rd - apr_time_from_sec(seconds));
2946 
2947             duration = apr_psprintf(r->pool, "%.1ld.%.6ld", seconds, micro);
2948             apr_table_setn(r->notes, JK_NOTE_REQUEST_DURATION, duration);
2949             if (s.route && *s.route)
2950                 apr_table_set(r->notes, JK_NOTE_WORKER_ROUTE, s.route);
2951 
2952             jk_close_pool(&private_data.p);
2953 
2954             if (rc > 0) {
2955                 if (s.extension.use_server_error_pages &&
2956                     s.http_response_status >= s.extension.use_server_error_pages) {
2957                     if (JK_IS_DEBUG_LEVEL(xconf->log))
2958                         jk_log(xconf->log, JK_LOG_DEBUG, "Forwarding status=%d"
2959                                " for worker=%s",
2960                                s.http_response_status, worker_name);
2961                     JK_TRACE_EXIT(xconf->log);
2962                     return s.http_response_status;
2963                 }
2964                 /* If tomcat returned no body and the status is not OK,
2965                    let apache handle the error code */
2966 
2967                 if (!r->sent_bodyct && r->status >= HTTP_BAD_REQUEST) {
2968                     jk_log(xconf->log, JK_LOG_INFO, "No body with status=%d"
2969                            " for worker=%s",
2970                            r->status, worker_name);
2971                     JK_TRACE_EXIT(xconf->log);
2972                     return r->status;
2973                 }
2974                 if (JK_IS_DEBUG_LEVEL(xconf->log))
2975                     jk_log(xconf->log, JK_LOG_DEBUG, "Service finished"
2976                            " with status=%d for worker=%s",
2977                            r->status, worker_name);
2978                 JK_TRACE_EXIT(xconf->log);
2979                 return OK;      /* NOT r->status, even if it has changed. */
2980             }
2981             else if (rc == JK_CLIENT_ERROR) {
2982                 if (is_error != HTTP_REQUEST_ENTITY_TOO_LARGE)
2983                     r->connection->aborted = 1;
2984                 jk_log(xconf->log, JK_LOG_INFO, "Aborting connection"
2985                        " for worker=%s",
2986                        worker_name);
2987                 JK_TRACE_EXIT(xconf->log);
2988                 return is_error;
2989             }
2990             else {
2991                 jk_log(xconf->log, JK_LOG_INFO, "Service error=%d"
2992                        " for worker=%s",
2993                        rc, worker_name);
2994                 JK_TRACE_EXIT(xconf->log);
2995                 return is_error;
2996             }
2997         }
2998         else {
2999             jk_log(xconf->log, JK_LOG_INFO, "Could not find a worker"
3000                    " for worker name=%s",
3001                    worker_name);
3002             JK_TRACE_EXIT(xconf->log);
3003             return HTTP_INTERNAL_SERVER_ERROR;
3004         }
3005     }
3006 
3007     rconf->jk_handled = JK_FALSE;
3008     JK_TRACE_EXIT(xconf->log);
3009     return DECLINED;
3010 }
3011 
3012 /** Standard apache hook, cleanup jk
3013  */
jk_apr_pool_cleanup(void * data)3014 static apr_status_t jk_apr_pool_cleanup(void *data)
3015 {
3016     server_rec *s = data;
3017 
3018     if (jk_worker_properties) {
3019         jk_map_free(&jk_worker_properties);
3020         jk_worker_properties = NULL;
3021         jk_worker_file = NULL;
3022         jk_mount_copy_all = JK_FALSE;
3023     }
3024 
3025     while (NULL != s) {
3026         jk_server_conf_t *conf =
3027             (jk_server_conf_t *) ap_get_module_config(s->module_config,
3028                                                       &jk_module);
3029 
3030         if (conf && conf->was_initialized == JK_TRUE) {
3031             /* On pool cleanup pass NULL for the jk_logger to
3032                prevent segmentation faults on Windows because
3033                we can't guarantee what order pools get cleaned
3034                up between APR implementations. */
3035             wc_close(NULL);
3036             if (conf->uri_to_context) {
3037                 jk_map_free(&conf->uri_to_context);
3038                 /* We cannot have allocated uw_map
3039                  * unless we've allocated uri_to_context
3040                  */
3041                 if (conf->uw_map)
3042                     uri_worker_map_free(&conf->uw_map, NULL);
3043             }
3044             conf->was_initialized = JK_FALSE;
3045         }
3046         s = s->next;
3047     }
3048     return APR_SUCCESS;
3049 }
3050 
3051 /** Create default jk_config. XXX This is mostly server-independent,
3052     all servers are using something similar - should go to common.
3053  */
create_jk_config(apr_pool_t * p,server_rec * s)3054 static void *create_jk_config(apr_pool_t * p, server_rec * s)
3055 {
3056     jk_server_conf_t *c =
3057         (jk_server_conf_t *) apr_pcalloc(p, sizeof(jk_server_conf_t));
3058 
3059     c->was_initialized = JK_FALSE;
3060 
3061     if (s->is_virtual) {
3062         c->mountcopy = JK_UNSET;
3063         c->mount_file_reload = JK_UNSET;
3064         c->log_level = JK_UNSET;
3065         c->ssl_enable = JK_UNSET;
3066         c->strip_session = JK_UNSET;
3067     }
3068     else {
3069         if (!jk_map_alloc(&(c->uri_to_context))) {
3070             ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Memory error");
3071         }
3072         c->mountcopy = JK_FALSE;
3073         c->mount_file_reload = JK_URIMAP_DEF_RELOAD;
3074         c->log_level = JK_LOG_DEF_LEVEL;
3075         c->options = JK_OPT_DEFAULT;
3076         c->worker_indicator = JK_ENV_WORKER_NAME;
3077 
3078         /*
3079          * Configurable environment variables to overwrite
3080          * request information using meta data send by a
3081          * proxy in front of us.
3082          */
3083         c->remote_addr_indicator = JK_ENV_REMOTE_ADDR;
3084         c->remote_port_indicator = JK_ENV_REMOTE_PORT;
3085         c->remote_host_indicator = JK_ENV_REMOTE_HOST;
3086         c->remote_user_indicator = JK_ENV_REMOTE_USER;
3087         c->auth_type_indicator = JK_ENV_AUTH_TYPE;
3088         c->local_name_indicator = JK_ENV_LOCAL_NAME;
3089         c->local_addr_indicator = JK_ENV_LOCAL_ADDR;
3090         c->local_port_indicator = JK_ENV_LOCAL_PORT;
3091 
3092         c->ignore_cl_indicator = JK_ENV_IGNORE_CL;
3093 
3094         /*
3095          * By default we will try to gather SSL info.
3096          * Disable this functionality through JkExtractSSL
3097          */
3098         c->ssl_enable = JK_TRUE;
3099         /*
3100          * The defaults ssl indicators match those in mod_ssl (seems
3101          * to be in more use).
3102          */
3103         c->https_indicator = JK_ENV_HTTPS;
3104         c->ssl_protocol_indicator = JK_ENV_SSL_PROTOCOL;
3105         c->certs_indicator = JK_ENV_CERTS;
3106         c->cipher_indicator = JK_ENV_CIPHER;
3107         c->certchain_prefix = JK_ENV_CERTCHAIN_PREFIX;
3108         c->session_indicator = JK_ENV_SESSION;
3109         c->key_size_indicator = JK_ENV_KEY_SIZE;
3110         c->strip_session = JK_FALSE;
3111     }
3112     c->envvars_has_own = JK_FALSE;
3113 
3114     c->s = s;
3115     apr_pool_cleanup_register(p, s, jk_apr_pool_cleanup, apr_pool_cleanup_null);
3116     return c;
3117 }
3118 
3119 
3120 /*
3121  * Utility - copy items from apr table src to dst,
3122  * for keys that exist in src but not in dst.
3123  */
merge_apr_table(apr_table_t * src,apr_table_t * dst)3124 static void merge_apr_table(apr_table_t *src, apr_table_t *dst)
3125 {
3126     int i;
3127     const apr_array_header_t *arr;
3128     const apr_table_entry_t *elts;
3129 
3130     arr = apr_table_elts(src);
3131     elts = (const apr_table_entry_t *)arr->elts;
3132     for (i = 0; i < arr->nelts; ++i) {
3133         if (!apr_table_get(dst, elts[i].key)) {
3134             apr_table_setn(dst, elts[i].key, elts[i].val);
3135         }
3136     }
3137 }
3138 
3139 
3140 /** Standard apache callback, merge jk options specified in <Directory>
3141     context or <Host>.
3142  */
merge_jk_config(apr_pool_t * p,void * basev,void * overridesv)3143 static void *merge_jk_config(apr_pool_t * p, void *basev, void *overridesv)
3144 {
3145     jk_server_conf_t *base = (jk_server_conf_t *) basev;
3146     jk_server_conf_t *overrides = (jk_server_conf_t *) overridesv;
3147     int mask = 0;
3148 
3149     if (!overrides->log_file)
3150         overrides->log_file = base->log_file;
3151     if (overrides->log_level == JK_UNSET)
3152         overrides->log_level = base->log_level;
3153 
3154     if (!overrides->stamp_format_string)
3155         overrides->stamp_format_string = base->stamp_format_string;
3156     if (!overrides->format_string)
3157         overrides->format_string = base->format_string;
3158 
3159     if (!overrides->worker_indicator)
3160         overrides->worker_indicator = base->worker_indicator;
3161 
3162     if (!overrides->remote_addr_indicator)
3163         overrides->remote_addr_indicator = base->remote_addr_indicator;
3164     if (!overrides->remote_port_indicator)
3165         overrides->remote_port_indicator = base->remote_port_indicator;
3166     if (!overrides->remote_host_indicator)
3167         overrides->remote_host_indicator = base->remote_host_indicator;
3168     if (!overrides->remote_user_indicator)
3169         overrides->remote_user_indicator = base->remote_user_indicator;
3170     if (!overrides->auth_type_indicator)
3171         overrides->auth_type_indicator = base->auth_type_indicator;
3172     if (!overrides->local_name_indicator)
3173         overrides->local_name_indicator = base->local_name_indicator;
3174     if (!overrides->local_port_indicator)
3175         overrides->local_port_indicator = base->local_port_indicator;
3176 
3177     if (!overrides->ignore_cl_indicator)
3178         overrides->ignore_cl_indicator = base->ignore_cl_indicator;
3179 
3180     if (overrides->ssl_enable == JK_UNSET)
3181         overrides->ssl_enable = base->ssl_enable;
3182     if (!overrides->https_indicator)
3183         overrides->https_indicator = base->https_indicator;
3184     if (!overrides->ssl_protocol_indicator)
3185         overrides->ssl_protocol_indicator = base->ssl_protocol_indicator;
3186     if (!overrides->certs_indicator)
3187         overrides->certs_indicator = base->certs_indicator;
3188     if (!overrides->cipher_indicator)
3189         overrides->cipher_indicator = base->cipher_indicator;
3190     if (!overrides->certchain_prefix)
3191         overrides->certchain_prefix = base->certchain_prefix;
3192     if (!overrides->session_indicator)
3193         overrides->session_indicator = base->session_indicator;
3194     if (!overrides->key_size_indicator)
3195         overrides->key_size_indicator = base->key_size_indicator;
3196 
3197 /* Don't simply accumulate bits in the JK_OPT_FWDURIMASK or
3198  * JK_OPT_COLLAPSEMASK region, because those are multi-bit values. */
3199     if (overrides->options & JK_OPT_FWDURIMASK)
3200         mask |= JK_OPT_FWDURIMASK;
3201     if (overrides->options & JK_OPT_COLLAPSEMASK)
3202         mask |= JK_OPT_COLLAPSEMASK;
3203     overrides->options |= (base->options & ~base->exclude_options) & ~mask;
3204 
3205     if (base->envvars) {
3206         if (overrides->envvars && overrides->envvars_has_own) {
3207 /* merge_apr_table() preserves existing entries in overrides table */
3208             merge_apr_table(base->envvars, overrides->envvars);
3209             merge_apr_table(base->envvars_def, overrides->envvars_def);
3210         }
3211         else {
3212             overrides->envvars = base->envvars;
3213             overrides->envvars_def = base->envvars_def;
3214             overrides->envvar_items = base->envvar_items;
3215         }
3216     }
3217 
3218     if (overrides->mountcopy == JK_UNSET && jk_mount_copy_all == JK_TRUE) {
3219         overrides->mountcopy = JK_TRUE;
3220     }
3221     if (overrides->uri_to_context && overrides->mountcopy == JK_TRUE) {
3222 /* jk_map_copy() preserves existing entries in overrides map */
3223         if (jk_map_copy(base->uri_to_context, overrides->uri_to_context) == JK_FALSE) {
3224                 jk_error_exit(JKLOG_MARK, APLOG_EMERG, overrides->s, p, "Memory error");
3225         }
3226         if (!overrides->mount_file)
3227             overrides->mount_file = base->mount_file;
3228     }
3229     if (overrides->mountcopy == JK_TRUE) {
3230         if (!overrides->alias_dir)
3231             overrides->alias_dir = base->alias_dir;
3232     }
3233     if (overrides->mount_file_reload == JK_UNSET)
3234         overrides->mount_file_reload = base->mount_file_reload;
3235     if (overrides->strip_session == JK_UNSET) {
3236         overrides->strip_session = base->strip_session;
3237         overrides->strip_session_name = base->strip_session_name;
3238     }
3239     return overrides;
3240 }
3241 
jk_log_to_file(jk_logger_t * l,int level,int used,char * what)3242 static int JK_METHOD jk_log_to_file(jk_logger_t *l, int level,
3243                                     int used, char *what)
3244 {
3245     if (l &&
3246         (l->level <= level || level == JK_LOG_REQUEST_LEVEL) &&
3247         l->logger_private && what && used > 0) {
3248         jk_file_logger_t *p = l->logger_private;
3249         if (p->jklogfp) {
3250             apr_status_t rv;
3251             apr_size_t wrote;
3252 #if defined(WIN32)
3253             what[used++] = '\r';
3254 #endif
3255             what[used++] = '\n';
3256             wrote = used;
3257             rv = apr_global_mutex_lock(jk_log_lock);
3258             if (rv != APR_SUCCESS) {
3259                 ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
3260                              "apr_global_mutex_lock(jk_log_lock) failed");
3261                 /* XXX: Maybe this should be fatal? */
3262             }
3263             rv = apr_file_write(p->jklogfp, what, &wrote);
3264             if (rv != APR_SUCCESS) {
3265                 char error[256];
3266                 apr_strerror(rv, error, 254);
3267                 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
3268                              "mod_jk: jk_log_to_file %.*s failed: %s",
3269                              used, what, error);
3270             }
3271             rv = apr_global_mutex_unlock(jk_log_lock);
3272             if (rv != APR_SUCCESS) {
3273                 ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
3274                              "apr_global_mutex_unlock(jk_log_lock) failed");
3275                 /* XXX: Maybe this should be fatal? */
3276             }
3277         }
3278         else {
3279             /* Can't use mod_jk log any more, log to error log instead.
3280              * Choose APLOG_ERR, since we already checked above, that if
3281              * the mod_jk log file would still be open, we would have
3282              * actually logged the message there
3283              */
3284             ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
3285                          "%.*s", used, what);
3286         }
3287 
3288         return JK_TRUE;
3289     }
3290 
3291     return JK_FALSE;
3292 }
3293 
3294 /*
3295 ** +-------------------------------------------------------+
3296 ** |                                                       |
3297 ** |              jk logfile support                       |
3298 ** |                                                       |
3299 ** +-------------------------------------------------------+
3300 */
3301 
jklog_cleanup(void * d)3302 static apr_status_t jklog_cleanup(void *d)
3303 {
3304     /* hgomez@20070425 */
3305     /* Clean up pointer content */
3306     if (d != NULL)
3307         *(jk_logger_t **)d = NULL;
3308 
3309     return APR_SUCCESS;
3310 }
3311 
open_jklog(server_rec * s,apr_pool_t * p)3312 static int open_jklog(server_rec * s, apr_pool_t * p)
3313 {
3314     jk_server_conf_t *conf;
3315     const char *fname;
3316     apr_status_t rc;
3317     apr_file_t *jklogfp;
3318     piped_log *pl;
3319     jk_logger_t *jkl;
3320     jk_file_logger_t *flp;
3321     int jklog_flags = (APR_WRITE | APR_APPEND | APR_CREATE);
3322     apr_fileperms_t jklog_mode =
3323         (APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD);
3324 
3325     conf = ap_get_module_config(s->module_config, &jk_module);
3326 
3327     if (conf->log_file == NULL) {
3328         conf->log_file = ap_server_root_relative(p, JK_LOG_DEF_FILE);
3329         if (conf->log_file)
3330             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
3331                          "No JkLogFile defined in httpd.conf. "
3332                          "Using default %s", conf->log_file);
3333     }
3334     if (*(conf->log_file) == '\0') {
3335         ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
3336                      "mod_jk: Invalid JkLogFile EMPTY");
3337         conf->log = main_log;
3338         return 0;
3339     }
3340 
3341     jklogfp = apr_hash_get(jk_log_fps, conf->log_file, APR_HASH_KEY_STRING);
3342     if (!jklogfp) {
3343         if (*conf->log_file == '|') {
3344             if ((pl = ap_open_piped_log(p, conf->log_file + 1)) == NULL) {
3345                 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
3346                              "mod_jk: could not open reliable pipe "
3347                              "to jk log %s", conf->log_file + 1);
3348                 return -1;
3349             }
3350             jklogfp = (void *)ap_piped_log_write_fd(pl);
3351         }
3352         else {
3353             fname = ap_server_root_relative(p, conf->log_file);
3354             if (!fname) {
3355                 ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
3356                              "mod_jk: Invalid JkLog " "path %s", conf->log_file);
3357                 return -1;
3358             }
3359             if ((rc = apr_file_open(&jklogfp, fname,
3360                                     jklog_flags, jklog_mode, p))
3361                 != APR_SUCCESS) {
3362                 ap_log_error(APLOG_MARK, APLOG_ERR, rc, s,
3363                              "mod_jk: could not open JkLog " "file %s", fname);
3364                 return -1;
3365             }
3366         }
3367         apr_file_inherit_set(jklogfp);
3368         apr_hash_set(jk_log_fps, conf->log_file, APR_HASH_KEY_STRING, jklogfp);
3369     }
3370     jkl = (jk_logger_t *)apr_palloc(p, sizeof(jk_logger_t));
3371     flp = (jk_file_logger_t *) apr_palloc(p, sizeof(jk_file_logger_t));
3372     if (jkl && flp) {
3373         jkl->log = jk_log_to_file;
3374         jkl->level = conf->log_level;
3375         jkl->logger_private = flp;
3376         flp->jklogfp = jklogfp;
3377         if (*conf->log_file == '|')
3378             flp->is_piped = JK_TRUE;
3379         else
3380             flp->is_piped = JK_FALSE;
3381         conf->log = jkl;
3382         jk_set_time_fmt(conf->log, conf->stamp_format_string);
3383         if (main_log == NULL) {
3384             main_log = conf->log;
3385 
3386             /* hgomez@20070425 */
3387             /* Shouldn't we clean both conf->log and main_log ?                   */
3388             /* Also should we pass pointer (ie: main_log) or handle (*main_log) ? */
3389             apr_pool_cleanup_register(p, &main_log,
3390                                       jklog_cleanup,
3391                                       apr_pool_cleanup_null);
3392         }
3393 
3394         return 0;
3395     }
3396 
3397     return -1;
3398 }
3399 
3400 #if APR_HAS_THREADS
3401 
jk_watchdog_func(apr_thread_t * thd,void * data)3402 static void * APR_THREAD_FUNC jk_watchdog_func(apr_thread_t *thd, void *data)
3403 {
3404     int i;
3405     jk_server_conf_t *conf = (jk_server_conf_t *)data;
3406 
3407     if (JK_IS_DEBUG_LEVEL(conf->log))
3408         jk_log(conf->log, JK_LOG_DEBUG,
3409                "Watchdog thread initialized with %d second interval",
3410                jk_watchdog_interval);
3411     for (;;) {
3412         for (i = 0; i < (jk_watchdog_interval * 10); i++) {
3413             /* apr_sleep() uses microseconds */
3414             apr_sleep((apr_time_t)(100000));
3415             if (!jk_watchdog_interval)
3416                 break;
3417         }
3418         if (!jk_watchdog_interval)
3419             break;
3420         if (JK_IS_DEBUG_LEVEL(conf->log))
3421            jk_log(conf->log, JK_LOG_DEBUG,
3422                   "Watchdog thread running");
3423         jk_watchdog_running = 1;
3424         wc_maintain(conf->log);
3425         if (!jk_watchdog_interval)
3426             break;
3427     }
3428     jk_watchdog_running = 0;
3429     return NULL;
3430 }
3431 
3432 #endif
3433 
3434 /** Standard apache callback, initialize jk.
3435  */
jk_child_init(apr_pool_t * pconf,server_rec * s)3436 static void jk_child_init(apr_pool_t * pconf, server_rec * s)
3437 {
3438     jk_server_conf_t *conf;
3439     apr_status_t rv;
3440     int rc;
3441     apr_thread_t *wdt;
3442 
3443     conf = ap_get_module_config(s->module_config, &jk_module);
3444 
3445     rv = apr_global_mutex_child_init(&jk_log_lock, NULL, pconf);
3446     if (rv != APR_SUCCESS) {
3447         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
3448                      "mod_jk: could not init JK log lock in child");
3449     }
3450 
3451     JK_TRACE_ENTER(conf->log);
3452 
3453     if (jk_watchdog_interval) {
3454 #if APR_HAS_THREADS
3455         rv = apr_thread_create(&wdt, NULL, jk_watchdog_func, conf, pconf);
3456         if (rv != APR_SUCCESS) {
3457             jk_log(conf->log, JK_LOG_ERROR,
3458                    "Could not init watchdog thread, error=%d", rv);
3459             jk_watchdog_interval = 0;
3460         }
3461         apr_thread_detach(wdt);
3462 #endif
3463     }
3464 
3465     if ((rc = jk_shm_attach(jk_shm_file, jk_shm_size, conf->log)) == 0) {
3466         apr_pool_cleanup_register(pconf, conf->log, jk_cleanup_child,
3467                                   apr_pool_cleanup_null);
3468     }
3469     else {
3470         jk_log(conf->log, JK_LOG_ERROR, "Attaching shm:%s errno=%d",
3471                jk_shm_name(), rc);
3472     }
3473     if (JK_IS_DEBUG_LEVEL(conf->log))
3474         jk_log(conf->log, JK_LOG_DEBUG, "Initialized %s", JK_FULL_EXPOSED_VERSION);
3475     JK_TRACE_EXIT(conf->log);
3476 }
3477 
3478 /** Initialize jk, using worker.properties.
3479     We also use apache commands ( JkWorker, etc), but this use is
3480     deprecated, as we'll try to concentrate all config in
3481     workers.properties, urimap.properties, and ajp14 autoconf.
3482 
3483     Apache config will only be used for manual override, using
3484     SetHandler and normal apache directives ( but minimal jk-specific
3485     stuff )
3486 */
init_jk(apr_pool_t * pconf,jk_server_conf_t * conf,server_rec * s)3487 static int init_jk(apr_pool_t * pconf, jk_server_conf_t * conf,
3488                     server_rec * s)
3489 {
3490     int rc;
3491     int is_threaded;
3492     int mpm_threads = 1;
3493 
3494     if (!jk_worker_properties)
3495         jk_map_alloc(&jk_worker_properties);
3496     jk_map_put(jk_worker_properties, "ServerRoot", ap_server_root, NULL);
3497 
3498     /* Set default connection cache size for multi-threaded MPMs */
3499     if (ap_mpm_query(AP_MPMQ_IS_THREADED, &is_threaded) == APR_SUCCESS &&
3500         is_threaded != AP_MPMQ_NOT_SUPPORTED) {
3501         if (ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads) != APR_SUCCESS)
3502             mpm_threads = 1;
3503     }
3504     if (mpm_threads > 1) {
3505 #if _MT_CODE
3506         /* _MT_CODE  */
3507         if (JK_IS_DEBUG_LEVEL(conf->log)) {
3508 #if !defined(WIN32)
3509 #if USE_FLOCK_LK
3510             jk_log(conf->log, JK_LOG_DEBUG,
3511                    "Using flock() for locking.");
3512 #else
3513             jk_log(conf->log, JK_LOG_DEBUG,
3514                    "Using fcntl() for locking.");
3515 #endif /* USE_FLOCK_LK */
3516 #else  /* WIN32 */
3517             jk_log(conf->log, JK_LOG_DEBUG,
3518                    "Not using locking.");
3519 #endif
3520         }
3521 #else
3522         /* !_MT_CODE */
3523         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3524                      "Cannot run prefork mod_jk on threaded server.");
3525         return JK_FALSE;
3526 #endif
3527     }
3528     if (JK_IS_DEBUG_LEVEL(conf->log))
3529         jk_log(conf->log, JK_LOG_DEBUG,
3530                "Setting default connection pool max size to %d",
3531                mpm_threads);
3532     jk_set_worker_def_cache_size(mpm_threads);
3533 
3534     if ((jk_worker_file != NULL) &&
3535         !jk_map_read_properties(jk_worker_properties, NULL, jk_worker_file, NULL,
3536                                 JK_MAP_HANDLE_DUPLICATES, conf->log)) {
3537         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3538                      "Error in reading worker properties from '%s'",
3539                      jk_worker_file);
3540         return JK_FALSE;
3541     }
3542 
3543     if (jk_map_resolve_references(jk_worker_properties, "worker.",
3544                                   1, 1, conf->log) == JK_FALSE) {
3545         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3546                      "Error in resolving configuration references");
3547         return JK_FALSE;
3548     }
3549 
3550 #if !defined(WIN32)
3551     if (!jk_shm_file) {
3552         jk_shm_file = ap_server_root_relative(pconf, JK_SHM_DEF_FILE);
3553         if (jk_shm_file)
3554             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
3555                          "No JkShmFile defined in httpd.conf. "
3556                          "Using default %s", jk_shm_file);
3557     }
3558 #endif
3559     if (jk_shm_size == 0) {
3560         jk_shm_size = jk_shm_calculate_size(jk_worker_properties, conf->log);
3561     }
3562     else if (jk_shm_size_set) {
3563         jk_log(conf->log, JK_LOG_WARNING,
3564                "The optimal shared memory size can now be determined automatically.");
3565         jk_log(conf->log, JK_LOG_WARNING,
3566                "You can remove the JkShmSize directive if you want to use the optimal size.");
3567     }
3568     if ((rc = jk_shm_open(jk_shm_file, jk_shm_size, conf->log)) == 0) {
3569         apr_pool_cleanup_register(pconf, conf->log,
3570                                   jk_cleanup_proc,
3571                                   apr_pool_cleanup_null);
3572     }
3573     else {
3574         jk_error_exit(JKLOG_MARK, APLOG_EMERG, s, s->process->pool,
3575                       "Initializing shm:%s errno=%d. Unable to start due to shared memory failure.",
3576                       jk_shm_name(), rc);
3577     }
3578     /* we add the URI->WORKER MAP since workers using AJP14
3579        will feed it */
3580     worker_env.uri_to_worker = conf->uw_map;
3581     worker_env.virtual = "*";   /* for now */
3582 #if ((AP_MODULE_MAGIC_AT_LEAST(20051115,4)) && !defined(API_COMPATIBILITY)) || (MODULE_MAGIC_NUMBER_MAJOR >= 20060905)
3583     worker_env.server_name = (char *)ap_get_server_description();
3584 #else
3585     worker_env.server_name = (char *)ap_get_server_version();
3586 #endif
3587     worker_env.pool = pconf;
3588 
3589     if (wc_open(jk_worker_properties, &worker_env, conf->log)) {
3590         ap_add_version_component(pconf, JK_EXPOSED_VERSION);
3591         jk_log(conf->log, JK_LOG_INFO,
3592                "%s initialized",
3593                JK_FULL_EXPOSED_VERSION);
3594     }
3595     else {
3596         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3597                      "Error in creating the workers."
3598                      " Please consult your mod_jk log file '%s'.", conf->log_file);
3599         return JK_FALSE;
3600     }
3601     return JK_TRUE;
3602 }
3603 
jk_post_config(apr_pool_t * pconf,apr_pool_t * plog,apr_pool_t * ptemp,server_rec * s)3604 static int jk_post_config(apr_pool_t * pconf,
3605                           apr_pool_t * plog,
3606                           apr_pool_t * ptemp, server_rec * s)
3607 {
3608     apr_status_t rv;
3609     jk_server_conf_t *conf;
3610     server_rec *srv = s;
3611     const char *err_string = NULL;
3612     int remain;
3613     void *data = NULL;
3614 
3615     remain = jk_check_buffer_size();
3616     if (remain < 0) {
3617         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
3618                      "mod_jk: JK_MAX_ATTRIBUTE_NAME_LEN in jk_util.c is too small, "
3619                      "increase by %d", -1 * remain);
3620         return HTTP_INTERNAL_SERVER_ERROR;
3621     }
3622     apr_pool_userdata_get(&data, JK_LOG_LOCK_KEY, s->process->pool);
3623     if (data == NULL) {
3624         /* create the jk log lockfiles in the parent */
3625         if ((rv = apr_global_mutex_create(&jk_log_lock, NULL,
3626                                           APR_LOCK_DEFAULT,
3627                                           s->process->pool)) != APR_SUCCESS) {
3628             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
3629                          "mod_jk: could not create jk_log_lock");
3630             return HTTP_INTERNAL_SERVER_ERROR;
3631         }
3632 
3633 #if JK_NEED_SET_MUTEX_PERMS
3634 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20090208)
3635         rv = ap_unixd_set_global_mutex_perms(jk_log_lock);
3636 #else
3637         rv = unixd_set_global_mutex_perms(jk_log_lock);
3638 #endif
3639         if (rv != APR_SUCCESS) {
3640             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
3641                          "mod_jk: Could not set permissions on "
3642                          "jk_log_lock; check User and Group directives");
3643             return HTTP_INTERNAL_SERVER_ERROR;
3644         }
3645 #endif
3646         apr_pool_userdata_set((const void *)jk_log_lock, JK_LOG_LOCK_KEY,
3647                               apr_pool_cleanup_null, s->process->pool);
3648     }
3649     else {
3650         jk_log_lock = (apr_global_mutex_t *)data;
3651     }
3652 
3653     main_server = s;
3654     jk_log_fps = apr_hash_make(pconf);
3655 
3656     if (!s->is_virtual) {
3657         conf = (jk_server_conf_t *)ap_get_module_config(s->module_config,
3658                                                         &jk_module);
3659         if (conf->was_initialized == JK_FALSE) {
3660             /* step through the servers and open each jk logfile
3661              * and do additional post config initialization.
3662              */
3663             for (; srv; srv = srv->next) {
3664                 jk_server_conf_t *sconf = (jk_server_conf_t *)ap_get_module_config(srv->module_config,
3665                                                                                    &jk_module);
3666 
3667 /*
3668  * If a virtual server contains no JK directive, httpd shares
3669  * the config structure. But we don't want to share some settings
3670  * by default, especially the JkMount rules.
3671  * Therefore we check, if this config structure really belongs to this
3672  * vhost, otherwise we create a new one and merge.
3673  */
3674                 if (sconf && sconf->s != srv) {
3675                     jk_server_conf_t *srvconf = (jk_server_conf_t *)create_jk_config(pconf, srv);
3676                     sconf = (jk_server_conf_t *)merge_jk_config(pconf, sconf, srvconf);
3677                     ap_set_module_config(srv->module_config, &jk_module, sconf);
3678                 }
3679 
3680                 if (sconf && sconf->was_initialized == JK_FALSE) {
3681                     sconf->was_initialized = JK_TRUE;
3682                     if (open_jklog(srv, pconf))
3683                         return HTTP_INTERNAL_SERVER_ERROR;
3684                     sconf->options &= ~sconf->exclude_options;
3685                     dump_options(srv, pconf);
3686                     if (sconf->uri_to_context) {
3687                         if (!uri_worker_map_alloc(&(sconf->uw_map),
3688                                                   sconf->uri_to_context, sconf->log))
3689                             jk_error_exit(JKLOG_MARK, APLOG_EMERG, srv,
3690                                           srv->process->pool, "Memory error");
3691                         if (sconf->options & JK_OPT_REJECTUNSAFE)
3692                             sconf->uw_map->reject_unsafe = 1;
3693                         else
3694                             sconf->uw_map->reject_unsafe = 0;
3695                         if (sconf->mount_file) {
3696                             sconf->uw_map->fname = sconf->mount_file;
3697                             sconf->uw_map->reload = sconf->mount_file_reload;
3698                             uri_worker_map_switch(sconf->uw_map, sconf->log);
3699                             uri_worker_map_load(sconf->uw_map, sconf->log);
3700                         }
3701                         if (sconf->options & JK_OPT_COLLAPSEMASK) {
3702                             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
3703                                          "Deprecated CollapseSlashes setting ignored");
3704                         }
3705                     }
3706                     else {
3707                         if (sconf->mountcopy == JK_TRUE) {
3708                             sconf->uw_map = conf->uw_map;
3709                         }
3710                     }
3711                     if (sconf->format_string) {
3712                         sconf->format =
3713                             parse_request_log_string(pconf, sconf->format_string, &err_string);
3714                         if (sconf->format == NULL)
3715                             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
3716                                          "JkRequestLogFormat format array NULL");
3717                     }
3718                     if (sconf->envvars && sconf->envvars_has_own) {
3719                         int i;
3720                         const apr_array_header_t *arr;
3721                         const apr_table_entry_t *elts;
3722                         envvar_item *item;
3723                         const char *envvar_def;
3724 
3725                         arr = apr_table_elts(sconf->envvars);
3726                         if (arr) {
3727                             elts = (const apr_table_entry_t *)arr->elts;
3728                             for (i = 0; i < arr->nelts; ++i) {
3729                                 item = (envvar_item *)apr_array_push(sconf->envvar_items);
3730                                 if (!item)
3731                                     return HTTP_INTERNAL_SERVER_ERROR;
3732                                 item->name = elts[i].key;
3733                                 envvar_def = apr_table_get(sconf->envvars_def, elts[i].key);
3734                                 if (envvar_def && !strcmp("1", envvar_def) ) {
3735                                     item->value = elts[i].val;
3736                                     item->has_default = 1;
3737                                 }
3738                                 else {
3739                                     item->value = "";
3740                                     item->has_default = 0;
3741                                 }
3742                             }
3743                         }
3744                     }
3745                 }
3746             }
3747             conf->was_initialized = JK_TRUE;
3748             if (init_jk(pconf, conf, s) == JK_FALSE)
3749                 return HTTP_INTERNAL_SERVER_ERROR;
3750             if (conf->uw_map) {
3751                 uri_worker_map_ext(conf->uw_map, conf->log);
3752                 uri_worker_map_switch(conf->uw_map, conf->log);
3753             }
3754             for (srv = s; srv; srv = srv->next) {
3755                 jk_server_conf_t *sconf = (jk_server_conf_t *)ap_get_module_config(srv->module_config,
3756                                                                                    &jk_module);
3757                 if (conf->uw_map != sconf->uw_map && sconf->uw_map) {
3758                     uri_worker_map_ext(sconf->uw_map, sconf->log);
3759                     uri_worker_map_switch(sconf->uw_map, sconf->log);
3760                 }
3761             }
3762 
3763         }
3764     }
3765 
3766     return OK;
3767 }
3768 
3769 /** Use the internal mod_jk mappings to find if this is a request for
3770  *    tomcat and what worker to use.
3771  */
jk_translate(request_rec * r)3772 static int jk_translate(request_rec * r)
3773 {
3774     jk_request_conf_t *rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t));
3775     rconf->jk_handled = JK_FALSE;
3776     rconf->rule_extensions = NULL;
3777     rconf->orig_uri = NULL;
3778     ap_set_module_config(r->request_config, &jk_module, rconf);
3779 
3780     if (!r->proxyreq) {
3781         jk_server_conf_t *conf =
3782             (jk_server_conf_t *) ap_get_module_config(r->server->
3783                                                       module_config,
3784                                                       &jk_module);
3785 
3786         if (conf) {
3787             char *clean_uri;
3788             int rc;
3789             const char *worker;
3790 
3791             JK_TRACE_ENTER(conf->log);
3792 
3793             if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) {
3794                 /* Somebody already set the handler, probably manual config
3795                  * or "native" configuration, no need for extra overhead
3796                  */
3797                 if (JK_IS_DEBUG_LEVEL(conf->log))
3798                     jk_log(conf->log, JK_LOG_DEBUG,
3799                            "Manually mapped, no need to call uri_to_worker");
3800                 JK_TRACE_EXIT(conf->log);
3801                 return DECLINED;
3802             }
3803 
3804             if (apr_table_get(r->subprocess_env, "no-jk")) {
3805                 if (JK_IS_DEBUG_LEVEL(conf->log))
3806                     jk_log(conf->log, JK_LOG_DEBUG,
3807                            "Into translate no-jk env var detected for uri=%s, declined",
3808                            r->uri);
3809 
3810                 JK_TRACE_EXIT(conf->log);
3811                 return DECLINED;
3812             }
3813 
3814             clean_uri = apr_pstrdup(r->pool, r->uri);
3815             rc = jk_servlet_normalize(clean_uri, conf->log);
3816             if (rc != 0) {
3817                 JK_TRACE_EXIT(conf->log);
3818                 return HTTP_BAD_REQUEST;
3819             }
3820 
3821             /* Special case to make sure that apache can serve a directory
3822                listing if there are no matches for the DirectoryIndex and
3823                Tomcat webapps are mapped into apache using JkAutoAlias. */
3824             if (r->main != NULL && r->main->handler != NULL &&
3825                 (conf->alias_dir != NULL) &&
3826                 !strcmp(r->main->handler, DIR_MAGIC_TYPE)) {
3827 
3828                 /* Append the request uri to the JkAutoAlias directory and
3829                    determine if the file exists. */
3830                 apr_finfo_t finfo;
3831                 finfo.filetype = APR_NOFILE;
3832                 /* Map uri to a context static file */
3833                 if (strlen(clean_uri) > 1) {
3834                     char *context_path = NULL;
3835 
3836                     context_path = apr_pstrcat(r->pool, conf->alias_dir, clean_uri, NULL);
3837                     if (context_path != NULL) {
3838                         apr_stat(&finfo, context_path, APR_FINFO_TYPE,
3839                                  r->pool);
3840                     }
3841                 }
3842                 if (finfo.filetype != APR_REG) {
3843                     if (JK_IS_DEBUG_LEVEL(conf->log))
3844                         jk_log(conf->log, JK_LOG_DEBUG,
3845                                "JkAutoAlias, no DirectoryIndex file for URI %s",
3846                                r->uri);
3847                     JK_TRACE_EXIT(conf->log);
3848                     return DECLINED;
3849                 }
3850             }
3851             if (!conf->uw_map) {
3852                 if (JK_IS_DEBUG_LEVEL(conf->log))
3853                     jk_log(conf->log, JK_LOG_DEBUG,
3854                            "missing uri map for %s:%s",
3855                            conf->s->server_hostname ? conf->s->server_hostname : "_default_",
3856                            r->uri);
3857                 JK_TRACE_EXIT(conf->log);
3858                 return DECLINED;
3859             }
3860             else {
3861                 rule_extension_t *e;
3862                 worker = map_uri_to_worker_ext(conf->uw_map, clean_uri,
3863                                                NULL, &e, NULL, conf->log);
3864                 if (worker) {
3865                     rconf->rule_extensions = e;
3866                     rconf->orig_uri = r->uri;
3867                     r->uri = clean_uri;
3868                 }
3869             }
3870 
3871             if (worker) {
3872                 r->handler = apr_pstrdup(r->pool, JK_HANDLER);
3873                 apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker);
3874 
3875                 /* This could be a sub-request, possibly from mod_dir */
3876                 /* Also add the the HANDLER to the main request */
3877                 if (r->main) {
3878                     r->main->handler = apr_pstrdup(r->main->pool, JK_HANDLER);
3879                     apr_table_setn(r->main->notes, JK_NOTE_WORKER_NAME, worker);
3880                 }
3881 
3882                 JK_TRACE_EXIT(conf->log);
3883                 return OK;
3884             }
3885             else if (conf->alias_dir != NULL) {
3886                 /* Automatically map uri to a context static file */
3887                 if (JK_IS_DEBUG_LEVEL(conf->log))
3888                     jk_log(conf->log, JK_LOG_DEBUG,
3889                            "check alias_dir: %s",
3890                            conf->alias_dir);
3891                 if (strlen(clean_uri) > 1) {
3892                     /* Get the context directory name */
3893                     char *context_dir = NULL;
3894                     char *context_path = NULL;
3895                     char *child_dir = NULL;
3896                     char *index = clean_uri;
3897                     char *suffix = strchr(index + 1, '/');
3898                     if (suffix != NULL) {
3899                         int size = (int)(suffix - index);
3900                         context_dir = apr_pstrndup(r->pool, index, size);
3901                         /* Get the context child directory name */
3902                         index = index + size + 1;
3903                         suffix = strchr(index, '/');
3904                         if (suffix != NULL) {
3905                             size = (int)(suffix - index);
3906                             child_dir = apr_pstrndup(r->pool, index, size);
3907                         }
3908                         else {
3909                             child_dir = index;
3910                         }
3911                         /* Deny access to WEB-INF and META-INF directories */
3912                         if (child_dir != NULL) {
3913                             if (JK_IS_DEBUG_LEVEL(conf->log))
3914                                 jk_log(conf->log, JK_LOG_DEBUG,
3915                                        "AutoAlias child_dir: %s",
3916                                        child_dir);
3917                             if (!strcasecmp(child_dir, "WEB-INF")
3918                                 || !strcasecmp(child_dir, "META-INF")) {
3919                                 if (JK_IS_DEBUG_LEVEL(conf->log))
3920                                     jk_log(conf->log, JK_LOG_DEBUG,
3921                                            "AutoAlias HTTP_NOT_FOUND for URI: %s",
3922                                            r->uri);
3923                                 JK_TRACE_EXIT(conf->log);
3924                                 return HTTP_NOT_FOUND;
3925                             }
3926                         }
3927                     }
3928                     else {
3929                         context_dir = apr_pstrdup(r->pool, index);
3930                     }
3931 
3932                     context_path = apr_pstrcat(r->pool, conf->alias_dir, context_dir, NULL);
3933                     if (context_path != NULL) {
3934                         apr_finfo_t finfo;
3935                         finfo.filetype = APR_NOFILE;
3936                         apr_stat(&finfo, context_path, APR_FINFO_TYPE,
3937                                  r->pool);
3938                         if (finfo.filetype == APR_DIR) {
3939                             char *ret = apr_pstrcat(r->pool, conf->alias_dir, clean_uri, NULL);
3940                             /* Add code to verify real path ap_os_canonical_name */
3941                             if (ret != NULL) {
3942                                 if (JK_IS_DEBUG_LEVEL(conf->log))
3943                                     jk_log(conf->log, JK_LOG_DEBUG,
3944                                            "AutoAlias OK for file: %s",
3945                                            ret);
3946                                 r->filename = ret;
3947                                 JK_TRACE_EXIT(conf->log);
3948                                 return OK;
3949                             }
3950                         }
3951                         else {
3952                             /* Deny access to war files in web app directory */
3953                             int size = (int)strlen(context_dir);
3954                             if (size > 4
3955                                 && !strcasecmp(context_dir + (size - 4),
3956                                                ".war")) {
3957                                 if (JK_IS_DEBUG_LEVEL(conf->log))
3958                                     jk_log(conf->log, JK_LOG_DEBUG,
3959                                            "AutoAlias HTTP_FORBIDDEN for URI: %s",
3960                                            r->uri);
3961                                 JK_TRACE_EXIT(conf->log);
3962                                 return HTTP_FORBIDDEN;
3963                             }
3964                         }
3965                     }
3966                 }
3967             }
3968             else {
3969                 if (JK_IS_DEBUG_LEVEL(conf->log))
3970                     jk_log(conf->log, JK_LOG_DEBUG,
3971                            "no match for %s found",
3972                            r->uri);
3973             }
3974         }
3975     }
3976 
3977     return DECLINED;
3978 }
3979 
3980 /* bypass the directory_walk and file_walk for non-file requests */
jk_map_to_storage(request_rec * r)3981 static int jk_map_to_storage(request_rec * r)
3982 {
3983 
3984     jk_request_conf_t *rconf = ap_get_module_config(r->request_config, &jk_module);
3985     if (rconf == NULL) {
3986         rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t));
3987         rconf->jk_handled = JK_FALSE;
3988         rconf->rule_extensions = NULL;
3989         rconf->orig_uri = NULL;
3990         ap_set_module_config(r->request_config, &jk_module, rconf);
3991     }
3992 
3993     if (!r->proxyreq && !apr_table_get(r->notes, JK_NOTE_WORKER_NAME)) {
3994         jk_server_conf_t *conf =
3995             (jk_server_conf_t *) ap_get_module_config(r->server->
3996                                                       module_config,
3997                                                       &jk_module);
3998 
3999         if (conf) {
4000             char *clean_uri;
4001             int rc;
4002             const char *worker;
4003 
4004             JK_TRACE_ENTER(conf->log);
4005 
4006             if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) {
4007                 /* Somebody already set the handler, probably manual config
4008                  * or "native" configuration, no need for extra overhead
4009                  */
4010                 if (JK_IS_DEBUG_LEVEL(conf->log))
4011                     jk_log(conf->log, JK_LOG_DEBUG,
4012                            "Manually mapped, no need to call uri_to_worker");
4013                 JK_TRACE_EXIT(conf->log);
4014                 return DECLINED;
4015             }
4016 
4017             if (apr_table_get(r->subprocess_env, "no-jk")) {
4018                 if (JK_IS_DEBUG_LEVEL(conf->log))
4019                     jk_log(conf->log, JK_LOG_DEBUG,
4020                            "Into map_to_storage no-jk env var detected for uri=%s, declined",
4021                            r->uri);
4022 
4023                 JK_TRACE_EXIT(conf->log);
4024                 return DECLINED;
4025             }
4026 
4027             // Not a URI based request - e.g. file based SSI include
4028             if (strlen(r->uri) == 0) {
4029                 jk_log(conf->log, JK_LOG_DEBUG,
4030                        "File based (sub-)request for file=%s. No URI to match.",
4031 					   r->filename);
4032                 JK_TRACE_EXIT(conf->log);
4033                 return DECLINED;
4034             }
4035 
4036             clean_uri = apr_pstrdup(r->pool, r->uri);
4037             rc = jk_servlet_normalize(clean_uri, conf->log);
4038             if (rc != 0) {
4039                 JK_TRACE_EXIT(conf->log);
4040                 return HTTP_BAD_REQUEST;
4041             }
4042 
4043             if (!conf->uw_map) {
4044                 if (JK_IS_DEBUG_LEVEL(conf->log))
4045                     jk_log(conf->log, JK_LOG_DEBUG,
4046                            "missing uri map for %s:%s",
4047                            conf->s->server_hostname ? conf->s->server_hostname : "_default_",
4048                            r->uri);
4049                 JK_TRACE_EXIT(conf->log);
4050                 return DECLINED;
4051             }
4052             else {
4053                 rule_extension_t *e;
4054                 worker = map_uri_to_worker_ext(conf->uw_map, clean_uri,
4055                                                NULL, &e, NULL, conf->log);
4056                 if (worker) {
4057                     rconf->rule_extensions = e;
4058                     rconf->orig_uri = r->uri;
4059                     r->uri = clean_uri;
4060                 }
4061             }
4062 
4063             if (worker) {
4064                 r->handler = apr_pstrdup(r->pool, JK_HANDLER);
4065                 apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker);
4066 
4067                 /* This could be a sub-request, possibly from mod_dir */
4068                 if (r->main)
4069                     apr_table_setn(r->main->notes, JK_NOTE_WORKER_NAME, worker);
4070 
4071             }
4072             else {
4073                 if (JK_IS_DEBUG_LEVEL(conf->log))
4074                     jk_log(conf->log, JK_LOG_DEBUG,
4075                            "no match for %s found",
4076                            r->uri);
4077                 if (conf->strip_session == JK_TRUE && conf->strip_session_name) {
4078                     if (r->uri) {
4079                         jk_strip_session_id(r->uri, conf->strip_session_name, conf->log);
4080                     }
4081                     if (r->filename) {
4082                         jk_strip_session_id(r->filename, conf->strip_session_name, conf->log);
4083                     }
4084                     JK_TRACE_EXIT(conf->log);
4085                     return DECLINED;
4086                 }
4087             }
4088 		JK_TRACE_EXIT(conf->log);
4089         }
4090     }
4091 
4092     if (apr_table_get(r->notes, JK_NOTE_WORKER_NAME)) {
4093 
4094         /* First find just the name of the file, no directory */
4095         r->filename = (char *)apr_filepath_name_get(r->uri);
4096 
4097         /* Only if sub-request for a directory, most likely from mod_dir */
4098         if (r->main && r->main->filename &&
4099             (!apr_filepath_name_get(r->main->filename) ||
4100              !strlen(apr_filepath_name_get(r->main->filename)))) {
4101 
4102             /* The filename from the main request will be set to what should
4103              * be picked up, aliases included. Tomcat will need to know about
4104              * those aliases or things won't work for them. Normal files should
4105              * be fine. */
4106 
4107             /* Need absolute path to stat */
4108             if (apr_filepath_merge(&r->filename,
4109                                    r->main->filename, r->filename,
4110                                    APR_FILEPATH_SECUREROOT |
4111                                    APR_FILEPATH_TRUENAME, r->pool)
4112                 != APR_SUCCESS) {
4113                 return DECLINED;        /* We should never get here, very bad */
4114             }
4115 
4116             /* Stat the file so that mod_dir knows it's there */
4117             apr_stat(&r->finfo, r->filename, APR_FINFO_TYPE, r->pool);
4118         }
4119 
4120         return OK;
4121     }
4122     return DECLINED;
4123 }
4124 
jk_register_hooks(apr_pool_t * p)4125 static void jk_register_hooks(apr_pool_t * p)
4126 {
4127     ap_hook_post_config(jk_post_config, NULL, NULL, APR_HOOK_MIDDLE);
4128     ap_hook_child_init(jk_child_init, NULL, NULL, APR_HOOK_MIDDLE);
4129     ap_hook_translate_name(jk_translate, NULL, NULL, APR_HOOK_MIDDLE);
4130     ap_hook_map_to_storage(jk_map_to_storage, NULL, NULL, APR_HOOK_MIDDLE);
4131     ap_hook_handler(jk_handler, NULL, NULL, APR_HOOK_MIDDLE);
4132     ap_hook_log_transaction(request_log_transaction, NULL, NULL, APR_HOOK_MIDDLE);
4133 }
4134 
4135 module AP_MODULE_DECLARE_DATA jk_module = {
4136     STANDARD20_MODULE_STUFF,
4137     NULL,                       /* dir config creater */
4138     NULL,                       /* dir merger --- default is to override */
4139     create_jk_config,           /* server config */
4140     merge_jk_config,            /* merge server config */
4141     jk_cmds,                    /* command ap_table_t */
4142     jk_register_hooks           /* register hooks */
4143 };
4144