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