Annotation of embedaddon/lighttpd/src/configfile-glue.c, revision 1.1.1.1
1.1 misho 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 */
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:
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:
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:
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:
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: */
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: */
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:
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:
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:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>