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