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