1 #include "base.h"
2 #include "buffer.h"
3 #include "array.h"
4 #include "log.h"
5 #include "plugin.h"
6
7 #include "configfile.h"
8
9 #include <string.h>
10 #include <stdlib.h>
11
12 /**
13 * like all glue code this file contains functions which
14 * are the external interface of lighttpd. The functions
15 * are used by the server itself and the plugins.
16 *
17 * The main-goal is to have a small library in the end
18 * which is linked against both and which will define
19 * the interface itself in the end.
20 *
21 */
22
23
24 /* handle global options */
25
26 /* parse config array */
config_insert_values_internal(server * srv,array * ca,const config_values_t cv[])27 int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
28 size_t i;
29 data_unset *du;
30
31 for (i = 0; cv[i].key; i++) {
32
33 if (NULL == (du = array_get_element(ca, cv[i].key))) {
34 /* no found */
35
36 continue;
37 }
38
39 switch (cv[i].type) {
40 case T_CONFIG_ARRAY:
41 if (du->type == TYPE_ARRAY) {
42 size_t j;
43 data_array *da = (data_array *)du;
44
45 for (j = 0; j < da->value->used; j++) {
46 if (da->value->data[j]->type == TYPE_STRING) {
47 data_string *ds = data_string_init();
48
49 buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
50 if (!da->is_index_key) {
51 /* the id's were generated automaticly, as we copy now we might have to renumber them
52 * this is used to prepend server.modules by mod_indexfile as it has to be loaded
53 * before mod_fastcgi and friends */
54 buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
55 }
56
57 array_insert_unique(cv[i].destination, (data_unset *)ds);
58 } else {
59 log_error_write(srv, __FILE__, __LINE__, "sssd",
60 "the key of an array can only be a string or a integer, variable:",
61 cv[i].key, "type:", da->value->data[j]->type);
62
63 return -1;
64 }
65 }
66 } else {
67 log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )");
68
69 return -1;
70 }
71 break;
72 case T_CONFIG_STRING:
73 if (du->type == TYPE_STRING) {
74 data_string *ds = (data_string *)du;
75
76 buffer_copy_string_buffer(cv[i].destination, ds->value);
77 } else {
78 log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\"");
79
80 return -1;
81 }
82 break;
83 case T_CONFIG_SHORT:
84 switch(du->type) {
85 case TYPE_INTEGER: {
86 data_integer *di = (data_integer *)du;
87
88 *((unsigned short *)(cv[i].destination)) = di->value;
89 break;
90 }
91 case TYPE_STRING: {
92 data_string *ds = (data_string *)du;
93
94 /* If the value came from an environment variable, then it is a
95 * data_string, although it may contain a number in ASCII
96 * decimal format. We try to interpret the string as a decimal
97 * short before giving up, in order to support setting numeric
98 * values with environment variables (eg, port number).
99 */
100 if (ds->value->ptr && *ds->value->ptr) {
101 char *e;
102 long l = strtol(ds->value->ptr, &e, 10);
103 if (e != ds->value->ptr && !*e && l >=0 && l <= 65535) {
104 *((unsigned short *)(cv[i].destination)) = l;
105 break;
106 }
107 }
108
109 log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value);
110
111 return -1;
112 }
113 default:
114 log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected a short integer, range 0 ... 65535");
115 return -1;
116 }
117 break;
118 case T_CONFIG_INT:
119 switch(du->type) {
120 case TYPE_INTEGER: {
121 data_integer *di = (data_integer *)du;
122
123 *((unsigned int *)(cv[i].destination)) = di->value;
124 break;
125 }
126 case TYPE_STRING: {
127 data_string *ds = (data_string *)du;
128
129 if (ds->value->ptr && *ds->value->ptr) {
130 char *e;
131 long l = strtol(ds->value->ptr, &e, 10);
132 if (e != ds->value->ptr && !*e && l >= 0) {
133 *((unsigned int *)(cv[i].destination)) = l;
134 break;
135 }
136 }
137
138
139 log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected an integer:", cv[i].key, ds->value);
140
141 return -1;
142 }
143 default:
144 log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected an integer, range 0 ... 4294967295");
145 return -1;
146 }
147 break;
148 case T_CONFIG_BOOLEAN:
149 if (du->type == TYPE_STRING) {
150 data_string *ds = (data_string *)du;
151
152 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
153 *((unsigned short *)(cv[i].destination)) = 1;
154 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
155 *((unsigned short *)(cv[i].destination)) = 0;
156 } else {
157 log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
158
159 return -1;
160 }
161 } else {
162 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
163
164 return -1;
165 }
166 break;
167 case T_CONFIG_LOCAL:
168 case T_CONFIG_UNSET:
169 break;
170 case T_CONFIG_UNSUPPORTED:
171 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination));
172
173 srv->config_unsupported = 1;
174
175 break;
176 case T_CONFIG_DEPRECATED:
177 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
178
179 srv->config_deprecated = 1;
180
181 break;
182 }
183 }
184
185 return 0;
186 }
187
config_insert_values_global(server * srv,array * ca,const config_values_t cv[])188 int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
189 size_t i;
190 data_unset *du;
191
192 for (i = 0; cv[i].key; i++) {
193 data_string *touched;
194
195 if (NULL == (du = array_get_element(ca, cv[i].key))) {
196 /* no found */
197
198 continue;
199 }
200
201 /* touched */
202 touched = data_string_init();
203
204 buffer_copy_string_len(touched->value, CONST_STR_LEN(""));
205 buffer_copy_string_buffer(touched->key, du->key);
206
207 array_insert_unique(srv->config_touched, (data_unset *)touched);
208 }
209
210 return config_insert_values_internal(srv, ca, cv);
211 }
212
sock_addr_get_port(sock_addr * addr)213 static unsigned short sock_addr_get_port(sock_addr *addr) {
214 #ifdef HAVE_IPV6
215 return ntohs(addr->plain.sa_family ? addr->ipv6.sin6_port : addr->ipv4.sin_port);
216 #else
217 return ntohs(addr->ipv4.sin_port);
218 #endif
219 }
220
221 static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc);
222
config_check_cond_nocache(server * srv,connection * con,data_config * dc)223 static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
224 buffer *l;
225 server_socket *srv_sock = con->srv_socket;
226
227 /* check parent first */
228 if (dc->parent && dc->parent->context_ndx) {
229 /**
230 * a nested conditional
231 *
232 * if the parent is not decided yet or false, we can't be true either
233 */
234 if (con->conf.log_condition_handling) {
235 log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->key);
236 }
237
238 switch (config_check_cond_cached(srv, con, dc->parent)) {
239 case COND_RESULT_FALSE:
240 return COND_RESULT_FALSE;
241 case COND_RESULT_UNSET:
242 return COND_RESULT_UNSET;
243 default:
244 break;
245 }
246 }
247
248 if (dc->prev) {
249 /**
250 * a else branch
251 *
252 * we can only be executed, if all of our previous brothers
253 * are false
254 */
255 if (con->conf.log_condition_handling) {
256 log_error_write(srv, __FILE__, __LINE__, "sb", "go prev", dc->prev->key);
257 }
258
259 /* make sure prev is checked first */
260 config_check_cond_cached(srv, con, dc->prev);
261
262 /* one of prev set me to FALSE */
263 switch (con->cond_cache[dc->context_ndx].result) {
264 case COND_RESULT_FALSE:
265 return con->cond_cache[dc->context_ndx].result;
266 default:
267 break;
268 }
269 }
270
271 if (!con->conditional_is_valid[dc->comp]) {
272 if (con->conf.log_condition_handling) {
273 log_error_write(srv, __FILE__, __LINE__, "dss",
274 dc->comp,
275 dc->key->ptr,
276 con->conditional_is_valid[dc->comp] ? "yeah" : "nej");
277 }
278
279 return COND_RESULT_UNSET;
280 }
281
282 /* pass the rules */
283
284 switch (dc->comp) {
285 case COMP_HTTP_HOST: {
286 char *ck_colon = NULL, *val_colon = NULL;
287
288 if (!buffer_is_empty(con->uri.authority)) {
289
290 /*
291 * append server-port to the HTTP_POST if necessary
292 */
293
294 l = con->uri.authority;
295
296 switch(dc->cond) {
297 case CONFIG_COND_NE:
298 case CONFIG_COND_EQ:
299 ck_colon = strchr(dc->string->ptr, ':');
300 val_colon = strchr(l->ptr, ':');
301
302 if (NULL != ck_colon && NULL == val_colon) {
303 /* condition "host:port" but client send "host" */
304 buffer_copy_string_buffer(srv->cond_check_buf, l);
305 buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":"));
306 buffer_append_long(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
307 l = srv->cond_check_buf;
308 } else if (NULL != val_colon && NULL == ck_colon) {
309 /* condition "host" but client send "host:port" */
310 buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr);
311 l = srv->cond_check_buf;
312 }
313 break;
314 default:
315 break;
316 }
317 #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
318 } else if (!buffer_is_empty(con->tlsext_server_name)) {
319 l = con->tlsext_server_name;
320 #endif
321 } else {
322 l = srv->empty_string;
323 }
324 break;
325 }
326 case COMP_HTTP_REMOTE_IP: {
327 char *nm_slash;
328 /* handle remoteip limitations
329 *
330 * "10.0.0.1" is provided for all comparisions
331 *
332 * only for == and != we support
333 *
334 * "10.0.0.1/24"
335 */
336
337 if ((dc->cond == CONFIG_COND_EQ ||
338 dc->cond == CONFIG_COND_NE) &&
339 (con->dst_addr.plain.sa_family == AF_INET) &&
340 (NULL != (nm_slash = strchr(dc->string->ptr, '/')))) {
341 int nm_bits;
342 long nm;
343 char *err;
344 struct in_addr val_inp;
345
346 if (*(nm_slash+1) == '\0') {
347 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
348
349 return COND_RESULT_FALSE;
350 }
351
352 nm_bits = strtol(nm_slash + 1, &err, 10);
353
354 if (*err) {
355 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, err);
356
357 return COND_RESULT_FALSE;
358 }
359
360 /* take IP convert to the native */
361 buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
362 #ifdef __WIN32
363 if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
364 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
365
366 return COND_RESULT_FALSE;
367 }
368
369 #else
370 if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
371 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
372
373 return COND_RESULT_FALSE;
374 }
375 #endif
376
377 /* build netmask */
378 nm = htonl(~((1 << (32 - nm_bits)) - 1));
379
380 if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
381 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
382 } else {
383 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
384 }
385 } else {
386 l = con->dst_addr_buf;
387 }
388 break;
389 }
390 case COMP_HTTP_SCHEME:
391 l = con->uri.scheme;
392 break;
393
394 case COMP_HTTP_URL:
395 l = con->uri.path;
396 break;
397
398 case COMP_HTTP_QUERY_STRING:
399 l = con->uri.query;
400 break;
401
402 case COMP_SERVER_SOCKET:
403 l = srv_sock->srv_token;
404 break;
405
406 case COMP_HTTP_REFERER: {
407 data_string *ds;
408
409 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
410 l = ds->value;
411 } else {
412 l = srv->empty_string;
413 }
414 break;
415 }
416 case COMP_HTTP_COOKIE: {
417 data_string *ds;
418 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
419 l = ds->value;
420 } else {
421 l = srv->empty_string;
422 }
423 break;
424 }
425 case COMP_HTTP_USER_AGENT: {
426 data_string *ds;
427 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) {
428 l = ds->value;
429 } else {
430 l = srv->empty_string;
431 }
432 break;
433 }
434 case COMP_HTTP_REQUEST_METHOD: {
435 const char *method = get_http_method_name(con->request.http_method);
436
437 /* we only have the request method as const char but we need a buffer for comparing */
438
439 buffer_copy_string(srv->tmp_buf, method);
440
441 l = srv->tmp_buf;
442
443 break;
444 }
445 case COMP_HTTP_LANGUAGE: {
446 data_string *ds;
447 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Language"))) {
448 l = ds->value;
449 } else {
450 l = srv->empty_string;
451 }
452 break;
453 }
454 default:
455 return COND_RESULT_FALSE;
456 }
457
458 if (NULL == l) {
459 if (con->conf.log_condition_handling) {
460 log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key,
461 "(", l, ") compare to NULL");
462 }
463 return COND_RESULT_FALSE;
464 }
465
466 if (con->conf.log_condition_handling) {
467 log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
468 "(", l, ") compare to ", dc->string);
469 }
470 switch(dc->cond) {
471 case CONFIG_COND_NE:
472 case CONFIG_COND_EQ:
473 if (buffer_is_equal(l, dc->string)) {
474 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
475 } else {
476 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
477 }
478 break;
479 #ifdef HAVE_PCRE_H
480 case CONFIG_COND_NOMATCH:
481 case CONFIG_COND_MATCH: {
482 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
483 int n;
484
485 #ifndef elementsof
486 #define elementsof(x) (sizeof(x) / sizeof(x[0]))
487 #endif
488 n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
489 cache->matches, elementsof(cache->matches));
490
491 cache->patterncount = n;
492 if (n > 0) {
493 cache->comp_value = l;
494 cache->comp_type = dc->comp;
495 return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
496 } else {
497 /* cache is already cleared */
498 return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
499 }
500 break;
501 }
502 #endif
503 default:
504 /* no way */
505 break;
506 }
507
508 return COND_RESULT_FALSE;
509 }
510
config_check_cond_cached(server * srv,connection * con,data_config * dc)511 static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc) {
512 cond_cache_t *caches = con->cond_cache;
513
514 if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
515 if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
516 if (dc->next) {
517 data_config *c;
518 if (con->conf.log_condition_handling) {
519 log_error_write(srv, __FILE__, __LINE__, "s",
520 "setting remains of chaining to false");
521 }
522 for (c = dc->next; c; c = c->next) {
523 caches[c->context_ndx].result = COND_RESULT_FALSE;
524 }
525 }
526 }
527 caches[dc->context_ndx].comp_type = dc->comp;
528
529 if (con->conf.log_condition_handling) {
530 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
531 "(uncached) result:",
532 caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
533 (caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false"));
534 }
535 } else {
536 if (con->conf.log_condition_handling) {
537 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
538 "(cached) result:",
539 caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
540 (caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false"));
541 }
542 }
543 return caches[dc->context_ndx].result;
544 }
545
546 /**
547 * reset the config-cache for a named item
548 *
549 * if the item is COND_LAST_ELEMENT we reset all items
550 */
config_cond_cache_reset_item(server * srv,connection * con,comp_key_t item)551 void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) {
552 size_t i;
553
554 for (i = 0; i < srv->config_context->used; i++) {
555 if (item == COMP_LAST_ELEMENT ||
556 con->cond_cache[i].comp_type == item) {
557 con->cond_cache[i].result = COND_RESULT_UNSET;
558 con->cond_cache[i].patterncount = 0;
559 con->cond_cache[i].comp_value = NULL;
560 }
561 }
562 }
563
564 /**
565 * reset the config cache to its initial state at connection start
566 */
config_cond_cache_reset(server * srv,connection * con)567 void config_cond_cache_reset(server *srv, connection *con) {
568 size_t i;
569
570 config_cond_cache_reset_all_items(srv, con);
571
572 for (i = 0; i < COMP_LAST_ELEMENT; i++) {
573 con->conditional_is_valid[i] = 0;
574 }
575 }
576
config_check_cond(server * srv,connection * con,data_config * dc)577 int config_check_cond(server *srv, connection *con, data_config *dc) {
578 if (con->conf.log_condition_handling) {
579 log_error_write(srv, __FILE__, __LINE__, "s", "=== start of condition block ===");
580 }
581 return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
582 }
583
config_append_cond_match_buffer(connection * con,data_config * dc,buffer * buf,int n)584 int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n)
585 {
586 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
587 if (n >= cache->patterncount) {
588 return 0;
589 }
590
591 n <<= 1; /* n *= 2 */
592 buffer_append_string_len(buf,
593 cache->comp_value->ptr + cache->matches[n],
594 cache->matches[n + 1] - cache->matches[n]);
595 return 1;
596 }
597
598