Annotation of embedaddon/lighttpd/src/configfile-glue.c, revision 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>