root/trunk/src/configfile-glue.c

Revision 2263, 17.2 kB (checked in by stbuehler, 4 weeks ago)

Replace buffer_{append,copy}_string with the _len variant where possible (#1732, thx crypt)
Replace BUFFER_{APPEND,COPY}_STRING_CONST with _len(b, CONST_STRL_LEN(x))

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