Annotation of embedaddon/lighttpd/src/configfile.c, revision 1.1.1.1

1.1       misho       1: #include "server.h"
                      2: #include "log.h"
                      3: #include "stream.h"
                      4: #include "plugin.h"
                      5: 
                      6: #include "configparser.h"
                      7: #include "configfile.h"
                      8: #include "proc_open.h"
                      9: 
                     10: #include <sys/stat.h>
                     11: 
                     12: #include <stdlib.h>
                     13: #include <fcntl.h>
                     14: #include <unistd.h>
                     15: #include <errno.h>
                     16: #include <string.h>
                     17: #include <stdio.h>
                     18: #include <ctype.h>
                     19: #include <limits.h>
                     20: #include <assert.h>
                     21: 
                     22: 
                     23: static int config_insert(server *srv) {
                     24:        size_t i;
                     25:        int ret = 0;
                     26:        buffer *stat_cache_string;
                     27: 
                     28:        config_values_t cv[] = {
                     29:                { "server.bind",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 0 */
                     30:                { "server.errorlog",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 1 */
                     31:                { "server.errorfile-prefix",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 2 */
                     32:                { "server.chroot",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 3 */
                     33:                { "server.username",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 4 */
                     34:                { "server.groupname",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 5 */
                     35:                { "server.port",                 NULL, T_CONFIG_SHORT,  T_CONFIG_SCOPE_SERVER },      /* 6 */
                     36:                { "server.tag",                  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 7 */
                     37:                { "server.use-ipv6",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
                     38:                { "server.modules",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER },       /* 9 */
                     39: 
                     40:                { "server.event-handler",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 10 */
                     41:                { "server.pid-file",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 11 */
                     42:                { "server.max-request-size",     NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },     /* 12 */
                     43:                { "server.max-worker",           NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER },       /* 13 */
                     44:                { "server.document-root",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 14 */
                     45:                { "server.force-lowercase-filenames", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },/* 15 */
                     46:                { "debug.log-condition-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },    /* 16 */
                     47:                { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },/* 17 */
                     48:                { "server.name",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 18 */
                     49:                { "server.max-keep-alive-idle",  NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 19 */
                     50: 
                     51:                { "server.max-read-idle",        NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 20 */
                     52:                { "server.max-write-idle",       NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 21 */
                     53:                { "server.error-handler-404",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 22 */
                     54:                { "server.max-fds",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER },       /* 23 */
                     55: #ifdef HAVE_LSTAT
                     56:                { "server.follow-symlink",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 24 */
                     57: #else
                     58:                { "server.follow-symlink",
                     59:                  "Your system lacks lstat(). We can not differ symlinks from files."
                     60:                  "Please remove server.follow-symlinks from your config.",
                     61:                  T_CONFIG_UNSUPPORTED, T_CONFIG_SCOPE_UNSET }, /* 24 */
                     62: #endif
                     63:                { "server.kbytes-per-second",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 25 */
                     64:                { "connection.kbytes-per-second", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },  /* 26 */
                     65:                { "mimetype.use-xattr",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
                     66:                { "mimetype.assign",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 28 */
                     67:                { "ssl.pemfile",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 29 */
                     68: 
                     69:                { "ssl.engine",                  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 30 */
                     70: 
                     71:                { "debug.log-file-not-found",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 31 */
                     72:                { "debug.log-request-handling",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 32 */
                     73:                { "debug.log-response-header",   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 33 */
                     74:                { "debug.log-request-header",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 34 */
                     75:                { "debug.log-ssl-noise",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 35 */
                     76: 
                     77:                { "server.protocol-http11",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 36 */
                     78:                { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */
                     79:                { "debug.log-state-handling",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 38 */
                     80:                { "ssl.ca-file",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 39 */
                     81: 
                     82:                { "server.errorlog-use-syslog",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 40 */
                     83:                { "server.range-requests",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
                     84:                { "server.stat-cache-engine",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 42 */
                     85:                { "server.max-connections",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER },       /* 43 */
                     86:                { "server.network-backend",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 44 */
                     87:                { "server.upload-dirs",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 45 */
                     88:                { "server.core-files",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 46 */
                     89:                { "ssl.cipher-list",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 47 */
                     90:                { "ssl.use-sslv2",               NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 48 */
                     91:                { "etag.use-inode",              NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 49 */
                     92:                { "etag.use-mtime",              NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 50 */
                     93:                { "etag.use-size",               NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 51 */
                     94:                { "server.reject-expect-100-with-417",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 52 */
                     95:                { "debug.log-timeouts",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 53 */
                     96:                { "server.defer-accept",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 54 */
                     97:                { "server.breakagelog",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 55 */
                     98:                { "ssl.verifyclient.activate",   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 56 */
                     99:                { "ssl.verifyclient.enforce",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 57 */
                    100:                { "ssl.verifyclient.depth",      NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER },     /* 58 */
                    101:                { "ssl.verifyclient.username",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },     /* 59 */
                    102:                { "ssl.verifyclient.exportcert", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 60 */
                    103: 
                    104:                { "server.set-v6only",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 61 */
                    105:                { "ssl.use-sslv3",               NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 62 */
                    106:                { "ssl.dh-file",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 63 */
                    107:                { "ssl.ec-curve",                NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 64 */
                    108:                { "ssl.disable-client-renegotiation", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },/* 65 */
                    109:                { "ssl.honor-cipher-order",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 66 */
                    110:                { "ssl.empty-fragments",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 67 */
                    111: 
                    112:                { "server.host",                 "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
                    113:                { "server.docroot",              "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
                    114:                { "server.virtual-root",         "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
                    115:                { "server.virtual-default-host", "load mod_simple_vhost and use simple-vhost.default-host instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
                    116:                { "server.virtual-docroot",      "load mod_simple_vhost and use simple-vhost.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
                    117:                { "server.userid",               "use server.username instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
                    118:                { "server.groupid",              "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
                    119:                { "server.use-keep-alive",       "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
                    120:                { "server.force-lower-case-files",       "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
                    121: 
                    122:                { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
                    123:        };
                    124: 
                    125: 
                    126:        /* 0 */
                    127:        cv[0].destination = srv->srvconf.bindhost;
                    128:        cv[1].destination = srv->srvconf.errorlog_file;
                    129:        cv[3].destination = srv->srvconf.changeroot;
                    130:        cv[4].destination = srv->srvconf.username;
                    131:        cv[5].destination = srv->srvconf.groupname;
                    132:        cv[6].destination = &(srv->srvconf.port);
                    133: 
                    134:        cv[9].destination = srv->srvconf.modules;
                    135:        cv[10].destination = srv->srvconf.event_handler;
                    136:        cv[11].destination = srv->srvconf.pid_file;
                    137: 
                    138:        cv[13].destination = &(srv->srvconf.max_worker);
                    139:        cv[23].destination = &(srv->srvconf.max_fds);
                    140:        cv[37].destination = &(srv->srvconf.log_request_header_on_error);
                    141:        cv[38].destination = &(srv->srvconf.log_state_handling);
                    142: 
                    143:        cv[40].destination = &(srv->srvconf.errorlog_use_syslog);
                    144: 
                    145:        stat_cache_string = buffer_init();
                    146:        cv[42].destination = stat_cache_string;
                    147:        cv[44].destination = srv->srvconf.network_backend;
                    148:        cv[45].destination = srv->srvconf.upload_tempdirs;
                    149:        cv[46].destination = &(srv->srvconf.enable_cores);
                    150: 
                    151:        cv[43].destination = &(srv->srvconf.max_conns);
                    152:        cv[12].destination = &(srv->srvconf.max_request_size);
                    153:        cv[52].destination = &(srv->srvconf.reject_expect_100_with_417);
                    154:        cv[55].destination = srv->srvconf.breakagelog_file;
                    155: 
                    156:        srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
                    157: 
                    158:        assert(srv->config_storage);
                    159: 
                    160:        for (i = 0; i < srv->config_context->used; i++) {
                    161:                specific_config *s;
                    162: 
                    163:                s = calloc(1, sizeof(specific_config));
                    164:                assert(s);
                    165:                s->document_root = buffer_init();
                    166:                s->mimetypes     = array_init();
                    167:                s->server_name   = buffer_init();
                    168:                s->ssl_pemfile   = buffer_init();
                    169:                s->ssl_ca_file   = buffer_init();
                    170:                s->error_handler = buffer_init();
                    171:                s->server_tag    = buffer_init();
                    172:                s->ssl_cipher_list = buffer_init();
                    173:                s->ssl_dh_file   = buffer_init();
                    174:                s->ssl_ec_curve  = buffer_init();
                    175:                s->errorfile_prefix = buffer_init();
                    176:                s->max_keep_alive_requests = 16;
                    177:                s->max_keep_alive_idle = 5;
                    178:                s->max_read_idle = 60;
                    179:                s->max_write_idle = 360;
                    180:                s->use_xattr     = 0;
                    181:                s->ssl_enabled   = 0;
                    182:                s->ssl_honor_cipher_order = 1;
                    183:                s->ssl_empty_fragments = 0;
                    184:                s->ssl_use_sslv2 = 0;
                    185:                s->ssl_use_sslv3 = 1;
                    186:                s->use_ipv6      = 0;
                    187:                s->set_v6only    = 1;
                    188:                s->defer_accept  = 0;
                    189: #ifdef HAVE_LSTAT
                    190:                s->follow_symlink = 1;
                    191: #endif
                    192:                s->kbytes_per_second = 0;
                    193:                s->allow_http11  = 1;
                    194:                s->etag_use_inode = 1;
                    195:                s->etag_use_mtime = 1;
                    196:                s->etag_use_size  = 1;
                    197:                s->range_requests = 1;
                    198:                s->force_lowercase_filenames = (i == 0) ? 2 : 0; /* we wan't to detect later if user changed this for global section */
                    199:                s->global_kbytes_per_second = 0;
                    200:                s->global_bytes_per_second_cnt = 0;
                    201:                s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
                    202:                s->ssl_verifyclient = 0;
                    203:                s->ssl_verifyclient_enforce = 1;
                    204:                s->ssl_verifyclient_username = buffer_init();
                    205:                s->ssl_verifyclient_depth = 9;
                    206:                s->ssl_verifyclient_export_cert = 0;
                    207:                s->ssl_disable_client_renegotiation = 1;
                    208: 
                    209:                cv[2].destination = s->errorfile_prefix;
                    210: 
                    211:                cv[7].destination = s->server_tag;
                    212:                cv[8].destination = &(s->use_ipv6);
                    213:                cv[61].destination = &(s->set_v6only);
                    214:                cv[54].destination = &(s->defer_accept);
                    215: 
                    216: 
                    217:                /* 13 max-worker */
                    218:                cv[14].destination = s->document_root;
                    219:                cv[15].destination = &(s->force_lowercase_filenames);
                    220:                cv[16].destination = &(s->log_condition_handling);
                    221:                cv[17].destination = &(s->max_keep_alive_requests);
                    222:                cv[18].destination = s->server_name;
                    223:                cv[19].destination = &(s->max_keep_alive_idle);
                    224:                cv[20].destination = &(s->max_read_idle);
                    225:                cv[21].destination = &(s->max_write_idle);
                    226:                cv[22].destination = s->error_handler;
                    227: #ifdef HAVE_LSTAT
                    228:                cv[24].destination = &(s->follow_symlink);
                    229: #endif
                    230:                /* 23 -> max-fds */
                    231:                cv[25].destination = &(s->global_kbytes_per_second);
                    232:                cv[26].destination = &(s->kbytes_per_second);
                    233:                cv[27].destination = &(s->use_xattr);
                    234:                cv[28].destination = s->mimetypes;
                    235:                cv[29].destination = s->ssl_pemfile;
                    236:                cv[30].destination = &(s->ssl_enabled);
                    237: 
                    238:                cv[31].destination = &(s->log_file_not_found);
                    239:                cv[32].destination = &(s->log_request_handling);
                    240:                cv[33].destination = &(s->log_response_header);
                    241:                cv[34].destination = &(s->log_request_header);
                    242:                cv[35].destination = &(s->log_ssl_noise);
                    243:                cv[53].destination = &(s->log_timeouts);
                    244: 
                    245:                cv[36].destination = &(s->allow_http11);
                    246:                cv[39].destination = s->ssl_ca_file;
                    247:                cv[41].destination = &(s->range_requests);
                    248: 
                    249:                cv[47].destination = s->ssl_cipher_list;
                    250:                cv[48].destination = &(s->ssl_use_sslv2);
                    251:                cv[62].destination = &(s->ssl_use_sslv3);
                    252:                cv[63].destination = s->ssl_dh_file;
                    253:                cv[64].destination = s->ssl_ec_curve;
                    254:                cv[66].destination = &(s->ssl_honor_cipher_order);
                    255:                cv[67].destination = &(s->ssl_empty_fragments);
                    256: 
                    257:                cv[49].destination = &(s->etag_use_inode);
                    258:                cv[50].destination = &(s->etag_use_mtime);
                    259:                cv[51].destination = &(s->etag_use_size);
                    260: 
                    261:                /* ssl.verify */
                    262:                cv[56].destination = &(s->ssl_verifyclient);
                    263:                cv[57].destination = &(s->ssl_verifyclient_enforce);
                    264:                cv[58].destination = &(s->ssl_verifyclient_depth);
                    265:                cv[59].destination = s->ssl_verifyclient_username;
                    266:                cv[60].destination = &(s->ssl_verifyclient_export_cert);
                    267:                cv[65].destination = &(s->ssl_disable_client_renegotiation);
                    268: 
                    269:                srv->config_storage[i] = s;
                    270: 
                    271:                if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
                    272:                        break;
                    273:                }
                    274:        }
                    275: 
                    276:        if (buffer_is_empty(stat_cache_string)) {
                    277:                srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
                    278:        } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
                    279:                srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
                    280: #ifdef HAVE_FAM_H
                    281:        } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("fam"))) {
                    282:                srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_FAM;
                    283: #endif
                    284:        } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
                    285:                srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
                    286:        } else {
                    287:                log_error_write(srv, __FILE__, __LINE__, "sb",
                    288:                                "server.stat-cache-engine can be one of \"disable\", \"simple\","
                    289: #ifdef HAVE_FAM_H
                    290:                                " \"fam\","
                    291: #endif
                    292:                                " but not:", stat_cache_string);
                    293:                ret = HANDLER_ERROR;
                    294:        }
                    295: 
                    296:        buffer_free(stat_cache_string);
                    297: 
                    298:        return ret;
                    299: 
                    300: }
                    301: 
                    302: 
                    303: #define PATCH(x) con->conf.x = s->x
                    304: int config_setup_connection(server *srv, connection *con) {
                    305:        specific_config *s = srv->config_storage[0];
                    306: 
                    307:        PATCH(allow_http11);
                    308:        PATCH(mimetypes);
                    309:        PATCH(document_root);
                    310:        PATCH(max_keep_alive_requests);
                    311:        PATCH(max_keep_alive_idle);
                    312:        PATCH(max_read_idle);
                    313:        PATCH(max_write_idle);
                    314:        PATCH(use_xattr);
                    315:        PATCH(error_handler);
                    316:        PATCH(errorfile_prefix);
                    317: #ifdef HAVE_LSTAT
                    318:        PATCH(follow_symlink);
                    319: #endif
                    320:        PATCH(server_tag);
                    321:        PATCH(kbytes_per_second);
                    322:        PATCH(global_kbytes_per_second);
                    323:        PATCH(global_bytes_per_second_cnt);
                    324: 
                    325:        con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
                    326:        buffer_copy_string_buffer(con->server_name, s->server_name);
                    327: 
                    328:        PATCH(log_request_header);
                    329:        PATCH(log_response_header);
                    330:        PATCH(log_request_handling);
                    331:        PATCH(log_condition_handling);
                    332:        PATCH(log_file_not_found);
                    333:        PATCH(log_ssl_noise);
                    334:        PATCH(log_timeouts);
                    335: 
                    336:        PATCH(range_requests);
                    337:        PATCH(force_lowercase_filenames);
                    338:        PATCH(ssl_enabled);
                    339: 
                    340:        PATCH(ssl_pemfile);
                    341: #ifdef USE_OPENSSL
                    342:        PATCH(ssl_ctx);
                    343: #endif
                    344:        PATCH(ssl_ca_file);
                    345:        PATCH(ssl_cipher_list);
                    346:        PATCH(ssl_dh_file);
                    347:        PATCH(ssl_ec_curve);
                    348:        PATCH(ssl_honor_cipher_order);
                    349:        PATCH(ssl_empty_fragments);
                    350:        PATCH(ssl_use_sslv2);
                    351:        PATCH(ssl_use_sslv3);
                    352:        PATCH(etag_use_inode);
                    353:        PATCH(etag_use_mtime);
                    354:        PATCH(etag_use_size);
                    355: 
                    356:        PATCH(ssl_verifyclient);
                    357:        PATCH(ssl_verifyclient_enforce);
                    358:        PATCH(ssl_verifyclient_depth);
                    359:        PATCH(ssl_verifyclient_username);
                    360:        PATCH(ssl_verifyclient_export_cert);
                    361:        PATCH(ssl_disable_client_renegotiation);
                    362: 
                    363:        return 0;
                    364: }
                    365: 
                    366: int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
                    367:        size_t i, j;
                    368: 
                    369:        con->conditional_is_valid[comp] = 1;
                    370: 
                    371:        /* skip the first, the global context */
                    372:        for (i = 1; i < srv->config_context->used; i++) {
                    373:                data_config *dc = (data_config *)srv->config_context->data[i];
                    374:                specific_config *s = srv->config_storage[i];
                    375: 
                    376:                /* condition didn't match */
                    377:                if (!config_check_cond(srv, con, dc)) continue;
                    378: 
                    379:                /* merge config */
                    380:                for (j = 0; j < dc->value->used; j++) {
                    381:                        data_unset *du = dc->value->data[j];
                    382: 
                    383:                        if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
                    384:                                PATCH(document_root);
                    385:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
                    386:                                PATCH(range_requests);
                    387:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.error-handler-404"))) {
                    388:                                PATCH(error_handler);
                    389:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.errorfile-prefix"))) {
                    390:                                PATCH(errorfile_prefix);
                    391:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.assign"))) {
                    392:                                PATCH(mimetypes);
                    393:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-keep-alive-requests"))) {
                    394:                                PATCH(max_keep_alive_requests);
                    395:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-keep-alive-idle"))) {
                    396:                                PATCH(max_keep_alive_idle);
                    397:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-write-idle"))) {
                    398:                                PATCH(max_write_idle);
                    399:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-read-idle"))) {
                    400:                                PATCH(max_read_idle);
                    401:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.use-xattr"))) {
                    402:                                PATCH(use_xattr);
                    403:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-inode"))) {
                    404:                                PATCH(etag_use_inode);
                    405:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-mtime"))) {
                    406:                                PATCH(etag_use_mtime);
                    407:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-size"))) {
                    408:                                PATCH(etag_use_size);
                    409:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.pemfile"))) {
                    410:                                PATCH(ssl_pemfile);
                    411: #ifdef USE_OPENSSL
                    412:                                PATCH(ssl_ctx);
                    413: #endif
                    414:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ca-file"))) {
                    415:                                PATCH(ssl_ca_file);
                    416:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.honor-cipher-order"))) {
                    417:                                PATCH(ssl_honor_cipher_order);
                    418:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.empty-fragments"))) {
                    419:                                PATCH(ssl_empty_fragments);
                    420:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv2"))) {
                    421:                                PATCH(ssl_use_sslv2);
                    422:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv3"))) {
                    423:                                PATCH(ssl_use_sslv3);
                    424:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.cipher-list"))) {
                    425:                                PATCH(ssl_cipher_list);
                    426:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) {
                    427:                                PATCH(ssl_enabled);
                    428:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.dh-file"))) {
                    429:                                PATCH(ssl_dh_file);
                    430:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ec-curve"))) {
                    431:                                PATCH(ssl_ec_curve);
                    432: #ifdef HAVE_LSTAT
                    433:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.follow-symlink"))) {
                    434:                                PATCH(follow_symlink);
                    435: #endif
                    436:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.name"))) {
                    437:                                buffer_copy_string_buffer(con->server_name, s->server_name);
                    438:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.tag"))) {
                    439:                                PATCH(server_tag);
                    440:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("connection.kbytes-per-second"))) {
                    441:                                PATCH(kbytes_per_second);
                    442:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-request-handling"))) {
                    443:                                PATCH(log_request_handling);
                    444:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-request-header"))) {
                    445:                                PATCH(log_request_header);
                    446:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-response-header"))) {
                    447:                                PATCH(log_response_header);
                    448:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
                    449:                                PATCH(log_condition_handling);
                    450:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
                    451:                                PATCH(log_file_not_found);
                    452:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-ssl-noise"))) {
                    453:                                PATCH(log_ssl_noise);
                    454:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-timeouts"))) {
                    455:                                PATCH(log_timeouts);
                    456:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
                    457:                                PATCH(allow_http11);
                    458:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
                    459:                                PATCH(force_lowercase_filenames);
                    460:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
                    461:                                PATCH(global_kbytes_per_second);
                    462:                                PATCH(global_bytes_per_second_cnt);
                    463:                                con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
                    464:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.activate"))) {
                    465:                                PATCH(ssl_verifyclient);
                    466:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.enforce"))) {
                    467:                                PATCH(ssl_verifyclient_enforce);
                    468:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.depth"))) {
                    469:                                PATCH(ssl_verifyclient_depth);
                    470:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.username"))) {
                    471:                                PATCH(ssl_verifyclient_username);
                    472:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.exportcert"))) {
                    473:                                PATCH(ssl_verifyclient_export_cert);
                    474:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.disable-client-renegotiation"))) {
                    475:                                PATCH(ssl_disable_client_renegotiation);
                    476:                        }
                    477:                }
                    478:        }
                    479: 
                    480:                con->etag_flags = (con->conf.etag_use_mtime ? ETAG_USE_MTIME : 0) |
                    481:                                  (con->conf.etag_use_inode ? ETAG_USE_INODE : 0) |
                    482:                                  (con->conf.etag_use_size  ? ETAG_USE_SIZE  : 0);
                    483: 
                    484:        return 0;
                    485: }
                    486: #undef PATCH
                    487: 
                    488: typedef struct {
                    489:        int foo;
                    490:        int bar;
                    491: 
                    492:        const buffer *source;
                    493:        const char *input;
                    494:        size_t offset;
                    495:        size_t size;
                    496: 
                    497:        int line_pos;
                    498:        int line;
                    499: 
                    500:        int in_key;
                    501:        int in_brace;
                    502:        int in_cond;
                    503: } tokenizer_t;
                    504: 
                    505: #if 0
                    506: static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const char *fn) {
                    507:        if (buffer_is_empty(basedir) ||
                    508:                        (fn[0] == '/' || fn[0] == '\\') ||
                    509:                        (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
                    510:                t->file = buffer_init_string(fn);
                    511:        } else {
                    512:                t->file = buffer_init_buffer(basedir);
                    513:                buffer_append_string(t->file, fn);
                    514:        }
                    515: 
                    516:        if (0 != stream_open(&(t->s), t->file)) {
                    517:                log_error_write(srv, __FILE__, __LINE__, "sbss",
                    518:                                "opening configfile ", t->file, "failed:", strerror(errno));
                    519:                buffer_free(t->file);
                    520:                return -1;
                    521:        }
                    522: 
                    523:        t->input = t->s.start;
                    524:        t->offset = 0;
                    525:        t->size = t->s.size;
                    526:        t->line = 1;
                    527:        t->line_pos = 1;
                    528: 
                    529:        t->in_key = 1;
                    530:        t->in_brace = 0;
                    531:        t->in_cond = 0;
                    532:        return 0;
                    533: }
                    534: 
                    535: static int tokenizer_close(server *srv, tokenizer_t *t) {
                    536:        UNUSED(srv);
                    537: 
                    538:        buffer_free(t->file);
                    539:        return stream_close(&(t->s));
                    540: }
                    541: #endif
                    542: static int config_skip_newline(tokenizer_t *t) {
                    543:        int skipped = 1;
                    544:        assert(t->input[t->offset] == '\r' || t->input[t->offset] == '\n');
                    545:        if (t->input[t->offset] == '\r' && t->input[t->offset + 1] == '\n') {
                    546:                skipped ++;
                    547:                t->offset ++;
                    548:        }
                    549:        t->offset ++;
                    550:        return skipped;
                    551: }
                    552: 
                    553: static int config_skip_comment(tokenizer_t *t) {
                    554:        int i;
                    555:        assert(t->input[t->offset] == '#');
                    556:        for (i = 1; t->input[t->offset + i] &&
                    557:             (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
                    558:             i++);
                    559:        t->offset += i;
                    560:        return i;
                    561: }
                    562: 
                    563: static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
                    564:        int tid = 0;
                    565:        size_t i;
                    566: 
                    567:        for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
                    568:                char c = t->input[t->offset];
                    569:                const char *start = NULL;
                    570: 
                    571:                switch (c) {
                    572:                case '=':
                    573:                        if (t->in_brace) {
                    574:                                if (t->input[t->offset + 1] == '>') {
                    575:                                        t->offset += 2;
                    576: 
                    577:                                        buffer_copy_string_len(token, CONST_STR_LEN("=>"));
                    578: 
                    579:                                        tid = TK_ARRAY_ASSIGN;
                    580:                                } else {
                    581:                                        log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    582:                                                        "source:", t->source,
                    583:                                                        "line:", t->line, "pos:", t->line_pos,
                    584:                                                        "use => for assignments in arrays");
                    585:                                        return -1;
                    586:                                }
                    587:                        } else if (t->in_cond) {
                    588:                                if (t->input[t->offset + 1] == '=') {
                    589:                                        t->offset += 2;
                    590: 
                    591:                                        buffer_copy_string_len(token, CONST_STR_LEN("=="));
                    592: 
                    593:                                        tid = TK_EQ;
                    594:                                } else if (t->input[t->offset + 1] == '~') {
                    595:                                        t->offset += 2;
                    596: 
                    597:                                        buffer_copy_string_len(token, CONST_STR_LEN("=~"));
                    598: 
                    599:                                        tid = TK_MATCH;
                    600:                                } else {
                    601:                                        log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    602:                                                        "source:", t->source,
                    603:                                                        "line:", t->line, "pos:", t->line_pos,
                    604:                                                        "only =~ and == are allowed in the condition");
                    605:                                        return -1;
                    606:                                }
                    607:                                t->in_key = 1;
                    608:                                t->in_cond = 0;
                    609:                        } else if (t->in_key) {
                    610:                                tid = TK_ASSIGN;
                    611: 
                    612:                                buffer_copy_string_len(token, t->input + t->offset, 1);
                    613: 
                    614:                                t->offset++;
                    615:                                t->line_pos++;
                    616:                        } else {
                    617:                                log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    618:                                                "source:", t->source,
                    619:                                                "line:", t->line, "pos:", t->line_pos,
                    620:                                                "unexpected equal-sign: =");
                    621:                                return -1;
                    622:                        }
                    623: 
                    624:                        break;
                    625:                case '!':
                    626:                        if (t->in_cond) {
                    627:                                if (t->input[t->offset + 1] == '=') {
                    628:                                        t->offset += 2;
                    629: 
                    630:                                        buffer_copy_string_len(token, CONST_STR_LEN("!="));
                    631: 
                    632:                                        tid = TK_NE;
                    633:                                } else if (t->input[t->offset + 1] == '~') {
                    634:                                        t->offset += 2;
                    635: 
                    636:                                        buffer_copy_string_len(token, CONST_STR_LEN("!~"));
                    637: 
                    638:                                        tid = TK_NOMATCH;
                    639:                                } else {
                    640:                                        log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    641:                                                        "source:", t->source,
                    642:                                                        "line:", t->line, "pos:", t->line_pos,
                    643:                                                        "only !~ and != are allowed in the condition");
                    644:                                        return -1;
                    645:                                }
                    646:                                t->in_key = 1;
                    647:                                t->in_cond = 0;
                    648:                        } else {
                    649:                                log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    650:                                                "source:", t->source,
                    651:                                                "line:", t->line, "pos:", t->line_pos,
                    652:                                                "unexpected exclamation-marks: !");
                    653:                                return -1;
                    654:                        }
                    655: 
                    656:                        break;
                    657:                case '\t':
                    658:                case ' ':
                    659:                        t->offset++;
                    660:                        t->line_pos++;
                    661:                        break;
                    662:                case '\n':
                    663:                case '\r':
                    664:                        if (t->in_brace == 0) {
                    665:                                int done = 0;
                    666:                                while (!done && t->offset < t->size) {
                    667:                                        switch (t->input[t->offset]) {
                    668:                                        case '\r':
                    669:                                        case '\n':
                    670:                                                config_skip_newline(t);
                    671:                                                t->line_pos = 1;
                    672:                                                t->line++;
                    673:                                                break;
                    674: 
                    675:                                        case '#':
                    676:                                                t->line_pos += config_skip_comment(t);
                    677:                                                break;
                    678: 
                    679:                                        case '\t':
                    680:                                        case ' ':
                    681:                                                t->offset++;
                    682:                                                t->line_pos++;
                    683:                                                break;
                    684: 
                    685:                                        default:
                    686:                                                done = 1;
                    687:                                        }
                    688:                                }
                    689:                                t->in_key = 1;
                    690:                                tid = TK_EOL;
                    691:                                buffer_copy_string_len(token, CONST_STR_LEN("(EOL)"));
                    692:                        } else {
                    693:                                config_skip_newline(t);
                    694:                                t->line_pos = 1;
                    695:                                t->line++;
                    696:                        }
                    697:                        break;
                    698:                case ',':
                    699:                        if (t->in_brace > 0) {
                    700:                                tid = TK_COMMA;
                    701: 
                    702:                                buffer_copy_string_len(token, CONST_STR_LEN("(COMMA)"));
                    703:                        }
                    704: 
                    705:                        t->offset++;
                    706:                        t->line_pos++;
                    707:                        break;
                    708:                case '"':
                    709:                        /* search for the terminating " */
                    710:                        start = t->input + t->offset + 1;
                    711:                        buffer_copy_string_len(token, CONST_STR_LEN(""));
                    712: 
                    713:                        for (i = 1; t->input[t->offset + i]; i++) {
                    714:                                if (t->input[t->offset + i] == '\\' &&
                    715:                                    t->input[t->offset + i + 1] == '"') {
                    716: 
                    717:                                        buffer_append_string_len(token, start, t->input + t->offset + i - start);
                    718: 
                    719:                                        start = t->input + t->offset + i + 1;
                    720: 
                    721:                                        /* skip the " */
                    722:                                        i++;
                    723:                                        continue;
                    724:                                }
                    725: 
                    726: 
                    727:                                if (t->input[t->offset + i] == '"') {
                    728:                                        tid = TK_STRING;
                    729: 
                    730:                                        buffer_append_string_len(token, start, t->input + t->offset + i - start);
                    731: 
                    732:                                        break;
                    733:                                }
                    734:                        }
                    735: 
                    736:                        if (t->input[t->offset + i] == '\0') {
                    737:                                /* ERROR */
                    738: 
                    739:                                log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    740:                                                "source:", t->source,
                    741:                                                "line:", t->line, "pos:", t->line_pos,
                    742:                                                "missing closing quote");
                    743: 
                    744:                                return -1;
                    745:                        }
                    746: 
                    747:                        t->offset += i + 1;
                    748:                        t->line_pos += i + 1;
                    749: 
                    750:                        break;
                    751:                case '(':
                    752:                        t->offset++;
                    753:                        t->in_brace++;
                    754: 
                    755:                        tid = TK_LPARAN;
                    756: 
                    757:                        buffer_copy_string_len(token, CONST_STR_LEN("("));
                    758:                        break;
                    759:                case ')':
                    760:                        t->offset++;
                    761:                        t->in_brace--;
                    762: 
                    763:                        tid = TK_RPARAN;
                    764: 
                    765:                        buffer_copy_string_len(token, CONST_STR_LEN(")"));
                    766:                        break;
                    767:                case '$':
                    768:                        t->offset++;
                    769: 
                    770:                        tid = TK_DOLLAR;
                    771:                        t->in_cond = 1;
                    772:                        t->in_key = 0;
                    773: 
                    774:                        buffer_copy_string_len(token, CONST_STR_LEN("$"));
                    775: 
                    776:                        break;
                    777: 
                    778:                case '+':
                    779:                        if (t->input[t->offset + 1] == '=') {
                    780:                                t->offset += 2;
                    781:                                buffer_copy_string_len(token, CONST_STR_LEN("+="));
                    782:                                tid = TK_APPEND;
                    783:                        } else {
                    784:                                t->offset++;
                    785:                                tid = TK_PLUS;
                    786:                                buffer_copy_string_len(token, CONST_STR_LEN("+"));
                    787:                        }
                    788:                        break;
                    789: 
                    790:                case '{':
                    791:                        t->offset++;
                    792: 
                    793:                        tid = TK_LCURLY;
                    794: 
                    795:                        buffer_copy_string_len(token, CONST_STR_LEN("{"));
                    796: 
                    797:                        break;
                    798: 
                    799:                case '}':
                    800:                        t->offset++;
                    801: 
                    802:                        tid = TK_RCURLY;
                    803: 
                    804:                        buffer_copy_string_len(token, CONST_STR_LEN("}"));
                    805: 
                    806:                        break;
                    807: 
                    808:                case '[':
                    809:                        t->offset++;
                    810: 
                    811:                        tid = TK_LBRACKET;
                    812: 
                    813:                        buffer_copy_string_len(token, CONST_STR_LEN("["));
                    814: 
                    815:                        break;
                    816: 
                    817:                case ']':
                    818:                        t->offset++;
                    819: 
                    820:                        tid = TK_RBRACKET;
                    821: 
                    822:                        buffer_copy_string_len(token, CONST_STR_LEN("]"));
                    823: 
                    824:                        break;
                    825:                case '#':
                    826:                        t->line_pos += config_skip_comment(t);
                    827: 
                    828:                        break;
                    829:                default:
                    830:                        if (t->in_cond) {
                    831:                                for (i = 0; t->input[t->offset + i] &&
                    832:                                     (isalpha((unsigned char)t->input[t->offset + i])
                    833:                                      ); i++);
                    834: 
                    835:                                if (i && t->input[t->offset + i]) {
                    836:                                        tid = TK_SRVVARNAME;
                    837:                                        buffer_copy_string_len(token, t->input + t->offset, i);
                    838: 
                    839:                                        t->offset += i;
                    840:                                        t->line_pos += i;
                    841:                                } else {
                    842:                                        /* ERROR */
                    843:                                        log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    844:                                                        "source:", t->source,
                    845:                                                        "line:", t->line, "pos:", t->line_pos,
                    846:                                                        "invalid character in condition");
                    847:                                        return -1;
                    848:                                }
                    849:                        } else if (isdigit((unsigned char)c)) {
                    850:                                /* take all digits */
                    851:                                for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]);  i++);
                    852: 
                    853:                                /* was there it least a digit ? */
                    854:                                if (i) {
                    855:                                        tid = TK_INTEGER;
                    856: 
                    857:                                        buffer_copy_string_len(token, t->input + t->offset, i);
                    858: 
                    859:                                        t->offset += i;
                    860:                                        t->line_pos += i;
                    861:                                }
                    862:                        } else {
                    863:                                /* the key might consist of [-.0-9a-z] */
                    864:                                for (i = 0; t->input[t->offset + i] &&
                    865:                                     (isalnum((unsigned char)t->input[t->offset + i]) ||
                    866:                                      t->input[t->offset + i] == '.' ||
                    867:                                      t->input[t->offset + i] == '_' || /* for env.* */
                    868:                                      t->input[t->offset + i] == '-'
                    869:                                      ); i++);
                    870: 
                    871:                                if (i && t->input[t->offset + i]) {
                    872:                                        buffer_copy_string_len(token, t->input + t->offset, i);
                    873: 
                    874:                                        if (strcmp(token->ptr, "include") == 0) {
                    875:                                                tid = TK_INCLUDE;
                    876:                                        } else if (strcmp(token->ptr, "include_shell") == 0) {
                    877:                                                tid = TK_INCLUDE_SHELL;
                    878:                                        } else if (strcmp(token->ptr, "global") == 0) {
                    879:                                                tid = TK_GLOBAL;
                    880:                                        } else if (strcmp(token->ptr, "else") == 0) {
                    881:                                                tid = TK_ELSE;
                    882:                                        } else {
                    883:                                                tid = TK_LKEY;
                    884:                                        }
                    885: 
                    886:                                        t->offset += i;
                    887:                                        t->line_pos += i;
                    888:                                } else {
                    889:                                        /* ERROR */
                    890:                                        log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    891:                                                        "source:", t->source,
                    892:                                                        "line:", t->line, "pos:", t->line_pos,
                    893:                                                        "invalid character in variable name");
                    894:                                        return -1;
                    895:                                }
                    896:                        }
                    897:                        break;
                    898:                }
                    899:        }
                    900: 
                    901:        if (tid) {
                    902:                *token_id = tid;
                    903: #if 0
                    904:                log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
                    905:                                "source:", t->source,
                    906:                                "line:", t->line, "pos:", t->line_pos,
                    907:                                token, token->used - 1, tid);
                    908: #endif
                    909: 
                    910:                return 1;
                    911:        } else if (t->offset < t->size) {
                    912:                fprintf(stderr, "%s.%d: %d, %s\n",
                    913:                        __FILE__, __LINE__,
                    914:                        tid, token->ptr);
                    915:        }
                    916:        return 0;
                    917: }
                    918: 
                    919: static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
                    920:        void *pParser;
                    921:        int token_id;
                    922:        buffer *token, *lasttoken;
                    923:        int ret;
                    924: 
                    925:        pParser = configparserAlloc( malloc );
                    926:        lasttoken = buffer_init();
                    927:        token = buffer_init();
                    928:        while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
                    929:                buffer_copy_string_buffer(lasttoken, token);
                    930:                configparser(pParser, token_id, token, context);
                    931: 
                    932:                token = buffer_init();
                    933:        }
                    934:        buffer_free(token);
                    935: 
                    936:        if (ret != -1 && context->ok) {
                    937:                /* add an EOL at EOF, better than say sorry */
                    938:                configparser(pParser, TK_EOL, buffer_init_string("(EOL)"), context);
                    939:                if (context->ok) {
                    940:                        configparser(pParser, 0, NULL, context);
                    941:                }
                    942:        }
                    943:        configparserFree(pParser, free);
                    944: 
                    945:        if (ret == -1) {
                    946:                log_error_write(srv, __FILE__, __LINE__, "sb",
                    947:                                "configfile parser failed at:", lasttoken);
                    948:        } else if (context->ok == 0) {
                    949:                log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
                    950:                                "source:", t->source,
                    951:                                "line:", t->line, "pos:", t->line_pos,
                    952:                                "parser failed somehow near here:", lasttoken);
                    953:                ret = -1;
                    954:        }
                    955:        buffer_free(lasttoken);
                    956: 
                    957:        return ret == -1 ? -1 : 0;
                    958: }
                    959: 
                    960: static int tokenizer_init(tokenizer_t *t, const buffer *source, const char *input, size_t size) {
                    961: 
                    962:        t->source = source;
                    963:        t->input = input;
                    964:        t->size = size;
                    965:        t->offset = 0;
                    966:        t->line = 1;
                    967:        t->line_pos = 1;
                    968: 
                    969:        t->in_key = 1;
                    970:        t->in_brace = 0;
                    971:        t->in_cond = 0;
                    972:        return 0;
                    973: }
                    974: 
                    975: int config_parse_file(server *srv, config_t *context, const char *fn) {
                    976:        tokenizer_t t;
                    977:        stream s;
                    978:        int ret;
                    979:        buffer *filename;
                    980: 
                    981:        if (buffer_is_empty(context->basedir) ||
                    982:                        (fn[0] == '/' || fn[0] == '\\') ||
                    983:                        (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
                    984:                filename = buffer_init_string(fn);
                    985:        } else {
                    986:                filename = buffer_init_buffer(context->basedir);
                    987:                buffer_append_string(filename, fn);
                    988:        }
                    989: 
                    990:        if (0 != stream_open(&s, filename)) {
                    991:                if (s.size == 0) {
                    992:                        /* the file was empty, nothing to parse */
                    993:                        ret = 0;
                    994:                } else {
                    995:                        log_error_write(srv, __FILE__, __LINE__, "sbss",
                    996:                                        "opening configfile ", filename, "failed:", strerror(errno));
                    997:                        ret = -1;
                    998:                } 
                    999:        } else {
                   1000:                tokenizer_init(&t, filename, s.start, s.size);
                   1001:                ret = config_parse(srv, context, &t);
                   1002:        }
                   1003: 
                   1004:        stream_close(&s);
                   1005:        buffer_free(filename);
                   1006:        return ret;
                   1007: }
                   1008: 
                   1009: static char* getCWD(void) {
                   1010:        char *s, *s1;
                   1011:        size_t len;
                   1012: #ifdef PATH_MAX
                   1013:        len = PATH_MAX;
                   1014: #else
                   1015:        len = 4096;
                   1016: #endif
                   1017: 
                   1018:        s = malloc(len);
                   1019:        if (!s) return NULL;
                   1020:        while (NULL == getcwd(s, len)) {
                   1021:                if (errno != ERANGE || SSIZE_MAX - len < len) return NULL;
                   1022:                len *= 2;
                   1023:                s1 = realloc(s, len);
                   1024:                if (!s1) {
                   1025:                        free(s);
                   1026:                        return NULL;
                   1027:                }
                   1028:                s = s1;
                   1029:        }
                   1030:        return s;
                   1031: }
                   1032: 
                   1033: int config_parse_cmd(server *srv, config_t *context, const char *cmd) {
                   1034:        tokenizer_t t;
                   1035:        int ret;
                   1036:        buffer *source;
                   1037:        buffer *out;
                   1038:        char *oldpwd;
                   1039: 
                   1040:        if (NULL == (oldpwd = getCWD())) {
                   1041:                log_error_write(srv, __FILE__, __LINE__, "s",
                   1042:                                "cannot get cwd", strerror(errno));
                   1043:                return -1;
                   1044:        }
                   1045: 
                   1046:        source = buffer_init_string(cmd);
                   1047:        out = buffer_init();
                   1048: 
                   1049:        if (!buffer_is_empty(context->basedir)) {
                   1050:                chdir(context->basedir->ptr);
                   1051:        }
                   1052: 
                   1053:        if (0 != proc_open_buffer(cmd, NULL, out, NULL)) {
                   1054:                log_error_write(srv, __FILE__, __LINE__, "sbss",
                   1055:                                "opening", source, "failed:", strerror(errno));
                   1056:                ret = -1;
                   1057:        } else {
                   1058:                tokenizer_init(&t, source, out->ptr, out->used);
                   1059:                ret = config_parse(srv, context, &t);
                   1060:        }
                   1061: 
                   1062:        buffer_free(source);
                   1063:        buffer_free(out);
                   1064:        chdir(oldpwd);
                   1065:        free(oldpwd);
                   1066:        return ret;
                   1067: }
                   1068: 
                   1069: static void context_init(server *srv, config_t *context) {
                   1070:        context->srv = srv;
                   1071:        context->ok = 1;
                   1072:        context->configs_stack = array_init();
                   1073:        context->configs_stack->is_weakref = 1;
                   1074:        context->basedir = buffer_init();
                   1075: }
                   1076: 
                   1077: static void context_free(config_t *context) {
                   1078:        array_free(context->configs_stack);
                   1079:        buffer_free(context->basedir);
                   1080: }
                   1081: 
                   1082: int config_read(server *srv, const char *fn) {
                   1083:        config_t context;
                   1084:        data_config *dc;
                   1085:        data_integer *dpid;
                   1086:        data_string *dcwd;
                   1087:        int ret;
                   1088:        char *pos;
                   1089:        data_array *modules;
                   1090: 
                   1091:        context_init(srv, &context);
                   1092:        context.all_configs = srv->config_context;
                   1093: 
                   1094: #ifdef __WIN32
                   1095:        pos = strrchr(fn, '\\');
                   1096: #else
                   1097:        pos = strrchr(fn, '/');
                   1098: #endif
                   1099:        if (pos) {
                   1100:                buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
                   1101:                fn = pos + 1;
                   1102:        }
                   1103: 
                   1104:        dc = data_config_init();
                   1105:        buffer_copy_string_len(dc->key, CONST_STR_LEN("global"));
                   1106: 
                   1107:        assert(context.all_configs->used == 0);
                   1108:        dc->context_ndx = context.all_configs->used;
                   1109:        array_insert_unique(context.all_configs, (data_unset *)dc);
                   1110:        context.current = dc;
                   1111: 
                   1112:        /* default context */
                   1113:        srv->config = dc->value;
                   1114:        dpid = data_integer_init();
                   1115:        dpid->value = getpid();
                   1116:        buffer_copy_string_len(dpid->key, CONST_STR_LEN("var.PID"));
                   1117:        array_insert_unique(srv->config, (data_unset *)dpid);
                   1118: 
                   1119:        dcwd = data_string_init();
                   1120:        buffer_prepare_copy(dcwd->value, 1024);
                   1121:        if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
                   1122:                dcwd->value->used = strlen(dcwd->value->ptr) + 1;
                   1123:                buffer_copy_string_len(dcwd->key, CONST_STR_LEN("var.CWD"));
                   1124:                array_insert_unique(srv->config, (data_unset *)dcwd);
                   1125:        }
                   1126: 
                   1127:        ret = config_parse_file(srv, &context, fn);
                   1128: 
                   1129:        /* remains nothing if parser is ok */
                   1130:        assert(!(0 == ret && context.ok && 0 != context.configs_stack->used));
                   1131:        context_free(&context);
                   1132: 
                   1133:        if (0 != ret) {
                   1134:                return ret;
                   1135:        }
                   1136: 
                   1137:        if (NULL != (dc = (data_config *)array_get_element(srv->config_context, "global"))) {
                   1138:                srv->config = dc->value;
                   1139:        } else {
                   1140:                return -1;
                   1141:        }
                   1142: 
                   1143:        if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
                   1144:                data_string *ds;
                   1145:                data_array *prepends;
                   1146: 
                   1147:                if (modules->type != TYPE_ARRAY) {
                   1148:                        fprintf(stderr, "server.modules must be an array");
                   1149:                        return -1;
                   1150:                }
                   1151: 
                   1152:                prepends = data_array_init();
                   1153: 
                   1154:                /* prepend default modules */
                   1155:                if (NULL == array_get_element(modules->value, "mod_indexfile")) {
                   1156:                        ds = data_string_init();
                   1157:                        buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_indexfile"));
                   1158:                        array_insert_unique(prepends->value, (data_unset *)ds);
                   1159:                }
                   1160: 
                   1161:                prepends = (data_array *)configparser_merge_data((data_unset *)prepends, (data_unset *)modules);
                   1162:                buffer_copy_string_buffer(prepends->key, modules->key);
                   1163:                array_replace(srv->config, (data_unset *)prepends);
                   1164:                modules->free((data_unset *)modules);
                   1165:                modules = prepends;
                   1166: 
                   1167:                /* append default modules */
                   1168:                if (NULL == array_get_element(modules->value, "mod_dirlisting")) {
                   1169:                        ds = data_string_init();
                   1170:                        buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_dirlisting"));
                   1171:                        array_insert_unique(modules->value, (data_unset *)ds);
                   1172:                }
                   1173: 
                   1174:                if (NULL == array_get_element(modules->value, "mod_staticfile")) {
                   1175:                        ds = data_string_init();
                   1176:                        buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_staticfile"));
                   1177:                        array_insert_unique(modules->value, (data_unset *)ds);
                   1178:                }
                   1179:        } else {
                   1180:                data_string *ds;
                   1181: 
                   1182:                modules = data_array_init();
                   1183: 
                   1184:                /* server.modules is not set */
                   1185:                ds = data_string_init();
                   1186:                buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_indexfile"));
                   1187:                array_insert_unique(modules->value, (data_unset *)ds);
                   1188: 
                   1189:                ds = data_string_init();
                   1190:                buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_dirlisting"));
                   1191:                array_insert_unique(modules->value, (data_unset *)ds);
                   1192: 
                   1193:                ds = data_string_init();
                   1194:                buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_staticfile"));
                   1195:                array_insert_unique(modules->value, (data_unset *)ds);
                   1196: 
                   1197:                buffer_copy_string_len(modules->key, CONST_STR_LEN("server.modules"));
                   1198:                array_insert_unique(srv->config, (data_unset *)modules);
                   1199:        }
                   1200: 
                   1201: 
                   1202:        if (0 != config_insert(srv)) {
                   1203:                return -1;
                   1204:        }
                   1205: 
                   1206:        return 0;
                   1207: }
                   1208: 
                   1209: int config_set_defaults(server *srv) {
                   1210:        size_t i;
                   1211:        specific_config *s = srv->config_storage[0];
                   1212:        struct stat st1, st2;
                   1213: 
                   1214:        struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
                   1215:        {
                   1216:                /* - epoll is most reliable
                   1217:                 * - select works everywhere
                   1218:                 */
                   1219: #ifdef USE_LINUX_EPOLL
                   1220:                { FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
                   1221: #endif
                   1222: #ifdef USE_POLL
                   1223:                { FDEVENT_HANDLER_POLL,           "poll" },
                   1224: #endif
                   1225: #ifdef USE_SELECT
                   1226:                { FDEVENT_HANDLER_SELECT,         "select" },
                   1227: #endif
                   1228: #ifdef USE_LIBEV
                   1229:                { FDEVENT_HANDLER_LIBEV,          "libev" },
                   1230: #endif
                   1231: #ifdef USE_SOLARIS_DEVPOLL
                   1232:                { FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
                   1233: #endif
                   1234: #ifdef USE_SOLARIS_PORT
                   1235:                { FDEVENT_HANDLER_SOLARIS_PORT,   "solaris-eventports" },
                   1236: #endif
                   1237: #ifdef USE_FREEBSD_KQUEUE
                   1238:                { FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
                   1239:                { FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue" },
                   1240: #endif
                   1241:                { FDEVENT_HANDLER_UNSET,          NULL }
                   1242:        };
                   1243: 
                   1244:        if (!buffer_is_empty(srv->srvconf.changeroot)) {
                   1245:                if (-1 == stat(srv->srvconf.changeroot->ptr, &st1)) {
                   1246:                        log_error_write(srv, __FILE__, __LINE__, "sb",
                   1247:                                        "server.chroot doesn't exist:", srv->srvconf.changeroot);
                   1248:                        return -1;
                   1249:                }
                   1250:                if (!S_ISDIR(st1.st_mode)) {
                   1251:                        log_error_write(srv, __FILE__, __LINE__, "sb",
                   1252:                                        "server.chroot isn't a directory:", srv->srvconf.changeroot);
                   1253:                        return -1;
                   1254:                }
                   1255:        }
                   1256: 
                   1257:        if (buffer_is_empty(s->document_root)) {
                   1258:                log_error_write(srv, __FILE__, __LINE__, "s",
                   1259:                                "a default document-root has to be set");
                   1260: 
                   1261:                return -1;
                   1262:        }
                   1263: 
                   1264:        buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
                   1265: 
                   1266:        buffer_to_lower(srv->tmp_buf);
                   1267: 
                   1268:        if (2 == s->force_lowercase_filenames) { /* user didn't configure it in global section? */
                   1269:                s->force_lowercase_filenames = 0; /* default to 0 */
                   1270: 
                   1271:                if (0 == stat(srv->tmp_buf->ptr, &st1)) {
                   1272:                        int is_lower = 0;
                   1273: 
                   1274:                        is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
                   1275: 
                   1276:                        /* lower-case existed, check upper-case */
                   1277:                        buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
                   1278: 
                   1279:                        buffer_to_upper(srv->tmp_buf);
                   1280: 
                   1281:                        /* we have to handle the special case that upper and lower-casing results in the same filename
                   1282:                         * as in server.document-root = "/" or "/12345/" */
                   1283: 
                   1284:                        if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
                   1285:                                /* lower-casing and upper-casing didn't result in
                   1286:                                 * an other filename, no need to stat(),
                   1287:                                 * just assume it is case-sensitive. */
                   1288: 
                   1289:                                s->force_lowercase_filenames = 0;
                   1290:                        } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
                   1291: 
                   1292:                                /* upper case exists too, doesn't the FS handle this ? */
                   1293: 
                   1294:                                /* upper and lower have the same inode -> case-insensitve FS */
                   1295: 
                   1296:                                if (st1.st_ino == st2.st_ino) {
                   1297:                                        /* upper and lower have the same inode -> case-insensitve FS */
                   1298: 
                   1299:                                        s->force_lowercase_filenames = 1;
                   1300:                                }
                   1301:                        }
                   1302:                }
                   1303:        }
                   1304: 
                   1305:        if (srv->srvconf.port == 0) {
                   1306:                srv->srvconf.port = s->ssl_enabled ? 443 : 80;
                   1307:        }
                   1308: 
                   1309:        if (srv->srvconf.event_handler->used == 0) {
                   1310:                /* choose a good default
                   1311:                 *
                   1312:                 * the event_handler list is sorted by 'goodness'
                   1313:                 * taking the first available should be the best solution
                   1314:                 */
                   1315:                srv->event_handler = event_handlers[0].et;
                   1316: 
                   1317:                if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
                   1318:                        log_error_write(srv, __FILE__, __LINE__, "s",
                   1319:                                        "sorry, there is no event handler for this system");
                   1320: 
                   1321:                        return -1;
                   1322:                }
                   1323:        } else {
                   1324:                /*
                   1325:                 * User override
                   1326:                 */
                   1327: 
                   1328:                for (i = 0; event_handlers[i].name; i++) {
                   1329:                        if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
                   1330:                                srv->event_handler = event_handlers[i].et;
                   1331:                                break;
                   1332:                        }
                   1333:                }
                   1334: 
                   1335:                if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
                   1336:                        log_error_write(srv, __FILE__, __LINE__, "sb",
                   1337:                                        "the selected event-handler in unknown or not supported:",
                   1338:                                        srv->srvconf.event_handler );
                   1339: 
                   1340:                        return -1;
                   1341:                }
                   1342:        }
                   1343: 
                   1344:        if (s->ssl_enabled) {
                   1345:                if (buffer_is_empty(s->ssl_pemfile)) {
                   1346:                        /* PEM file is require */
                   1347: 
                   1348:                        log_error_write(srv, __FILE__, __LINE__, "s",
                   1349:                                        "ssl.pemfile has to be set");
                   1350:                        return -1;
                   1351:                }
                   1352: 
                   1353: #ifndef USE_OPENSSL
                   1354:                log_error_write(srv, __FILE__, __LINE__, "s",
                   1355:                                "ssl support is missing, recompile with --with-openssl");
                   1356: 
                   1357:                return -1;
                   1358: #endif
                   1359:        }
                   1360: 
                   1361:        return 0;
                   1362: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>