10 #include "configparser.h"
11 #include "configfile.h"
12 #include "stat_cache.h"
13 #include "sys-crypto.h"
31 #if defined(HAVE_MYSQL) || (defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER))
32 static void config_warn_authn_module (server
*srv
, const char *module
, size_t len
) {
33 for (size_t i
= 0; i
< srv
->config_context
->used
; ++i
) {
34 const data_config
*config
= (data_config
const*)srv
->config_context
->data
[i
];
35 const data_unset
*du
= array_get_element(config
->value
, "auth.backend");
36 if (NULL
!= du
&& du
->type
== TYPE_STRING
) {
37 data_string
*ds
= (data_string
*)du
;
38 if (buffer_is_equal_string(ds
->value
, module
, len
)) {
39 buffer_copy_string_len(srv
->tmp_buf
, CONST_STR_LEN("mod_authn_"));
40 buffer_append_string_len(srv
->tmp_buf
, module
, len
);
41 array_insert_value(srv
->srvconf
.modules
, CONST_BUF_LEN(srv
->tmp_buf
));
42 log_error_write(srv
, __FILE__
, __LINE__
, "SSSsSSS", "Warning: please add \"mod_authn_", module
, "\" to server.modules list in lighttpd.conf. A future release of lighttpd 1.4.x will not automatically load mod_authn_", module
, "and lighttpd will fail to start up since your lighttpd.conf uses auth.backend = \"", module
, "\".");
50 #ifdef USE_OPENSSL_CRYPTO
51 static void config_warn_openssl_module (server
*srv
) {
52 for (size_t i
= 0; i
< srv
->config_context
->used
; ++i
) {
53 const data_config
*config
= (data_config
const*)srv
->config_context
->data
[i
];
54 for (size_t j
= 0; j
< config
->value
->used
; ++j
) {
55 data_unset
*du
= config
->value
->data
[j
];
56 if (0 == strncmp(du
->key
->ptr
, "ssl.", sizeof("ssl.")-1)) {
57 /* mod_openssl should be loaded after mod_extforward */
58 array_insert_value(srv
->srvconf
.modules
, CONST_STR_LEN("mod_openssl"));
59 log_error_write(srv
, __FILE__
, __LINE__
, "S", "Warning: please add \"mod_openssl\" to server.modules list in lighttpd.conf. A future release of lighttpd 1.4.x *will not* automatically load mod_openssl and lighttpd *will not* use SSL/TLS where your lighttpd.conf contains ssl.* directives");
67 static int config_http_parseopts (server
*srv
, array
*a
) {
68 unsigned short int opts
= srv
->srvconf
.http_url_normalize
;
69 unsigned short int decode_2f
= 1;
71 if (!array_is_kvstring(a
)) {
72 log_error_write(srv
, __FILE__
, __LINE__
, "s",
73 "unexpected value for server.http-parseopts; "
74 "expected list of \"key\" => \"[enable|disable]\"");
77 for (size_t i
= 0; i
< a
->used
; ++i
) {
78 const data_string
* const ds
= (data_string
*)a
->data
[i
];
79 unsigned short int opt
;
81 if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("enable")))
83 else if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("disable")))
86 log_error_write(srv
, __FILE__
, __LINE__
, "sbsbs",
87 "unrecognized value for server.http-parseopts:",
88 ds
->key
, "=>", ds
->value
,
89 "(expect \"[enable|disable]\")");
92 if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("url-normalize")))
93 opt
= HTTP_PARSEOPT_URL_NORMALIZE
;
94 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("url-normalize-unreserved")))
95 opt
= HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED
;
96 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("url-normalize-required")))
97 opt
= HTTP_PARSEOPT_URL_NORMALIZE_REQUIRED
;
98 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("url-ctrls-reject")))
99 opt
= HTTP_PARSEOPT_URL_NORMALIZE_CTRLS_REJECT
;
100 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("url-path-backslash-trans")))
101 opt
= HTTP_PARSEOPT_URL_NORMALIZE_PATH_BACKSLASH_TRANS
;
102 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("url-path-2f-decode")))
103 opt
= HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE
;
104 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("url-path-2f-reject")))
105 opt
= HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT
;
106 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("url-path-dotseg-remove")))
107 opt
= HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE
;
108 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("url-path-dotseg-reject")))
109 opt
= HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT
;
110 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("url-query-20-plus")))
111 opt
= HTTP_PARSEOPT_URL_NORMALIZE_QUERY_20_PLUS
;
112 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("header-strict"))) {
113 srv
->srvconf
.http_header_strict
= val
;
116 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("host-strict"))) {
117 srv
->srvconf
.http_host_strict
= val
;
120 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("host-normalize"))) {
121 srv
->srvconf
.http_host_normalize
= val
;
124 else if (buffer_is_equal_string(ds
->key
, CONST_STR_LEN("method-get-body"))) {
125 srv
->srvconf
.http_method_get_body
= val
;
129 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
130 "unrecognized key for server.http-parseopts:",
139 if (opt
== HTTP_PARSEOPT_URL_NORMALIZE
) {
143 if (opt
== HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE
) {
149 opts
|= HTTP_PARSEOPT_URL_NORMALIZE
;
150 if ((opts
& (HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE
151 |HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT
))
152 == (HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE
153 |HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT
)) {
154 log_error_write(srv
, __FILE__
, __LINE__
, "s",
155 "conflicting options in server.http-parseopts:"
156 "url-path-2f-decode, url-path-2f-reject");
159 if ((opts
& (HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE
160 |HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT
))
161 == (HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REMOVE
162 |HTTP_PARSEOPT_URL_NORMALIZE_PATH_DOTSEG_REJECT
)) {
163 log_error_write(srv
, __FILE__
, __LINE__
, "s",
164 "conflicting options in server.http-parseopts:"
165 "url-path-dotseg-remove, url-path-dotseg-reject");
168 if (!(opts
& (HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED
169 |HTTP_PARSEOPT_URL_NORMALIZE_REQUIRED
))) {
170 opts
|= HTTP_PARSEOPT_URL_NORMALIZE_UNRESERVED
;
172 && !(opts
& HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_REJECT
))
173 opts
|= HTTP_PARSEOPT_URL_NORMALIZE_PATH_2F_DECODE
;
176 srv
->srvconf
.http_url_normalize
= opts
;
180 static int config_insert(server
*srv
) {
183 buffer
*stat_cache_string
;
184 array
*http_parseopts
;
185 unsigned int chunk_sz
= 0;
187 config_values_t cv
[] = {
188 { "server.bind", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 0 */
189 { "server.errorlog", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 1 */
190 { "server.errorfile-prefix", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 2 */
191 { "server.chroot", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 3 */
192 { "server.username", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 4 */
193 { "server.groupname", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 5 */
194 { "server.port", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_SERVER
}, /* 6 */
195 { "server.tag", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 7 */
196 { "server.use-ipv6", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 8 */
197 { "server.modules", NULL
, T_CONFIG_ARRAY
, T_CONFIG_SCOPE_SERVER
}, /* 9 */
199 { "server.event-handler", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 10 */
200 { "server.pid-file", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 11 */
201 { "server.max-request-size", NULL
, T_CONFIG_INT
, T_CONFIG_SCOPE_CONNECTION
}, /* 12 */
202 { "server.max-worker", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_SERVER
}, /* 13 */
203 { "server.document-root", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 14 */
204 { "server.force-lowercase-filenames", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 15 */
205 { "debug.log-condition-handling", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 16 */
206 { "server.max-keep-alive-requests", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 17 */
207 { "server.name", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 18 */
208 { "server.max-keep-alive-idle", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 19 */
210 { "server.max-read-idle", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 20 */
211 { "server.max-write-idle", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 21 */
212 { "server.error-handler", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 22 */
213 { "server.max-fds", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_SERVER
}, /* 23 */
215 { "server.follow-symlink", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 24 */
217 { "server.follow-symlink",
218 "Your system lacks lstat(). We can not differ symlinks from files."
219 "Please remove server.follow-symlinks from your config.",
220 T_CONFIG_UNSUPPORTED
, T_CONFIG_SCOPE_UNSET
},
222 { "server.kbytes-per-second", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 25 */
223 { "connection.kbytes-per-second", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 26 */
224 { "mimetype.use-xattr", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 27 */
225 { "mimetype.assign", NULL
, T_CONFIG_ARRAY
, T_CONFIG_SCOPE_CONNECTION
}, /* 28 */
226 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 29 */
228 { "ssl.engine", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 30 */
229 { "debug.log-file-not-found", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 31 */
230 { "debug.log-request-handling", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 32 */
231 { "debug.log-response-header", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 33 */
232 { "debug.log-request-header", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 34 */
233 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 35 */
234 { "server.protocol-http11", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 36 */
235 { "debug.log-request-header-on-error", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_SERVER
}, /* 37 */
236 { "debug.log-state-handling", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_SERVER
}, /* 38 */
237 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 39 */
239 { "server.errorlog-use-syslog", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_SERVER
}, /* 40 */
240 { "server.range-requests", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 41 */
241 { "server.stat-cache-engine", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 42 */
242 { "server.max-connections", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_SERVER
}, /* 43 */
243 { "server.network-backend", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 44 */
244 { "server.upload-dirs", NULL
, T_CONFIG_ARRAY
, T_CONFIG_SCOPE_SERVER
}, /* 45 */
245 { "server.core-files", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_SERVER
}, /* 46 */
246 { "server.compat-module-load", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_SERVER
}, /* 47 */
247 { "server.chunkqueue-chunk-sz", NULL
, T_CONFIG_INT
, T_CONFIG_SCOPE_SERVER
}, /* 48 */
248 { "etag.use-inode", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 49 */
250 { "etag.use-mtime", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 50 */
251 { "etag.use-size", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 51 */
252 { "server.reject-expect-100-with-417", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_SERVER
}, /* 52 */
253 { "debug.log-timeouts", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 53 */
254 { "server.defer-accept", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 54 */
255 { "server.breakagelog", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 55 */
256 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 56 */
257 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 57 */
258 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 58 */
259 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 59 */
261 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 60 */
262 { "server.set-v6only", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 61 */
263 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 62 */
264 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 63 */
265 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 64 */
266 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 65 */
267 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 66 */
268 { "unused-slot-moved-to-mod-openssl", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 67 */
269 { "server.upload-temp-file-size", NULL
, T_CONFIG_INT
, T_CONFIG_SCOPE_SERVER
}, /* 68 */
270 { "mimetype.xattr-name", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 69 */
271 { "server.listen-backlog", NULL
, T_CONFIG_INT
, T_CONFIG_SCOPE_CONNECTION
}, /* 70 */
272 { "server.error-handler-404", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 71 */
273 { "server.http-parseopt-header-strict",NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_SERVER
}, /* 72 */
274 { "server.http-parseopt-host-strict", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_SERVER
}, /* 73 */
275 { "server.http-parseopt-host-normalize",NULL
,T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_SERVER
}, /* 74 */
276 { "server.bsd-accept-filter", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 75 */
277 { "server.stream-request-body", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 76 */
278 { "server.stream-response-body", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 77 */
279 { "server.max-request-field-size", NULL
, T_CONFIG_INT
, T_CONFIG_SCOPE_SERVER
}, /* 78 */
280 { "server.error-intercept", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 79 */
281 { "server.syslog-facility", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_SERVER
}, /* 80 */
282 { "server.socket-perms", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 81 */
283 { "server.http-parseopts", NULL
, T_CONFIG_ARRAY
, T_CONFIG_SCOPE_SERVER
}, /* 82 */
284 { "server.systemd-socket-activation", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_SERVER
}, /* 83 */
286 { NULL
, NULL
, T_CONFIG_UNSET
, T_CONFIG_SCOPE_UNSET
}
289 /* all T_CONFIG_SCOPE_SERVER options */
290 cv
[0].destination
= srv
->srvconf
.bindhost
;
291 cv
[1].destination
= srv
->srvconf
.errorlog_file
;
292 cv
[3].destination
= srv
->srvconf
.changeroot
;
293 cv
[4].destination
= srv
->srvconf
.username
;
294 cv
[5].destination
= srv
->srvconf
.groupname
;
295 cv
[6].destination
= &(srv
->srvconf
.port
);
296 cv
[9].destination
= srv
->srvconf
.modules
;
298 cv
[10].destination
= srv
->srvconf
.event_handler
;
299 cv
[11].destination
= srv
->srvconf
.pid_file
;
300 cv
[13].destination
= &(srv
->srvconf
.max_worker
);
302 cv
[23].destination
= &(srv
->srvconf
.max_fds
);
304 cv
[37].destination
= &(srv
->srvconf
.log_request_header_on_error
);
305 cv
[38].destination
= &(srv
->srvconf
.log_state_handling
);
307 cv
[40].destination
= &(srv
->srvconf
.errorlog_use_syslog
);
308 stat_cache_string
= buffer_init();
309 cv
[42].destination
= stat_cache_string
;
310 cv
[43].destination
= &(srv
->srvconf
.max_conns
);
311 cv
[44].destination
= srv
->srvconf
.network_backend
;
312 cv
[45].destination
= srv
->srvconf
.upload_tempdirs
;
313 cv
[46].destination
= &(srv
->srvconf
.enable_cores
);
314 cv
[47].destination
= &(srv
->srvconf
.compat_module_load
);
315 cv
[48].destination
= &chunk_sz
;
317 cv
[52].destination
= &(srv
->srvconf
.reject_expect_100_with_417
);
318 cv
[55].destination
= srv
->srvconf
.breakagelog_file
;
320 cv
[68].destination
= &(srv
->srvconf
.upload_temp_file_size
);
321 cv
[69].destination
= srv
->srvconf
.xattr_name
;
322 cv
[72].destination
= &(srv
->srvconf
.http_header_strict
);
323 cv
[73].destination
= &(srv
->srvconf
.http_host_strict
);
324 cv
[74].destination
= &(srv
->srvconf
.http_host_normalize
);
325 cv
[78].destination
= &(srv
->srvconf
.max_request_field_size
);
326 cv
[80].destination
= srv
->srvconf
.syslog_facility
;
327 http_parseopts
= array_init();
328 cv
[82].destination
= http_parseopts
;
329 cv
[83].destination
= &(srv
->srvconf
.systemd_socket_activation
);
331 srv
->config_storage
= calloc(1, srv
->config_context
->used
* sizeof(specific_config
*));
333 force_assert(srv
->config_storage
);
334 force_assert(srv
->config_context
->used
); /* static analysis hint for ccc
337 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
338 data_config
* const config
= (data_config
*)srv
->config_context
->data
[i
];
341 s
= calloc(1, sizeof(specific_config
));
343 s
->document_root
= buffer_init();
344 s
->mimetypes
= array_init();
345 s
->server_name
= buffer_init();
346 s
->error_handler
= buffer_init();
347 s
->error_handler_404
= buffer_init();
348 s
->server_tag
= buffer_init();
349 s
->errorfile_prefix
= buffer_init();
350 #if defined(__FreeBSD__) || defined(__NetBSD__) \
351 || defined(__OpenBSD__) || defined(__DragonFly__)
352 s
->bsd_accept_filter
= (i
== 0)
354 : buffer_init_buffer(srv
->config_storage
[0]->bsd_accept_filter
);
356 s
->socket_perms
= (i
== 0 || buffer_string_is_empty(srv
->config_storage
[0]->socket_perms
))
358 : buffer_init_buffer(srv
->config_storage
[0]->socket_perms
);
359 s
->max_keep_alive_requests
= 100;
360 s
->max_keep_alive_idle
= 5;
361 s
->max_read_idle
= 60;
362 s
->max_write_idle
= 360;
363 s
->max_request_size
= 0;
366 s
->use_ipv6
= (i
== 0) ? 0 : srv
->config_storage
[0]->use_ipv6
;
367 s
->set_v6only
= (i
== 0) ? 1 : srv
->config_storage
[0]->set_v6only
;
368 s
->defer_accept
= (i
== 0) ? 0 : srv
->config_storage
[0]->defer_accept
;
369 s
->follow_symlink
= 1;
370 s
->kbytes_per_second
= 0;
372 s
->etag_use_inode
= 1;
373 s
->etag_use_mtime
= 1;
374 s
->etag_use_size
= 1;
375 s
->range_requests
= 1;
376 s
->force_lowercase_filenames
= (i
== 0) ? 2 : 0; /* we wan't to detect later if user changed this for global section */
377 s
->global_kbytes_per_second
= 0;
378 s
->global_bytes_per_second_cnt
= 0;
379 s
->global_bytes_per_second_cnt_ptr
= &s
->global_bytes_per_second_cnt
;
380 s
->listen_backlog
= (0 == i
? 1024 : srv
->config_storage
[0]->listen_backlog
);
381 s
->stream_request_body
= 0;
382 s
->stream_response_body
= 0;
383 s
->error_intercept
= 0;
385 /* all T_CONFIG_SCOPE_CONNECTION options */
386 cv
[2].destination
= s
->errorfile_prefix
;
387 cv
[7].destination
= s
->server_tag
;
388 cv
[8].destination
= &(s
->use_ipv6
);
390 cv
[12].destination
= &(s
->max_request_size
);
391 cv
[14].destination
= s
->document_root
;
392 cv
[15].destination
= &(s
->force_lowercase_filenames
);
393 cv
[16].destination
= &(s
->log_condition_handling
);
394 cv
[17].destination
= &(s
->max_keep_alive_requests
);
395 cv
[18].destination
= s
->server_name
;
396 cv
[19].destination
= &(s
->max_keep_alive_idle
);
398 cv
[20].destination
= &(s
->max_read_idle
);
399 cv
[21].destination
= &(s
->max_write_idle
);
400 cv
[22].destination
= s
->error_handler
;
401 cv
[24].destination
= &(s
->follow_symlink
);
402 cv
[25].destination
= &(s
->global_kbytes_per_second
);
403 cv
[26].destination
= &(s
->kbytes_per_second
);
404 cv
[27].destination
= &(s
->use_xattr
);
405 cv
[28].destination
= s
->mimetypes
;
406 /*cv[29].destination = s->unused;*/
408 cv
[30].destination
= &(s
->ssl_enabled
);
409 cv
[31].destination
= &(s
->log_file_not_found
);
410 cv
[32].destination
= &(s
->log_request_handling
);
411 cv
[33].destination
= &(s
->log_response_header
);
412 cv
[34].destination
= &(s
->log_request_header
);
413 /*cv[35].destination = &(s->unused);*/
414 cv
[36].destination
= &(s
->allow_http11
);
415 /*cv[39].destination = s->unused;*/
417 cv
[41].destination
= &(s
->range_requests
);
418 /*cv[47].destination = s->unused;*/
419 /*cv[48].destination = &(s->unused);*/
420 cv
[49].destination
= &(s
->etag_use_inode
);
422 cv
[50].destination
= &(s
->etag_use_mtime
);
423 cv
[51].destination
= &(s
->etag_use_size
);
424 cv
[53].destination
= &(s
->log_timeouts
);
425 cv
[54].destination
= &(s
->defer_accept
);
426 /*cv[56].destination = &(s->unused);*/
427 /*cv[57].destination = &(s->unused);*/
428 /*cv[58].destination = &(s->unused);*/
429 /*cv[59].destination = s->unused;*/
431 /*cv[60].destination = &(s->unused);*/
432 cv
[61].destination
= &(s
->set_v6only
);
433 /*cv[62].destination = &(s->unused);*/
434 /*cv[63].destination = s->unused;*/
435 /*cv[64].destination = s->unused;*/
436 /*cv[65].destination = &(s->unused);*/
437 /*cv[66].destination = &(s->unused);*/
438 /*cv[67].destination = &(s->unused);*/
439 cv
[70].destination
= &(s
->listen_backlog
);
440 cv
[71].destination
= s
->error_handler_404
;
441 #if defined(__FreeBSD__) || defined(__NetBSD__) \
442 || defined(__OpenBSD__) || defined(__DragonFly__)
443 cv
[75].destination
= s
->bsd_accept_filter
;
445 cv
[76].destination
= &(s
->stream_request_body
);
446 cv
[77].destination
= &(s
->stream_response_body
);
447 cv
[79].destination
= &(s
->error_intercept
);
448 cv
[81].destination
= s
->socket_perms
;
450 srv
->config_storage
[i
] = s
;
452 if (0 != (ret
= config_insert_values_global(srv
, config
->value
, cv
, i
== 0 ? T_CONFIG_SCOPE_SERVER
: T_CONFIG_SCOPE_CONNECTION
))) {
456 if (s
->stream_request_body
& FDEVENT_STREAM_REQUEST_BUFMIN
) {
457 s
->stream_request_body
|= FDEVENT_STREAM_REQUEST
;
459 if (s
->stream_response_body
& FDEVENT_STREAM_RESPONSE_BUFMIN
) {
460 s
->stream_response_body
|= FDEVENT_STREAM_RESPONSE
;
463 if (!array_is_kvstring(s
->mimetypes
)) {
464 log_error_write(srv
, __FILE__
, __LINE__
, "s",
465 "unexpected value for mimetype.assign; expected list of \"ext\" => \"mimetype\"");
468 if (!buffer_string_is_empty(s
->server_tag
)) {
469 for (char *t
= strchr(s
->server_tag
->ptr
,'\n'); NULL
!= t
; t
= strchr(t
+2,'\n')) {
470 /* not expecting admin to define multi-line server.tag,
471 * but ensure server_tag has proper header continuation,
473 off_t off
= t
- s
->server_tag
->ptr
;
475 if (t
[1] == ' ' || t
[1] == '\t') continue;
476 len
= buffer_string_length(s
->server_tag
);
477 buffer_string_prepare_append(s
->server_tag
, 1);
478 t
= s
->server_tag
->ptr
+off
;
479 memmove(t
+2, t
+1, len
- off
- 1);
481 buffer_commit(s
->server_tag
, 1);
486 if (!config_http_parseopts(srv
, http_parseopts
)) {
492 if (srv
->srvconf
.http_url_normalize
493 && COMP_HTTP_QUERY_STRING
== config
->comp
) {
494 switch(config
->cond
) {
497 /* (can use this routine as long as it does not perform
498 * any regex-specific normalization of first arg) */
499 pcre_keyvalue_burl_normalize_key(config
->string
, srv
->tmp_buf
);
501 case CONFIG_COND_NOMATCH
:
502 case CONFIG_COND_MATCH
:
503 pcre_keyvalue_burl_normalize_key(config
->string
, srv
->tmp_buf
);
504 if (!data_config_pcre_compile(config
)) {
511 if (HANDLER_ERROR
== ret
) break;
514 #ifndef USE_OPENSSL_CRYPTO
515 if (s
->ssl_enabled
) {
516 log_error_write(srv
, __FILE__
, __LINE__
, "s",
517 "ssl support is missing, recompile with e.g. --with-openssl");
523 array_free(http_parseopts
);
526 specific_config
*s
= srv
->config_storage
[0];
527 s
->http_parseopts
= /*(global, but stored in con->conf.http_parseopts)*/
528 (srv
->srvconf
.http_header_strict
?(HTTP_PARSEOPT_HEADER_STRICT
) :0)
529 |(srv
->srvconf
.http_host_strict
?(HTTP_PARSEOPT_HOST_STRICT
530 |HTTP_PARSEOPT_HOST_NORMALIZE
):0)
531 |(srv
->srvconf
.http_host_normalize
?(HTTP_PARSEOPT_HOST_NORMALIZE
):0)
532 |(srv
->srvconf
.http_method_get_body
?(HTTP_PARSEOPT_METHOD_GET_BODY
):0);
533 s
->http_parseopts
|= srv
->srvconf
.http_url_normalize
;
535 if (s
->log_request_handling
|| s
->log_request_header
)
536 srv
->srvconf
.log_request_header_on_error
= 1;
540 chunkqueue_set_chunk_size(chunk_sz
);
543 if (0 != stat_cache_choose_engine(srv
, stat_cache_string
)) {
546 buffer_free(stat_cache_string
);
548 if (!array_is_vlist(srv
->srvconf
.upload_tempdirs
)) {
549 log_error_write(srv
, __FILE__
, __LINE__
, "s",
550 "unexpected value for server.upload-dirs; expected list of \"path\" strings");
554 if (!array_is_vlist(srv
->srvconf
.modules
)) {
555 log_error_write(srv
, __FILE__
, __LINE__
, "s",
556 "unexpected value for server.modules; expected list of \"mod_xxxxxx\" strings");
558 } else if (srv
->srvconf
.compat_module_load
) {
560 int prepend_mod_indexfile
= 1;
561 int append_mod_dirlisting
= 1;
562 int append_mod_staticfile
= 1;
563 int append_mod_authn_file
= 1;
564 int append_mod_authn_ldap
= 1;
565 int append_mod_authn_mysql
= 1;
566 int append_mod_openssl
= 1;
567 int contains_mod_auth
= 0;
569 /* prepend default modules */
570 for (i
= 0; i
< srv
->srvconf
.modules
->used
; i
++) {
571 ds
= (data_string
*)srv
->srvconf
.modules
->data
[i
];
573 if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("mod_indexfile"))) {
574 prepend_mod_indexfile
= 0;
577 if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("mod_staticfile"))) {
578 append_mod_staticfile
= 0;
581 if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("mod_dirlisting"))) {
582 append_mod_dirlisting
= 0;
585 if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("mod_openssl"))) {
586 append_mod_openssl
= 0;
589 if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("mod_authn_file"))) {
590 append_mod_authn_file
= 0;
593 if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("mod_authn_ldap"))) {
594 append_mod_authn_ldap
= 0;
597 if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("mod_authn_mysql"))) {
598 append_mod_authn_mysql
= 0;
601 if (buffer_is_equal_string(ds
->value
, CONST_STR_LEN("mod_auth"))) {
602 contains_mod_auth
= 1;
605 if (0 == prepend_mod_indexfile
&&
606 0 == append_mod_dirlisting
&&
607 0 == append_mod_staticfile
&&
608 0 == append_mod_openssl
&&
609 0 == append_mod_authn_file
&&
610 0 == append_mod_authn_ldap
&&
611 0 == append_mod_authn_mysql
&&
612 1 == contains_mod_auth
) {
617 if (prepend_mod_indexfile
) {
618 /* mod_indexfile has to be loaded before mod_fastcgi and friends */
619 array
*modules
= array_init();
620 array_insert_value(modules
, CONST_STR_LEN("mod_indexfile"));
622 for (i
= 0; i
< srv
->srvconf
.modules
->used
; i
++) {
623 ds
= (data_string
*)srv
->srvconf
.modules
->data
[i
];
624 array_insert_value(modules
, CONST_BUF_LEN(ds
->value
));
627 array_free(srv
->srvconf
.modules
);
628 srv
->srvconf
.modules
= modules
;
631 /* append default modules */
632 if (append_mod_dirlisting
) {
633 array_insert_value(srv
->srvconf
.modules
, CONST_STR_LEN("mod_dirlisting"));
636 if (append_mod_staticfile
) {
637 array_insert_value(srv
->srvconf
.modules
, CONST_STR_LEN("mod_staticfile"));
640 if (append_mod_openssl
) {
641 #ifdef USE_OPENSSL_CRYPTO
642 config_warn_openssl_module(srv
);
646 /* mod_auth.c,http_auth.c auth backends were split into separate modules
647 * Automatically load auth backend modules for compatibility with
648 * existing lighttpd 1.4.x configs */
649 if (contains_mod_auth
) {
650 if (append_mod_authn_file
) {
651 array_insert_value(srv
->srvconf
.modules
, CONST_STR_LEN("mod_authn_file"));
653 if (append_mod_authn_ldap
) {
654 #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
655 config_warn_authn_module(srv
, CONST_STR_LEN("ldap"));
658 if (append_mod_authn_mysql
) {
659 #if defined(HAVE_MYSQL)
660 config_warn_authn_module(srv
, CONST_STR_LEN("mysql"));
671 #define PATCH(x) con->conf.x = s->x
672 int config_setup_connection(server
*srv
, connection
*con
) {
673 specific_config
*s
= srv
->config_storage
[0];
675 PATCH(http_parseopts
);
679 PATCH(document_root
);
680 PATCH(high_precision_timestamps
);
681 PATCH(max_keep_alive_requests
);
682 PATCH(max_keep_alive_idle
);
683 PATCH(max_read_idle
);
684 PATCH(max_write_idle
);
685 PATCH(max_request_size
);
687 PATCH(error_handler
);
688 PATCH(error_handler_404
);
689 PATCH(error_intercept
);
690 PATCH(errorfile_prefix
);
691 PATCH(follow_symlink
);
693 PATCH(kbytes_per_second
);
694 PATCH(global_kbytes_per_second
);
695 PATCH(global_bytes_per_second_cnt
);
697 con
->conf
.global_bytes_per_second_cnt_ptr
= &s
->global_bytes_per_second_cnt
;
698 buffer_copy_buffer(con
->server_name
, s
->server_name
);
700 PATCH(log_request_header
);
701 PATCH(log_response_header
);
702 PATCH(log_request_handling
);
703 PATCH(log_condition_handling
);
704 PATCH(log_file_not_found
);
707 PATCH(range_requests
);
708 PATCH(force_lowercase_filenames
);
709 /*PATCH(listen_backlog);*//*(not necessary; used only at startup)*/
710 PATCH(stream_request_body
);
711 PATCH(stream_response_body
);
714 PATCH(etag_use_inode
);
715 PATCH(etag_use_mtime
);
716 PATCH(etag_use_size
);
721 int config_patch_connection(server
*srv
, connection
*con
) {
724 /* skip the first, the global context */
725 for (i
= 1; i
< srv
->config_context
->used
; i
++) {
726 data_config
*dc
= (data_config
*)srv
->config_context
->data
[i
];
727 specific_config
*s
= srv
->config_storage
[i
];
729 /* condition didn't match */
730 if (!config_check_cond(srv
, con
, dc
)) continue;
733 for (j
= 0; j
< dc
->value
->used
; j
++) {
734 data_unset
*du
= dc
->value
->data
[j
];
736 if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.document-root"))) {
737 PATCH(document_root
);
738 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.range-requests"))) {
739 PATCH(range_requests
);
740 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.error-handler"))) {
741 PATCH(error_handler
);
742 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.error-handler-404"))) {
743 PATCH(error_handler_404
);
744 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.error-intercept"))) {
745 PATCH(error_intercept
);
746 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.errorfile-prefix"))) {
747 PATCH(errorfile_prefix
);
748 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("mimetype.assign"))) {
750 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.max-keep-alive-requests"))) {
751 PATCH(max_keep_alive_requests
);
752 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.max-keep-alive-idle"))) {
753 PATCH(max_keep_alive_idle
);
754 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.max-write-idle"))) {
755 PATCH(max_write_idle
);
756 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.max-read-idle"))) {
757 PATCH(max_read_idle
);
758 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.max-request-size"))) {
759 PATCH(max_request_size
);
760 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("mimetype.use-xattr"))) {
762 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("etag.use-inode"))) {
763 PATCH(etag_use_inode
);
764 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("etag.use-mtime"))) {
765 PATCH(etag_use_mtime
);
766 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("etag.use-size"))) {
767 PATCH(etag_use_size
);
768 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.follow-symlink"))) {
769 PATCH(follow_symlink
);
770 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.name"))) {
771 buffer_copy_buffer(con
->server_name
, s
->server_name
);
772 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.tag"))) {
774 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.stream-request-body"))) {
775 PATCH(stream_request_body
);
776 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.stream-response-body"))) {
777 PATCH(stream_response_body
);
778 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("connection.kbytes-per-second"))) {
779 PATCH(kbytes_per_second
);
780 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("debug.log-request-handling"))) {
781 PATCH(log_request_handling
);
782 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("debug.log-request-header"))) {
783 PATCH(log_request_header
);
784 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("debug.log-response-header"))) {
785 PATCH(log_response_header
);
786 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("debug.log-condition-handling"))) {
787 PATCH(log_condition_handling
);
788 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("debug.log-file-not-found"))) {
789 PATCH(log_file_not_found
);
790 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("debug.log-timeouts"))) {
792 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.protocol-http11"))) {
794 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.force-lowercase-filenames"))) {
795 PATCH(force_lowercase_filenames
);
796 #if 0 /*(not necessary; used only at startup)*/
797 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.listen-backlog"))) {
798 PATCH(listen_backlog
);
800 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.kbytes-per-second"))) {
801 PATCH(global_kbytes_per_second
);
802 PATCH(global_bytes_per_second_cnt
);
803 con
->conf
.global_bytes_per_second_cnt_ptr
= &s
->global_bytes_per_second_cnt
;
804 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("server.socket-perms"))) {
810 con
->etag_flags
= (con
->conf
.etag_use_mtime
? ETAG_USE_MTIME
: 0) |
811 (con
->conf
.etag_use_inode
? ETAG_USE_INODE
: 0) |
812 (con
->conf
.etag_use_size
? ETAG_USE_SIZE
: 0);
822 const buffer
*source
;
837 static int tokenizer_open(server
*srv
, tokenizer_t
*t
, buffer
*basedir
, const char *fn
) {
838 if (buffer_string_is_empty(basedir
) ||
839 (fn
[0] == '/' || fn
[0] == '\\') ||
840 (fn
[0] == '.' && (fn
[1] == '/' || fn
[1] == '\\'))) {
841 t
->file
= buffer_init_string(fn
);
843 t
->file
= buffer_init_buffer(basedir
);
844 buffer_append_string(t
->file
, fn
);
847 if (0 != stream_open(&(t
->s
), t
->file
)) {
848 log_error_write(srv
, __FILE__
, __LINE__
, "sbss",
849 "opening configfile ", t
->file
, "failed:", strerror(errno
));
850 buffer_free(t
->file
);
854 t
->input
= t
->s
.start
;
866 static int tokenizer_close(server
*srv
, tokenizer_t
*t
) {
869 buffer_free(t
->file
);
870 return stream_close(&(t
->s
));
873 static int config_skip_newline(tokenizer_t
*t
) {
875 force_assert(t
->input
[t
->offset
] == '\r' || t
->input
[t
->offset
] == '\n');
876 if (t
->input
[t
->offset
] == '\r' && t
->input
[t
->offset
+ 1] == '\n') {
884 static int config_skip_comment(tokenizer_t
*t
) {
886 force_assert(t
->input
[t
->offset
] == '#');
887 for (i
= 1; t
->input
[t
->offset
+ i
] &&
888 (t
->input
[t
->offset
+ i
] != '\n' && t
->input
[t
->offset
+ i
] != '\r');
894 static int config_tokenizer(server
*srv
, tokenizer_t
*t
, int *token_id
, buffer
*token
) {
898 if (t
->simulate_eol
) {
902 buffer_copy_string_len(token
, CONST_STR_LEN("(EOL)"));
905 while (tid
== 0 && t
->offset
< t
->size
&& t
->input
[t
->offset
]) {
906 char c
= t
->input
[t
->offset
];
907 const char *start
= NULL
;
912 if (t
->input
[t
->offset
+ 1] == '>') {
915 buffer_copy_string_len(token
, CONST_STR_LEN("=>"));
917 tid
= TK_ARRAY_ASSIGN
;
919 log_error_write(srv
, __FILE__
, __LINE__
, "sbsdsds",
920 "source:", t
->source
,
921 "line:", t
->line
, "pos:", t
->line_pos
,
922 "use => for assignments in arrays");
925 } else if (t
->in_cond
) {
926 if (t
->input
[t
->offset
+ 1] == '=') {
929 buffer_copy_string_len(token
, CONST_STR_LEN("=="));
932 } else if (t
->input
[t
->offset
+ 1] == '~') {
935 buffer_copy_string_len(token
, CONST_STR_LEN("=~"));
939 log_error_write(srv
, __FILE__
, __LINE__
, "sbsdsds",
940 "source:", t
->source
,
941 "line:", t
->line
, "pos:", t
->line_pos
,
942 "only =~ and == are allowed in the condition");
947 } else if (t
->in_key
) {
950 buffer_copy_string_len(token
, t
->input
+ t
->offset
, 1);
955 log_error_write(srv
, __FILE__
, __LINE__
, "sbsdsds",
956 "source:", t
->source
,
957 "line:", t
->line
, "pos:", t
->line_pos
,
958 "unexpected equal-sign: =");
965 if (t
->input
[t
->offset
+ 1] == '=') {
968 buffer_copy_string_len(token
, CONST_STR_LEN("!="));
971 } else if (t
->input
[t
->offset
+ 1] == '~') {
974 buffer_copy_string_len(token
, CONST_STR_LEN("!~"));
978 log_error_write(srv
, __FILE__
, __LINE__
, "sbsdsds",
979 "source:", t
->source
,
980 "line:", t
->line
, "pos:", t
->line_pos
,
981 "only !~ and != are allowed in the condition");
987 log_error_write(srv
, __FILE__
, __LINE__
, "sbsdsds",
988 "source:", t
->source
,
989 "line:", t
->line
, "pos:", t
->line_pos
,
990 "unexpected exclamation-marks: !");
1002 if (t
->in_brace
== 0) {
1004 while (!done
&& t
->offset
< t
->size
) {
1005 switch (t
->input
[t
->offset
]) {
1008 config_skip_newline(t
);
1014 t
->line_pos
+= config_skip_comment(t
);
1029 buffer_copy_string_len(token
, CONST_STR_LEN("(EOL)"));
1031 config_skip_newline(t
);
1037 if (t
->in_brace
> 0) {
1040 buffer_copy_string_len(token
, CONST_STR_LEN("(COMMA)"));
1047 /* search for the terminating " */
1048 start
= t
->input
+ t
->offset
+ 1;
1049 buffer_copy_string_len(token
, CONST_STR_LEN(""));
1051 for (i
= 1; t
->input
[t
->offset
+ i
]; i
++) {
1052 if (t
->input
[t
->offset
+ i
] == '\\' &&
1053 t
->input
[t
->offset
+ i
+ 1] == '"') {
1055 buffer_append_string_len(token
, start
, t
->input
+ t
->offset
+ i
- start
);
1057 start
= t
->input
+ t
->offset
+ i
+ 1;
1065 if (t
->input
[t
->offset
+ i
] == '"') {
1068 buffer_append_string_len(token
, start
, t
->input
+ t
->offset
+ i
- start
);
1074 if (t
->input
[t
->offset
+ i
] == '\0') {
1077 log_error_write(srv
, __FILE__
, __LINE__
, "sbsdsds",
1078 "source:", t
->source
,
1079 "line:", t
->line
, "pos:", t
->line_pos
,
1080 "missing closing quote");
1086 t
->line_pos
+= i
+ 1;
1095 buffer_copy_string_len(token
, CONST_STR_LEN("("));
1103 buffer_copy_string_len(token
, CONST_STR_LEN(")"));
1112 buffer_copy_string_len(token
, CONST_STR_LEN("$"));
1117 if (t
->input
[t
->offset
+ 1] == '=') {
1119 buffer_copy_string_len(token
, CONST_STR_LEN("+="));
1124 buffer_copy_string_len(token
, CONST_STR_LEN("+"));
1129 if (t
->input
[t
->offset
+1] == '=') {
1131 tid
= TK_FORCE_ASSIGN
;
1132 buffer_copy_string_len(token
, CONST_STR_LEN(":="));
1135 log_error_write(srv
, __FILE__
, __LINE__
, "sbsdsds",
1136 "source:", t
->source
,
1137 "line:", t
->line
, "pos:", t
->line_pos
,
1138 "unexpected character ':'");
1148 buffer_copy_string_len(token
, CONST_STR_LEN("{"));
1157 buffer_copy_string_len(token
, CONST_STR_LEN("}"));
1159 for (; t
->offset
< t
->size
; ++t
->offset
,++t
->line_pos
) {
1160 c
= t
->input
[t
->offset
];
1161 if (c
== '\r' || c
== '\n') {
1164 else if (c
== '#') {
1165 t
->line_pos
+= config_skip_comment(t
);
1168 else if (c
!= ' ' && c
!= '\t') {
1169 t
->simulate_eol
= 1;
1171 } /* else (c == ' ' || c == '\t') */
1181 buffer_copy_string_len(token
, CONST_STR_LEN("["));
1190 buffer_copy_string_len(token
, CONST_STR_LEN("]"));
1194 t
->line_pos
+= config_skip_comment(t
);
1199 for (i
= 0; t
->input
[t
->offset
+ i
] &&
1200 (isalpha((unsigned char)t
->input
[t
->offset
+ i
])
1201 || t
->input
[t
->offset
+ i
] == '_'); ++i
);
1203 if (i
&& t
->input
[t
->offset
+ i
]) {
1204 tid
= TK_SRVVARNAME
;
1205 buffer_copy_string_len(token
, t
->input
+ t
->offset
, i
);
1211 log_error_write(srv
, __FILE__
, __LINE__
, "sbsdsds",
1212 "source:", t
->source
,
1213 "line:", t
->line
, "pos:", t
->line_pos
,
1214 "invalid character in condition");
1217 } else if (isdigit((unsigned char)c
)) {
1218 /* take all digits */
1219 for (i
= 0; t
->input
[t
->offset
+ i
] && isdigit((unsigned char)t
->input
[t
->offset
+ i
]); i
++);
1221 /* was there it least a digit ? */
1225 buffer_copy_string_len(token
, t
->input
+ t
->offset
, i
);
1231 /* the key might consist of [-.0-9a-z] */
1232 for (i
= 0; t
->input
[t
->offset
+ i
] &&
1233 (isalnum((unsigned char)t
->input
[t
->offset
+ i
]) ||
1234 t
->input
[t
->offset
+ i
] == '.' ||
1235 t
->input
[t
->offset
+ i
] == '_' || /* for env.* */
1236 t
->input
[t
->offset
+ i
] == '-'
1239 if (i
&& t
->input
[t
->offset
+ i
]) {
1240 buffer_copy_string_len(token
, t
->input
+ t
->offset
, i
);
1242 if (strcmp(token
->ptr
, "include") == 0) {
1244 } else if (strcmp(token
->ptr
, "include_shell") == 0) {
1245 tid
= TK_INCLUDE_SHELL
;
1246 } else if (strcmp(token
->ptr
, "global") == 0) {
1248 } else if (strcmp(token
->ptr
, "else") == 0) {
1258 log_error_write(srv
, __FILE__
, __LINE__
, "sbsdsds",
1259 "source:", t
->source
,
1260 "line:", t
->line
, "pos:", t
->line_pos
,
1261 "invalid character in variable name");
1272 log_error_write(srv
, __FILE__
, __LINE__
, "sbsdsdbdd",
1273 "source:", t
->source
,
1274 "line:", t
->line
, "pos:", t
->line_pos
,
1275 token
, token
->used
- 1, tid
);
1279 } else if (t
->offset
< t
->size
) {
1280 log_error_write(srv
, __FILE__
, __LINE__
, "Dsb", tid
, ",", token
);
1285 static int config_parse(server
*srv
, config_t
*context
, tokenizer_t
*t
) {
1288 buffer
*token
, *lasttoken
;
1291 pParser
= configparserAlloc( malloc
);
1292 force_assert(pParser
);
1293 lasttoken
= buffer_init();
1294 token
= buffer_init();
1295 while((1 == (ret
= config_tokenizer(srv
, t
, &token_id
, token
))) && context
->ok
) {
1296 buffer_copy_buffer(lasttoken
, token
);
1297 configparser(pParser
, token_id
, token
, context
);
1299 token
= buffer_init();
1303 if (ret
!= -1 && context
->ok
) {
1304 /* add an EOL at EOF, better than say sorry */
1305 configparser(pParser
, TK_EOL
, buffer_init_string("(EOL)"), context
);
1307 configparser(pParser
, 0, NULL
, context
);
1310 configparserFree(pParser
, free
);
1313 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
1314 "configfile parser failed at:", lasttoken
);
1315 } else if (context
->ok
== 0) {
1316 log_error_write(srv
, __FILE__
, __LINE__
, "sbsdsdsb",
1317 "source:", t
->source
,
1318 "line:", t
->line
, "pos:", t
->line_pos
,
1319 "parser failed somehow near here:", lasttoken
);
1322 buffer_free(lasttoken
);
1324 return ret
== -1 ? -1 : 0;
1327 static int tokenizer_init(tokenizer_t
*t
, const buffer
*source
, const char *input
, size_t size
) {
1339 t
->simulate_eol
= 0;
1343 static int config_parse_file_stream(server
*srv
, config_t
*context
, const buffer
*filename
) {
1348 if (0 != stream_open(&s
, filename
)) {
1349 log_error_write(srv
, __FILE__
, __LINE__
, "sbss",
1350 "opening configfile ", filename
, "failed:", strerror(errno
));
1353 tokenizer_init(&t
, filename
, s
.start
, s
.size
);
1354 ret
= config_parse(srv
, context
, &t
);
1361 int config_parse_file(server
*srv
, config_t
*context
, const char *fn
) {
1366 int flags
= GLOB_BRACE
;
1372 if ((fn
[0] == '/' || fn
[0] == '\\') ||
1373 (fn
[0] == '.' && (fn
[1] == '/' || fn
[1] == '\\')) ||
1374 (fn
[0] == '.' && fn
[1] == '.' && (fn
[2] == '/' || fn
[2] == '\\'))) {
1375 filename
= buffer_init_string(fn
);
1377 filename
= buffer_init_buffer(context
->basedir
);
1378 buffer_append_string(filename
, fn
);
1381 switch (glob(filename
->ptr
, flags
, NULL
, &gl
)) {
1383 for (i
= 0; i
< gl
.gl_pathc
; ++i
) {
1384 buffer_copy_string(filename
, gl
.gl_pathv
[i
]);
1385 ret
= config_parse_file_stream(srv
, context
, filename
);
1386 if (0 != ret
) break;
1391 if (filename
->ptr
[strcspn(filename
->ptr
, "*?[]{}")] != '\0') { /*(contains glob metachars)*/
1392 ret
= 0; /* not an error if no files match glob pattern */
1395 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "include file not found: ", filename
);
1400 log_error_write(srv
, __FILE__
, __LINE__
, "sbss", "glob()", filename
, "failed:", strerror(errno
));
1404 buffer_free(filename
);
1410 static char* getCWD(char *buf
, size_t sz
) {
1411 if (NULL
== getcwd(buf
, sz
)) {
1414 for (size_t i
= 0; buf
[i
]; ++i
) {
1415 if (buf
[i
] == '\\') buf
[i
] = '/';
1420 #define getcwd(buf, sz) getCWD((buf),(sz))
1422 #endif /* __CYGWIN__ */
1424 int config_parse_cmd(server
*srv
, config_t
*context
, const char *cmd
) {
1427 char oldpwd
[PATH_MAX
];
1429 if (NULL
== getcwd(oldpwd
, sizeof(oldpwd
))) {
1430 log_error_write(srv
, __FILE__
, __LINE__
, "s",
1431 "cannot get cwd", strerror(errno
));
1435 if (!buffer_string_is_empty(context
->basedir
)) {
1436 if (0 != chdir(context
->basedir
->ptr
)) {
1437 log_error_write(srv
, __FILE__
, __LINE__
, "sbs",
1438 "cannot change directory to", context
->basedir
, strerror(errno
));
1444 log_error_write(srv
, __FILE__
, __LINE__
, "ss",
1445 "pipe failed: ", strerror(errno
));
1449 char *shell
= getenv("SHELL");
1452 *(const char **)&args
[0] = shell
? shell
: "/bin/sh";
1453 *(const char **)&args
[1] = "-c";
1454 *(const char **)&args
[2] = cmd
;
1457 fdevent_setfd_cloexec(fds
[0]);
1458 pid
= fdevent_fork_execve(args
[0], args
, NULL
, -1, fds
[1], -1, -1);
1460 log_error_write(srv
, __FILE__
, __LINE__
, "SSss",
1461 "fork/exec(", cmd
, "):", strerror(errno
));
1468 buffer
*out
= buffer_init();
1472 rd
= read(fds
[0], buffer_string_prepare_append(out
, 1023), 1023);
1473 if (rd
>= 0) buffer_commit(out
, (size_t)rd
);
1474 } while (rd
> 0 || (-1 == rd
&& errno
== EINTR
));
1476 log_error_write(srv
, __FILE__
, __LINE__
, "SSss",
1477 "read \"", cmd
, "\" failed:", strerror(errno
));
1482 while (-1 == (wpid
= waitpid(pid
, &wstatus
, 0)) && errno
== EINTR
) ;
1484 log_error_write(srv
, __FILE__
, __LINE__
, "SSss",
1485 "waitpid \"", cmd
, "\" failed:", strerror(errno
));
1489 log_error_write(srv
, __FILE__
, __LINE__
, "SSsd",
1490 "command \"", cmd
, "\" exited non-zero:", WEXITSTATUS(wstatus
));
1495 buffer
*source
= buffer_init_string(cmd
);
1497 tokenizer_init(&t
, source
, CONST_BUF_LEN(out
));
1498 ret
= config_parse(srv
, context
, &t
);
1499 buffer_free(source
);
1503 if (-1 != fds
[0]) close(fds
[0]);
1504 if (-1 != fds
[1]) close(fds
[1]);
1507 if (0 != chdir(oldpwd
)) {
1508 log_error_write(srv
, __FILE__
, __LINE__
, "sss",
1509 "cannot change directory to", oldpwd
, strerror(errno
));
1515 static void context_init(server
*srv
, config_t
*context
) {
1518 vector_config_weak_init(&context
->configs_stack
);
1519 context
->basedir
= buffer_init();
1522 static void context_free(config_t
*context
) {
1523 vector_config_weak_clear(&context
->configs_stack
);
1524 buffer_free(context
->basedir
);
1527 int config_read(server
*srv
, const char *fn
) {
1535 context_init(srv
, &context
);
1536 context
.all_configs
= srv
->config_context
;
1539 pos
= strrchr(fn
, '\\');
1541 pos
= strrchr(fn
, '/');
1544 buffer_copy_string_len(context
.basedir
, fn
, pos
- fn
+ 1);
1547 dc
= data_config_init();
1548 buffer_copy_string_len(dc
->key
, CONST_STR_LEN("global"));
1550 force_assert(context
.all_configs
->used
== 0);
1551 dc
->context_ndx
= context
.all_configs
->used
;
1552 array_insert_unique(context
.all_configs
, (data_unset
*)dc
);
1553 context
.current
= dc
;
1555 /* default context */
1556 *array_get_int_ptr(dc
->value
, CONST_STR_LEN("var.PID")) = getpid();
1558 dcwd
= srv
->tmp_buf
;
1559 buffer_string_prepare_copy(dcwd
, PATH_MAX
-1);
1560 if (NULL
!= getcwd(dcwd
->ptr
, buffer_string_space(dcwd
)+1)) {
1561 buffer_commit(dcwd
, strlen(dcwd
->ptr
));
1562 array_set_key_value(dc
->value
, CONST_STR_LEN("var.CWD"), CONST_BUF_LEN(dcwd
));
1565 filename
= buffer_init_string(fn
);
1566 ret
= config_parse_file_stream(srv
, &context
, filename
);
1567 buffer_free(filename
);
1569 /* remains nothing if parser is ok */
1570 force_assert(!(0 == ret
&& context
.ok
&& 0 != context
.configs_stack
.used
));
1571 context_free(&context
);
1577 if (0 != config_insert(srv
)) {
1584 int config_set_defaults(server
*srv
) {
1586 specific_config
*s
= srv
->config_storage
[0];
1587 struct stat st1
, st2
;
1589 force_assert(sizeof(((connection
*)0)->conditional_is_valid
) >= COMP_LAST_ELEMENT
);
1591 if (0 != fdevent_config(srv
)) return -1;
1593 if (!buffer_string_is_empty(srv
->srvconf
.changeroot
)) {
1594 if (-1 == stat(srv
->srvconf
.changeroot
->ptr
, &st1
)) {
1595 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
1596 "server.chroot doesn't exist:", srv
->srvconf
.changeroot
);
1599 if (!S_ISDIR(st1
.st_mode
)) {
1600 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
1601 "server.chroot isn't a directory:", srv
->srvconf
.changeroot
);
1606 if (!srv
->srvconf
.upload_tempdirs
->used
) {
1607 const char *tmpdir
= getenv("TMPDIR");
1608 if (NULL
== tmpdir
) tmpdir
= "/var/tmp";
1609 array_insert_value(srv
->srvconf
.upload_tempdirs
, tmpdir
, strlen(tmpdir
));
1612 if (srv
->srvconf
.upload_tempdirs
->used
) {
1613 buffer
* const b
= srv
->tmp_buf
;
1616 if (!buffer_string_is_empty(srv
->srvconf
.changeroot
)) {
1617 buffer_copy_buffer(b
, srv
->srvconf
.changeroot
);
1618 buffer_append_slash(b
);
1620 len
= buffer_string_length(b
);
1622 for (i
= 0; i
< srv
->srvconf
.upload_tempdirs
->used
; ++i
) {
1623 const data_string
* const ds
= (data_string
*)srv
->srvconf
.upload_tempdirs
->data
[i
];
1624 buffer_string_set_length(b
, len
); /*(truncate)*/
1625 buffer_append_string_buffer(b
, ds
->value
);
1626 if (-1 == stat(b
->ptr
, &st1
)) {
1627 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
1628 "server.upload-dirs doesn't exist:", b
);
1629 } else if (!S_ISDIR(st1
.st_mode
)) {
1630 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
1631 "server.upload-dirs isn't a directory:", b
);
1636 chunkqueue_set_tempdirs_default(
1637 srv
->srvconf
.upload_tempdirs
,
1638 srv
->srvconf
.upload_temp_file_size
);
1640 if (buffer_string_is_empty(s
->document_root
)) {
1641 log_error_write(srv
, __FILE__
, __LINE__
, "s",
1642 "a default document-root has to be set");
1647 buffer_copy_buffer(srv
->tmp_buf
, s
->document_root
);
1649 buffer_to_lower(srv
->tmp_buf
);
1651 if (2 == s
->force_lowercase_filenames
) { /* user didn't configure it in global section? */
1652 s
->force_lowercase_filenames
= 0; /* default to 0 */
1654 if (0 == stat(srv
->tmp_buf
->ptr
, &st1
)) {
1657 is_lower
= buffer_is_equal(srv
->tmp_buf
, s
->document_root
);
1659 /* lower-case existed, check upper-case */
1660 buffer_copy_buffer(srv
->tmp_buf
, s
->document_root
);
1662 buffer_to_upper(srv
->tmp_buf
);
1664 /* we have to handle the special case that upper and lower-casing results in the same filename
1665 * as in server.document-root = "/" or "/12345/" */
1667 if (is_lower
&& buffer_is_equal(srv
->tmp_buf
, s
->document_root
)) {
1668 /* lower-casing and upper-casing didn't result in
1669 * an other filename, no need to stat(),
1670 * just assume it is case-sensitive. */
1672 s
->force_lowercase_filenames
= 0;
1673 } else if (0 == stat(srv
->tmp_buf
->ptr
, &st2
)) {
1675 /* upper case exists too, doesn't the FS handle this ? */
1677 /* upper and lower have the same inode -> case-insensitve FS */
1679 if (st1
.st_ino
== st2
.st_ino
) {
1680 /* upper and lower have the same inode -> case-insensitve FS */
1682 s
->force_lowercase_filenames
= 1;
1688 if (srv
->srvconf
.port
== 0) {
1689 srv
->srvconf
.port
= s
->ssl_enabled
? 443 : 80;