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

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: 
1.1.1.2 ! misho     158:        force_assert(srv->config_storage);
1.1       misho     159: 
                    160:        for (i = 0; i < srv->config_context->used; i++) {
                    161:                specific_config *s;
                    162: 
                    163:                s = calloc(1, sizeof(specific_config));
1.1.1.2 ! misho     164:                force_assert(s);
1.1       misho     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
1.1.1.2 ! misho     342:        PATCH(ssl_pemfile_x509);
        !           343:        PATCH(ssl_pemfile_pkey);
1.1       misho     344: #endif
                    345:        PATCH(ssl_ca_file);
1.1.1.2 ! misho     346: #ifdef USE_OPENSSL
        !           347:        PATCH(ssl_ca_file_cert_names);
        !           348: #endif
1.1       misho     349:        PATCH(ssl_cipher_list);
                    350:        PATCH(ssl_dh_file);
                    351:        PATCH(ssl_ec_curve);
                    352:        PATCH(ssl_honor_cipher_order);
                    353:        PATCH(ssl_empty_fragments);
                    354:        PATCH(ssl_use_sslv2);
                    355:        PATCH(ssl_use_sslv3);
                    356:        PATCH(etag_use_inode);
                    357:        PATCH(etag_use_mtime);
                    358:        PATCH(etag_use_size);
                    359: 
                    360:        PATCH(ssl_verifyclient);
                    361:        PATCH(ssl_verifyclient_enforce);
                    362:        PATCH(ssl_verifyclient_depth);
                    363:        PATCH(ssl_verifyclient_username);
                    364:        PATCH(ssl_verifyclient_export_cert);
                    365:        PATCH(ssl_disable_client_renegotiation);
                    366: 
                    367:        return 0;
                    368: }
                    369: 
                    370: int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
                    371:        size_t i, j;
                    372: 
                    373:        con->conditional_is_valid[comp] = 1;
                    374: 
                    375:        /* skip the first, the global context */
                    376:        for (i = 1; i < srv->config_context->used; i++) {
                    377:                data_config *dc = (data_config *)srv->config_context->data[i];
                    378:                specific_config *s = srv->config_storage[i];
                    379: 
                    380:                /* condition didn't match */
                    381:                if (!config_check_cond(srv, con, dc)) continue;
                    382: 
                    383:                /* merge config */
                    384:                for (j = 0; j < dc->value->used; j++) {
                    385:                        data_unset *du = dc->value->data[j];
                    386: 
                    387:                        if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
                    388:                                PATCH(document_root);
                    389:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
                    390:                                PATCH(range_requests);
                    391:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.error-handler-404"))) {
                    392:                                PATCH(error_handler);
                    393:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.errorfile-prefix"))) {
                    394:                                PATCH(errorfile_prefix);
                    395:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.assign"))) {
                    396:                                PATCH(mimetypes);
                    397:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-keep-alive-requests"))) {
                    398:                                PATCH(max_keep_alive_requests);
                    399:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-keep-alive-idle"))) {
                    400:                                PATCH(max_keep_alive_idle);
                    401:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-write-idle"))) {
                    402:                                PATCH(max_write_idle);
                    403:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-read-idle"))) {
                    404:                                PATCH(max_read_idle);
                    405:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.use-xattr"))) {
                    406:                                PATCH(use_xattr);
                    407:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-inode"))) {
                    408:                                PATCH(etag_use_inode);
                    409:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-mtime"))) {
                    410:                                PATCH(etag_use_mtime);
                    411:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-size"))) {
                    412:                                PATCH(etag_use_size);
                    413:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.pemfile"))) {
                    414:                                PATCH(ssl_pemfile);
                    415: #ifdef USE_OPENSSL
1.1.1.2 ! misho     416:                                PATCH(ssl_pemfile_x509);
        !           417:                                PATCH(ssl_pemfile_pkey);
1.1       misho     418: #endif
                    419:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ca-file"))) {
                    420:                                PATCH(ssl_ca_file);
1.1.1.2 ! misho     421: #ifdef USE_OPENSSL
        !           422:                                PATCH(ssl_ca_file_cert_names);
        !           423: #endif
1.1       misho     424:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.honor-cipher-order"))) {
                    425:                                PATCH(ssl_honor_cipher_order);
                    426:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.empty-fragments"))) {
                    427:                                PATCH(ssl_empty_fragments);
                    428:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv2"))) {
                    429:                                PATCH(ssl_use_sslv2);
                    430:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv3"))) {
                    431:                                PATCH(ssl_use_sslv3);
                    432:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.cipher-list"))) {
                    433:                                PATCH(ssl_cipher_list);
                    434:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) {
                    435:                                PATCH(ssl_enabled);
                    436:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.dh-file"))) {
                    437:                                PATCH(ssl_dh_file);
                    438:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ec-curve"))) {
                    439:                                PATCH(ssl_ec_curve);
                    440: #ifdef HAVE_LSTAT
                    441:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.follow-symlink"))) {
                    442:                                PATCH(follow_symlink);
                    443: #endif
                    444:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.name"))) {
                    445:                                buffer_copy_string_buffer(con->server_name, s->server_name);
                    446:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.tag"))) {
                    447:                                PATCH(server_tag);
                    448:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("connection.kbytes-per-second"))) {
                    449:                                PATCH(kbytes_per_second);
                    450:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-request-handling"))) {
                    451:                                PATCH(log_request_handling);
                    452:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-request-header"))) {
                    453:                                PATCH(log_request_header);
                    454:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-response-header"))) {
                    455:                                PATCH(log_response_header);
                    456:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
                    457:                                PATCH(log_condition_handling);
                    458:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
                    459:                                PATCH(log_file_not_found);
                    460:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-ssl-noise"))) {
                    461:                                PATCH(log_ssl_noise);
                    462:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-timeouts"))) {
                    463:                                PATCH(log_timeouts);
                    464:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
                    465:                                PATCH(allow_http11);
                    466:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
                    467:                                PATCH(force_lowercase_filenames);
                    468:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
                    469:                                PATCH(global_kbytes_per_second);
                    470:                                PATCH(global_bytes_per_second_cnt);
                    471:                                con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
                    472:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.activate"))) {
                    473:                                PATCH(ssl_verifyclient);
                    474:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.enforce"))) {
                    475:                                PATCH(ssl_verifyclient_enforce);
                    476:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.depth"))) {
                    477:                                PATCH(ssl_verifyclient_depth);
                    478:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.username"))) {
                    479:                                PATCH(ssl_verifyclient_username);
                    480:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.exportcert"))) {
                    481:                                PATCH(ssl_verifyclient_export_cert);
                    482:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.disable-client-renegotiation"))) {
                    483:                                PATCH(ssl_disable_client_renegotiation);
                    484:                        }
                    485:                }
                    486:        }
                    487: 
                    488:                con->etag_flags = (con->conf.etag_use_mtime ? ETAG_USE_MTIME : 0) |
                    489:                                  (con->conf.etag_use_inode ? ETAG_USE_INODE : 0) |
                    490:                                  (con->conf.etag_use_size  ? ETAG_USE_SIZE  : 0);
                    491: 
                    492:        return 0;
                    493: }
                    494: #undef PATCH
                    495: 
                    496: typedef struct {
                    497:        int foo;
                    498:        int bar;
                    499: 
                    500:        const buffer *source;
                    501:        const char *input;
                    502:        size_t offset;
                    503:        size_t size;
                    504: 
                    505:        int line_pos;
                    506:        int line;
                    507: 
                    508:        int in_key;
                    509:        int in_brace;
                    510:        int in_cond;
                    511: } tokenizer_t;
                    512: 
                    513: #if 0
                    514: static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const char *fn) {
                    515:        if (buffer_is_empty(basedir) ||
                    516:                        (fn[0] == '/' || fn[0] == '\\') ||
                    517:                        (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
                    518:                t->file = buffer_init_string(fn);
                    519:        } else {
                    520:                t->file = buffer_init_buffer(basedir);
                    521:                buffer_append_string(t->file, fn);
                    522:        }
                    523: 
                    524:        if (0 != stream_open(&(t->s), t->file)) {
                    525:                log_error_write(srv, __FILE__, __LINE__, "sbss",
                    526:                                "opening configfile ", t->file, "failed:", strerror(errno));
                    527:                buffer_free(t->file);
                    528:                return -1;
                    529:        }
                    530: 
                    531:        t->input = t->s.start;
                    532:        t->offset = 0;
                    533:        t->size = t->s.size;
                    534:        t->line = 1;
                    535:        t->line_pos = 1;
                    536: 
                    537:        t->in_key = 1;
                    538:        t->in_brace = 0;
                    539:        t->in_cond = 0;
                    540:        return 0;
                    541: }
                    542: 
                    543: static int tokenizer_close(server *srv, tokenizer_t *t) {
                    544:        UNUSED(srv);
                    545: 
                    546:        buffer_free(t->file);
                    547:        return stream_close(&(t->s));
                    548: }
                    549: #endif
                    550: static int config_skip_newline(tokenizer_t *t) {
                    551:        int skipped = 1;
1.1.1.2 ! misho     552:        force_assert(t->input[t->offset] == '\r' || t->input[t->offset] == '\n');
1.1       misho     553:        if (t->input[t->offset] == '\r' && t->input[t->offset + 1] == '\n') {
                    554:                skipped ++;
                    555:                t->offset ++;
                    556:        }
                    557:        t->offset ++;
                    558:        return skipped;
                    559: }
                    560: 
                    561: static int config_skip_comment(tokenizer_t *t) {
                    562:        int i;
1.1.1.2 ! misho     563:        force_assert(t->input[t->offset] == '#');
1.1       misho     564:        for (i = 1; t->input[t->offset + i] &&
                    565:             (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
                    566:             i++);
                    567:        t->offset += i;
                    568:        return i;
                    569: }
                    570: 
                    571: static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
                    572:        int tid = 0;
                    573:        size_t i;
                    574: 
                    575:        for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
                    576:                char c = t->input[t->offset];
                    577:                const char *start = NULL;
                    578: 
                    579:                switch (c) {
                    580:                case '=':
                    581:                        if (t->in_brace) {
                    582:                                if (t->input[t->offset + 1] == '>') {
                    583:                                        t->offset += 2;
                    584: 
                    585:                                        buffer_copy_string_len(token, CONST_STR_LEN("=>"));
                    586: 
                    587:                                        tid = TK_ARRAY_ASSIGN;
                    588:                                } else {
                    589:                                        log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    590:                                                        "source:", t->source,
                    591:                                                        "line:", t->line, "pos:", t->line_pos,
                    592:                                                        "use => for assignments in arrays");
                    593:                                        return -1;
                    594:                                }
                    595:                        } else if (t->in_cond) {
                    596:                                if (t->input[t->offset + 1] == '=') {
                    597:                                        t->offset += 2;
                    598: 
                    599:                                        buffer_copy_string_len(token, CONST_STR_LEN("=="));
                    600: 
                    601:                                        tid = TK_EQ;
                    602:                                } else if (t->input[t->offset + 1] == '~') {
                    603:                                        t->offset += 2;
                    604: 
                    605:                                        buffer_copy_string_len(token, CONST_STR_LEN("=~"));
                    606: 
                    607:                                        tid = TK_MATCH;
                    608:                                } else {
                    609:                                        log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    610:                                                        "source:", t->source,
                    611:                                                        "line:", t->line, "pos:", t->line_pos,
                    612:                                                        "only =~ and == are allowed in the condition");
                    613:                                        return -1;
                    614:                                }
                    615:                                t->in_key = 1;
                    616:                                t->in_cond = 0;
                    617:                        } else if (t->in_key) {
                    618:                                tid = TK_ASSIGN;
                    619: 
                    620:                                buffer_copy_string_len(token, t->input + t->offset, 1);
                    621: 
                    622:                                t->offset++;
                    623:                                t->line_pos++;
                    624:                        } else {
                    625:                                log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    626:                                                "source:", t->source,
                    627:                                                "line:", t->line, "pos:", t->line_pos,
                    628:                                                "unexpected equal-sign: =");
                    629:                                return -1;
                    630:                        }
                    631: 
                    632:                        break;
                    633:                case '!':
                    634:                        if (t->in_cond) {
                    635:                                if (t->input[t->offset + 1] == '=') {
                    636:                                        t->offset += 2;
                    637: 
                    638:                                        buffer_copy_string_len(token, CONST_STR_LEN("!="));
                    639: 
                    640:                                        tid = TK_NE;
                    641:                                } else if (t->input[t->offset + 1] == '~') {
                    642:                                        t->offset += 2;
                    643: 
                    644:                                        buffer_copy_string_len(token, CONST_STR_LEN("!~"));
                    645: 
                    646:                                        tid = TK_NOMATCH;
                    647:                                } else {
                    648:                                        log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    649:                                                        "source:", t->source,
                    650:                                                        "line:", t->line, "pos:", t->line_pos,
                    651:                                                        "only !~ and != are allowed in the condition");
                    652:                                        return -1;
                    653:                                }
                    654:                                t->in_key = 1;
                    655:                                t->in_cond = 0;
                    656:                        } else {
                    657:                                log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    658:                                                "source:", t->source,
                    659:                                                "line:", t->line, "pos:", t->line_pos,
                    660:                                                "unexpected exclamation-marks: !");
                    661:                                return -1;
                    662:                        }
                    663: 
                    664:                        break;
                    665:                case '\t':
                    666:                case ' ':
                    667:                        t->offset++;
                    668:                        t->line_pos++;
                    669:                        break;
                    670:                case '\n':
                    671:                case '\r':
                    672:                        if (t->in_brace == 0) {
                    673:                                int done = 0;
                    674:                                while (!done && t->offset < t->size) {
                    675:                                        switch (t->input[t->offset]) {
                    676:                                        case '\r':
                    677:                                        case '\n':
                    678:                                                config_skip_newline(t);
                    679:                                                t->line_pos = 1;
                    680:                                                t->line++;
                    681:                                                break;
                    682: 
                    683:                                        case '#':
                    684:                                                t->line_pos += config_skip_comment(t);
                    685:                                                break;
                    686: 
                    687:                                        case '\t':
                    688:                                        case ' ':
                    689:                                                t->offset++;
                    690:                                                t->line_pos++;
                    691:                                                break;
                    692: 
                    693:                                        default:
                    694:                                                done = 1;
                    695:                                        }
                    696:                                }
                    697:                                t->in_key = 1;
                    698:                                tid = TK_EOL;
                    699:                                buffer_copy_string_len(token, CONST_STR_LEN("(EOL)"));
                    700:                        } else {
                    701:                                config_skip_newline(t);
                    702:                                t->line_pos = 1;
                    703:                                t->line++;
                    704:                        }
                    705:                        break;
                    706:                case ',':
                    707:                        if (t->in_brace > 0) {
                    708:                                tid = TK_COMMA;
                    709: 
                    710:                                buffer_copy_string_len(token, CONST_STR_LEN("(COMMA)"));
                    711:                        }
                    712: 
                    713:                        t->offset++;
                    714:                        t->line_pos++;
                    715:                        break;
                    716:                case '"':
                    717:                        /* search for the terminating " */
                    718:                        start = t->input + t->offset + 1;
                    719:                        buffer_copy_string_len(token, CONST_STR_LEN(""));
                    720: 
                    721:                        for (i = 1; t->input[t->offset + i]; i++) {
                    722:                                if (t->input[t->offset + i] == '\\' &&
                    723:                                    t->input[t->offset + i + 1] == '"') {
                    724: 
                    725:                                        buffer_append_string_len(token, start, t->input + t->offset + i - start);
                    726: 
                    727:                                        start = t->input + t->offset + i + 1;
                    728: 
                    729:                                        /* skip the " */
                    730:                                        i++;
                    731:                                        continue;
                    732:                                }
                    733: 
                    734: 
                    735:                                if (t->input[t->offset + i] == '"') {
                    736:                                        tid = TK_STRING;
                    737: 
                    738:                                        buffer_append_string_len(token, start, t->input + t->offset + i - start);
                    739: 
                    740:                                        break;
                    741:                                }
                    742:                        }
                    743: 
                    744:                        if (t->input[t->offset + i] == '\0') {
                    745:                                /* ERROR */
                    746: 
                    747:                                log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    748:                                                "source:", t->source,
                    749:                                                "line:", t->line, "pos:", t->line_pos,
                    750:                                                "missing closing quote");
                    751: 
                    752:                                return -1;
                    753:                        }
                    754: 
                    755:                        t->offset += i + 1;
                    756:                        t->line_pos += i + 1;
                    757: 
                    758:                        break;
                    759:                case '(':
                    760:                        t->offset++;
                    761:                        t->in_brace++;
                    762: 
                    763:                        tid = TK_LPARAN;
                    764: 
                    765:                        buffer_copy_string_len(token, CONST_STR_LEN("("));
                    766:                        break;
                    767:                case ')':
                    768:                        t->offset++;
                    769:                        t->in_brace--;
                    770: 
                    771:                        tid = TK_RPARAN;
                    772: 
                    773:                        buffer_copy_string_len(token, CONST_STR_LEN(")"));
                    774:                        break;
                    775:                case '$':
                    776:                        t->offset++;
                    777: 
                    778:                        tid = TK_DOLLAR;
                    779:                        t->in_cond = 1;
                    780:                        t->in_key = 0;
                    781: 
                    782:                        buffer_copy_string_len(token, CONST_STR_LEN("$"));
                    783: 
                    784:                        break;
                    785: 
                    786:                case '+':
                    787:                        if (t->input[t->offset + 1] == '=') {
                    788:                                t->offset += 2;
                    789:                                buffer_copy_string_len(token, CONST_STR_LEN("+="));
                    790:                                tid = TK_APPEND;
                    791:                        } else {
                    792:                                t->offset++;
                    793:                                tid = TK_PLUS;
                    794:                                buffer_copy_string_len(token, CONST_STR_LEN("+"));
                    795:                        }
                    796:                        break;
                    797: 
                    798:                case '{':
                    799:                        t->offset++;
                    800: 
                    801:                        tid = TK_LCURLY;
                    802: 
                    803:                        buffer_copy_string_len(token, CONST_STR_LEN("{"));
                    804: 
                    805:                        break;
                    806: 
                    807:                case '}':
                    808:                        t->offset++;
                    809: 
                    810:                        tid = TK_RCURLY;
                    811: 
                    812:                        buffer_copy_string_len(token, CONST_STR_LEN("}"));
                    813: 
                    814:                        break;
                    815: 
                    816:                case '[':
                    817:                        t->offset++;
                    818: 
                    819:                        tid = TK_LBRACKET;
                    820: 
                    821:                        buffer_copy_string_len(token, CONST_STR_LEN("["));
                    822: 
                    823:                        break;
                    824: 
                    825:                case ']':
                    826:                        t->offset++;
                    827: 
                    828:                        tid = TK_RBRACKET;
                    829: 
                    830:                        buffer_copy_string_len(token, CONST_STR_LEN("]"));
                    831: 
                    832:                        break;
                    833:                case '#':
                    834:                        t->line_pos += config_skip_comment(t);
                    835: 
                    836:                        break;
                    837:                default:
                    838:                        if (t->in_cond) {
                    839:                                for (i = 0; t->input[t->offset + i] &&
                    840:                                     (isalpha((unsigned char)t->input[t->offset + i])
                    841:                                      ); i++);
                    842: 
                    843:                                if (i && t->input[t->offset + i]) {
                    844:                                        tid = TK_SRVVARNAME;
                    845:                                        buffer_copy_string_len(token, t->input + t->offset, i);
                    846: 
                    847:                                        t->offset += i;
                    848:                                        t->line_pos += i;
                    849:                                } else {
                    850:                                        /* ERROR */
                    851:                                        log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    852:                                                        "source:", t->source,
                    853:                                                        "line:", t->line, "pos:", t->line_pos,
                    854:                                                        "invalid character in condition");
                    855:                                        return -1;
                    856:                                }
                    857:                        } else if (isdigit((unsigned char)c)) {
                    858:                                /* take all digits */
                    859:                                for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]);  i++);
                    860: 
                    861:                                /* was there it least a digit ? */
                    862:                                if (i) {
                    863:                                        tid = TK_INTEGER;
                    864: 
                    865:                                        buffer_copy_string_len(token, t->input + t->offset, i);
                    866: 
                    867:                                        t->offset += i;
                    868:                                        t->line_pos += i;
                    869:                                }
                    870:                        } else {
                    871:                                /* the key might consist of [-.0-9a-z] */
                    872:                                for (i = 0; t->input[t->offset + i] &&
                    873:                                     (isalnum((unsigned char)t->input[t->offset + i]) ||
                    874:                                      t->input[t->offset + i] == '.' ||
                    875:                                      t->input[t->offset + i] == '_' || /* for env.* */
                    876:                                      t->input[t->offset + i] == '-'
                    877:                                      ); i++);
                    878: 
                    879:                                if (i && t->input[t->offset + i]) {
                    880:                                        buffer_copy_string_len(token, t->input + t->offset, i);
                    881: 
                    882:                                        if (strcmp(token->ptr, "include") == 0) {
                    883:                                                tid = TK_INCLUDE;
                    884:                                        } else if (strcmp(token->ptr, "include_shell") == 0) {
                    885:                                                tid = TK_INCLUDE_SHELL;
                    886:                                        } else if (strcmp(token->ptr, "global") == 0) {
                    887:                                                tid = TK_GLOBAL;
                    888:                                        } else if (strcmp(token->ptr, "else") == 0) {
                    889:                                                tid = TK_ELSE;
                    890:                                        } else {
                    891:                                                tid = TK_LKEY;
                    892:                                        }
                    893: 
                    894:                                        t->offset += i;
                    895:                                        t->line_pos += i;
                    896:                                } else {
                    897:                                        /* ERROR */
                    898:                                        log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
                    899:                                                        "source:", t->source,
                    900:                                                        "line:", t->line, "pos:", t->line_pos,
                    901:                                                        "invalid character in variable name");
                    902:                                        return -1;
                    903:                                }
                    904:                        }
                    905:                        break;
                    906:                }
                    907:        }
                    908: 
                    909:        if (tid) {
                    910:                *token_id = tid;
                    911: #if 0
                    912:                log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
                    913:                                "source:", t->source,
                    914:                                "line:", t->line, "pos:", t->line_pos,
                    915:                                token, token->used - 1, tid);
                    916: #endif
                    917: 
                    918:                return 1;
                    919:        } else if (t->offset < t->size) {
                    920:                fprintf(stderr, "%s.%d: %d, %s\n",
                    921:                        __FILE__, __LINE__,
                    922:                        tid, token->ptr);
                    923:        }
                    924:        return 0;
                    925: }
                    926: 
                    927: static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
                    928:        void *pParser;
                    929:        int token_id;
                    930:        buffer *token, *lasttoken;
                    931:        int ret;
                    932: 
                    933:        pParser = configparserAlloc( malloc );
                    934:        lasttoken = buffer_init();
                    935:        token = buffer_init();
                    936:        while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
                    937:                buffer_copy_string_buffer(lasttoken, token);
                    938:                configparser(pParser, token_id, token, context);
                    939: 
                    940:                token = buffer_init();
                    941:        }
                    942:        buffer_free(token);
                    943: 
                    944:        if (ret != -1 && context->ok) {
                    945:                /* add an EOL at EOF, better than say sorry */
                    946:                configparser(pParser, TK_EOL, buffer_init_string("(EOL)"), context);
                    947:                if (context->ok) {
                    948:                        configparser(pParser, 0, NULL, context);
                    949:                }
                    950:        }
                    951:        configparserFree(pParser, free);
                    952: 
                    953:        if (ret == -1) {
                    954:                log_error_write(srv, __FILE__, __LINE__, "sb",
                    955:                                "configfile parser failed at:", lasttoken);
                    956:        } else if (context->ok == 0) {
                    957:                log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
                    958:                                "source:", t->source,
                    959:                                "line:", t->line, "pos:", t->line_pos,
                    960:                                "parser failed somehow near here:", lasttoken);
                    961:                ret = -1;
                    962:        }
                    963:        buffer_free(lasttoken);
                    964: 
                    965:        return ret == -1 ? -1 : 0;
                    966: }
                    967: 
                    968: static int tokenizer_init(tokenizer_t *t, const buffer *source, const char *input, size_t size) {
                    969: 
                    970:        t->source = source;
                    971:        t->input = input;
                    972:        t->size = size;
                    973:        t->offset = 0;
                    974:        t->line = 1;
                    975:        t->line_pos = 1;
                    976: 
                    977:        t->in_key = 1;
                    978:        t->in_brace = 0;
                    979:        t->in_cond = 0;
                    980:        return 0;
                    981: }
                    982: 
                    983: int config_parse_file(server *srv, config_t *context, const char *fn) {
                    984:        tokenizer_t t;
                    985:        stream s;
                    986:        int ret;
                    987:        buffer *filename;
                    988: 
                    989:        if (buffer_is_empty(context->basedir) ||
                    990:                        (fn[0] == '/' || fn[0] == '\\') ||
                    991:                        (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
                    992:                filename = buffer_init_string(fn);
                    993:        } else {
                    994:                filename = buffer_init_buffer(context->basedir);
                    995:                buffer_append_string(filename, fn);
                    996:        }
                    997: 
                    998:        if (0 != stream_open(&s, filename)) {
                    999:                if (s.size == 0) {
                   1000:                        /* the file was empty, nothing to parse */
                   1001:                        ret = 0;
                   1002:                } else {
                   1003:                        log_error_write(srv, __FILE__, __LINE__, "sbss",
                   1004:                                        "opening configfile ", filename, "failed:", strerror(errno));
                   1005:                        ret = -1;
                   1006:                } 
                   1007:        } else {
                   1008:                tokenizer_init(&t, filename, s.start, s.size);
                   1009:                ret = config_parse(srv, context, &t);
                   1010:        }
                   1011: 
                   1012:        stream_close(&s);
                   1013:        buffer_free(filename);
                   1014:        return ret;
                   1015: }
                   1016: 
                   1017: static char* getCWD(void) {
                   1018:        char *s, *s1;
                   1019:        size_t len;
                   1020: #ifdef PATH_MAX
                   1021:        len = PATH_MAX;
                   1022: #else
                   1023:        len = 4096;
                   1024: #endif
                   1025: 
                   1026:        s = malloc(len);
                   1027:        if (!s) return NULL;
                   1028:        while (NULL == getcwd(s, len)) {
1.1.1.2 ! misho    1029:                if (errno != ERANGE || SSIZE_MAX - len < len) {
        !          1030:                        free(s);
        !          1031:                        return NULL;
        !          1032:                }
1.1       misho    1033:                len *= 2;
                   1034:                s1 = realloc(s, len);
                   1035:                if (!s1) {
                   1036:                        free(s);
                   1037:                        return NULL;
                   1038:                }
                   1039:                s = s1;
                   1040:        }
                   1041:        return s;
                   1042: }
                   1043: 
                   1044: int config_parse_cmd(server *srv, config_t *context, const char *cmd) {
                   1045:        tokenizer_t t;
                   1046:        int ret;
                   1047:        buffer *source;
                   1048:        buffer *out;
                   1049:        char *oldpwd;
                   1050: 
                   1051:        if (NULL == (oldpwd = getCWD())) {
                   1052:                log_error_write(srv, __FILE__, __LINE__, "s",
                   1053:                                "cannot get cwd", strerror(errno));
                   1054:                return -1;
                   1055:        }
                   1056: 
                   1057:        source = buffer_init_string(cmd);
                   1058:        out = buffer_init();
                   1059: 
                   1060:        if (!buffer_is_empty(context->basedir)) {
                   1061:                chdir(context->basedir->ptr);
                   1062:        }
                   1063: 
                   1064:        if (0 != proc_open_buffer(cmd, NULL, out, NULL)) {
                   1065:                log_error_write(srv, __FILE__, __LINE__, "sbss",
                   1066:                                "opening", source, "failed:", strerror(errno));
                   1067:                ret = -1;
                   1068:        } else {
                   1069:                tokenizer_init(&t, source, out->ptr, out->used);
                   1070:                ret = config_parse(srv, context, &t);
                   1071:        }
                   1072: 
                   1073:        buffer_free(source);
                   1074:        buffer_free(out);
                   1075:        chdir(oldpwd);
                   1076:        free(oldpwd);
                   1077:        return ret;
                   1078: }
                   1079: 
                   1080: static void context_init(server *srv, config_t *context) {
                   1081:        context->srv = srv;
                   1082:        context->ok = 1;
                   1083:        context->configs_stack = array_init();
                   1084:        context->configs_stack->is_weakref = 1;
                   1085:        context->basedir = buffer_init();
                   1086: }
                   1087: 
                   1088: static void context_free(config_t *context) {
                   1089:        array_free(context->configs_stack);
                   1090:        buffer_free(context->basedir);
                   1091: }
                   1092: 
                   1093: int config_read(server *srv, const char *fn) {
                   1094:        config_t context;
                   1095:        data_config *dc;
                   1096:        data_integer *dpid;
                   1097:        data_string *dcwd;
                   1098:        int ret;
                   1099:        char *pos;
                   1100:        data_array *modules;
                   1101: 
                   1102:        context_init(srv, &context);
                   1103:        context.all_configs = srv->config_context;
                   1104: 
                   1105: #ifdef __WIN32
                   1106:        pos = strrchr(fn, '\\');
                   1107: #else
                   1108:        pos = strrchr(fn, '/');
                   1109: #endif
                   1110:        if (pos) {
                   1111:                buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
                   1112:                fn = pos + 1;
                   1113:        }
                   1114: 
                   1115:        dc = data_config_init();
                   1116:        buffer_copy_string_len(dc->key, CONST_STR_LEN("global"));
                   1117: 
1.1.1.2 ! misho    1118:        force_assert(context.all_configs->used == 0);
1.1       misho    1119:        dc->context_ndx = context.all_configs->used;
                   1120:        array_insert_unique(context.all_configs, (data_unset *)dc);
                   1121:        context.current = dc;
                   1122: 
                   1123:        /* default context */
                   1124:        srv->config = dc->value;
                   1125:        dpid = data_integer_init();
                   1126:        dpid->value = getpid();
                   1127:        buffer_copy_string_len(dpid->key, CONST_STR_LEN("var.PID"));
                   1128:        array_insert_unique(srv->config, (data_unset *)dpid);
                   1129: 
                   1130:        dcwd = data_string_init();
                   1131:        buffer_prepare_copy(dcwd->value, 1024);
                   1132:        if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
                   1133:                dcwd->value->used = strlen(dcwd->value->ptr) + 1;
                   1134:                buffer_copy_string_len(dcwd->key, CONST_STR_LEN("var.CWD"));
                   1135:                array_insert_unique(srv->config, (data_unset *)dcwd);
1.1.1.2 ! misho    1136:        } else {
        !          1137:                dcwd->free((data_unset*) dcwd);
1.1       misho    1138:        }
                   1139: 
                   1140:        ret = config_parse_file(srv, &context, fn);
                   1141: 
                   1142:        /* remains nothing if parser is ok */
1.1.1.2 ! misho    1143:        force_assert(!(0 == ret && context.ok && 0 != context.configs_stack->used));
1.1       misho    1144:        context_free(&context);
                   1145: 
                   1146:        if (0 != ret) {
                   1147:                return ret;
                   1148:        }
                   1149: 
                   1150:        if (NULL != (dc = (data_config *)array_get_element(srv->config_context, "global"))) {
                   1151:                srv->config = dc->value;
                   1152:        } else {
                   1153:                return -1;
                   1154:        }
                   1155: 
                   1156:        if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
                   1157:                data_string *ds;
                   1158:                data_array *prepends;
                   1159: 
                   1160:                if (modules->type != TYPE_ARRAY) {
                   1161:                        fprintf(stderr, "server.modules must be an array");
                   1162:                        return -1;
                   1163:                }
                   1164: 
                   1165:                prepends = data_array_init();
                   1166: 
                   1167:                /* prepend default modules */
                   1168:                if (NULL == array_get_element(modules->value, "mod_indexfile")) {
                   1169:                        ds = data_string_init();
                   1170:                        buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_indexfile"));
                   1171:                        array_insert_unique(prepends->value, (data_unset *)ds);
                   1172:                }
                   1173: 
                   1174:                prepends = (data_array *)configparser_merge_data((data_unset *)prepends, (data_unset *)modules);
1.1.1.2 ! misho    1175:                force_assert(NULL != prepends);
1.1       misho    1176:                buffer_copy_string_buffer(prepends->key, modules->key);
                   1177:                array_replace(srv->config, (data_unset *)prepends);
                   1178:                modules->free((data_unset *)modules);
                   1179:                modules = prepends;
                   1180: 
                   1181:                /* append default modules */
                   1182:                if (NULL == array_get_element(modules->value, "mod_dirlisting")) {
                   1183:                        ds = data_string_init();
                   1184:                        buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_dirlisting"));
                   1185:                        array_insert_unique(modules->value, (data_unset *)ds);
                   1186:                }
                   1187: 
                   1188:                if (NULL == array_get_element(modules->value, "mod_staticfile")) {
                   1189:                        ds = data_string_init();
                   1190:                        buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_staticfile"));
                   1191:                        array_insert_unique(modules->value, (data_unset *)ds);
                   1192:                }
                   1193:        } else {
                   1194:                data_string *ds;
                   1195: 
                   1196:                modules = data_array_init();
                   1197: 
                   1198:                /* server.modules is not set */
                   1199:                ds = data_string_init();
                   1200:                buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_indexfile"));
                   1201:                array_insert_unique(modules->value, (data_unset *)ds);
                   1202: 
                   1203:                ds = data_string_init();
                   1204:                buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_dirlisting"));
                   1205:                array_insert_unique(modules->value, (data_unset *)ds);
                   1206: 
                   1207:                ds = data_string_init();
                   1208:                buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_staticfile"));
                   1209:                array_insert_unique(modules->value, (data_unset *)ds);
                   1210: 
                   1211:                buffer_copy_string_len(modules->key, CONST_STR_LEN("server.modules"));
                   1212:                array_insert_unique(srv->config, (data_unset *)modules);
                   1213:        }
                   1214: 
                   1215: 
                   1216:        if (0 != config_insert(srv)) {
                   1217:                return -1;
                   1218:        }
                   1219: 
                   1220:        return 0;
                   1221: }
                   1222: 
                   1223: int config_set_defaults(server *srv) {
                   1224:        size_t i;
                   1225:        specific_config *s = srv->config_storage[0];
                   1226:        struct stat st1, st2;
                   1227: 
                   1228:        struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
                   1229:        {
                   1230:                /* - epoll is most reliable
                   1231:                 * - select works everywhere
                   1232:                 */
                   1233: #ifdef USE_LINUX_EPOLL
                   1234:                { FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
                   1235: #endif
                   1236: #ifdef USE_POLL
                   1237:                { FDEVENT_HANDLER_POLL,           "poll" },
                   1238: #endif
                   1239: #ifdef USE_SELECT
                   1240:                { FDEVENT_HANDLER_SELECT,         "select" },
                   1241: #endif
                   1242: #ifdef USE_LIBEV
                   1243:                { FDEVENT_HANDLER_LIBEV,          "libev" },
                   1244: #endif
                   1245: #ifdef USE_SOLARIS_DEVPOLL
                   1246:                { FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
                   1247: #endif
                   1248: #ifdef USE_SOLARIS_PORT
                   1249:                { FDEVENT_HANDLER_SOLARIS_PORT,   "solaris-eventports" },
                   1250: #endif
                   1251: #ifdef USE_FREEBSD_KQUEUE
                   1252:                { FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
                   1253:                { FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue" },
                   1254: #endif
                   1255:                { FDEVENT_HANDLER_UNSET,          NULL }
                   1256:        };
                   1257: 
                   1258:        if (!buffer_is_empty(srv->srvconf.changeroot)) {
                   1259:                if (-1 == stat(srv->srvconf.changeroot->ptr, &st1)) {
                   1260:                        log_error_write(srv, __FILE__, __LINE__, "sb",
                   1261:                                        "server.chroot doesn't exist:", srv->srvconf.changeroot);
                   1262:                        return -1;
                   1263:                }
                   1264:                if (!S_ISDIR(st1.st_mode)) {
                   1265:                        log_error_write(srv, __FILE__, __LINE__, "sb",
                   1266:                                        "server.chroot isn't a directory:", srv->srvconf.changeroot);
                   1267:                        return -1;
                   1268:                }
                   1269:        }
                   1270: 
                   1271:        if (buffer_is_empty(s->document_root)) {
                   1272:                log_error_write(srv, __FILE__, __LINE__, "s",
                   1273:                                "a default document-root has to be set");
                   1274: 
                   1275:                return -1;
                   1276:        }
                   1277: 
                   1278:        buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
                   1279: 
                   1280:        buffer_to_lower(srv->tmp_buf);
                   1281: 
                   1282:        if (2 == s->force_lowercase_filenames) { /* user didn't configure it in global section? */
                   1283:                s->force_lowercase_filenames = 0; /* default to 0 */
                   1284: 
                   1285:                if (0 == stat(srv->tmp_buf->ptr, &st1)) {
                   1286:                        int is_lower = 0;
                   1287: 
                   1288:                        is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
                   1289: 
                   1290:                        /* lower-case existed, check upper-case */
                   1291:                        buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
                   1292: 
                   1293:                        buffer_to_upper(srv->tmp_buf);
                   1294: 
                   1295:                        /* we have to handle the special case that upper and lower-casing results in the same filename
                   1296:                         * as in server.document-root = "/" or "/12345/" */
                   1297: 
                   1298:                        if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
                   1299:                                /* lower-casing and upper-casing didn't result in
                   1300:                                 * an other filename, no need to stat(),
                   1301:                                 * just assume it is case-sensitive. */
                   1302: 
                   1303:                                s->force_lowercase_filenames = 0;
                   1304:                        } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
                   1305: 
                   1306:                                /* upper case exists too, doesn't the FS handle this ? */
                   1307: 
                   1308:                                /* upper and lower have the same inode -> case-insensitve FS */
                   1309: 
                   1310:                                if (st1.st_ino == st2.st_ino) {
                   1311:                                        /* upper and lower have the same inode -> case-insensitve FS */
                   1312: 
                   1313:                                        s->force_lowercase_filenames = 1;
                   1314:                                }
                   1315:                        }
                   1316:                }
                   1317:        }
                   1318: 
                   1319:        if (srv->srvconf.port == 0) {
                   1320:                srv->srvconf.port = s->ssl_enabled ? 443 : 80;
                   1321:        }
                   1322: 
                   1323:        if (srv->srvconf.event_handler->used == 0) {
                   1324:                /* choose a good default
                   1325:                 *
                   1326:                 * the event_handler list is sorted by 'goodness'
                   1327:                 * taking the first available should be the best solution
                   1328:                 */
                   1329:                srv->event_handler = event_handlers[0].et;
                   1330: 
                   1331:                if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
                   1332:                        log_error_write(srv, __FILE__, __LINE__, "s",
                   1333:                                        "sorry, there is no event handler for this system");
                   1334: 
                   1335:                        return -1;
                   1336:                }
                   1337:        } else {
                   1338:                /*
                   1339:                 * User override
                   1340:                 */
                   1341: 
                   1342:                for (i = 0; event_handlers[i].name; i++) {
                   1343:                        if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
                   1344:                                srv->event_handler = event_handlers[i].et;
                   1345:                                break;
                   1346:                        }
                   1347:                }
                   1348: 
                   1349:                if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
                   1350:                        log_error_write(srv, __FILE__, __LINE__, "sb",
                   1351:                                        "the selected event-handler in unknown or not supported:",
                   1352:                                        srv->srvconf.event_handler );
                   1353: 
                   1354:                        return -1;
                   1355:                }
                   1356:        }
                   1357: 
                   1358:        if (s->ssl_enabled) {
                   1359:                if (buffer_is_empty(s->ssl_pemfile)) {
                   1360:                        /* PEM file is require */
                   1361: 
                   1362:                        log_error_write(srv, __FILE__, __LINE__, "s",
                   1363:                                        "ssl.pemfile has to be set");
                   1364:                        return -1;
                   1365:                }
                   1366: 
                   1367: #ifndef USE_OPENSSL
                   1368:                log_error_write(srv, __FILE__, __LINE__, "s",
                   1369:                                "ssl support is missing, recompile with --with-openssl");
                   1370: 
                   1371:                return -1;
                   1372: #endif
                   1373:        }
                   1374: 
                   1375:        return 0;
                   1376: }

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