• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/lighttpd-1.4.39/src/
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