1 :
2 : #include "httpd.h"
3 : #include "httpd_policy.h"
4 :
5 : #include <err.h>
6 :
7 : #define EX_UTILS_NO_USE_INIT 1
8 : #define EX_UTILS_NO_USE_EXIT 1
9 : #define EX_UTILS_NO_USE_LIMIT 1
10 : #define EX_UTILS_NO_USE_INPUT 1
11 : #define EX_UTILS_NO_USE_BLOCK 1
12 : #define EX_UTILS_NO_USE_PUT 1
13 : #define EX_UTILS_NO_USE_BLOCKING_OPEN 1
14 : #define EX_UTILS_RET_FAIL 1
15 : #include "ex_utils.h"
16 :
17 : #define HTTPD_CONF_REQ__X_CONTENT_SINGLE_VSTR(x) do { \
18 : if (!httpd__conf_req_single_str(req, conf, token, \
19 : &req-> x ## _vs1, \
20 : &req-> x ## _pos, \
21 : &req-> x ## _len)) \
22 : return (FALSE); \
23 : } while (FALSE)
24 :
25 : #define HTTPD_CONF_REQ__X_CONTENT_VSTR(x) do { \
26 : if (!httpd__conf_req_make_str(req, conf, token, \
27 : &req-> x ## _vs1, \
28 : &req-> x ## _pos, \
29 : &req-> x ## _len)) \
30 : return (FALSE); \
31 : } while (FALSE)
32 :
33 :
34 :
35 : #define HTTPD_CONF_REQ__TYPE_BUILD_PATH_SKIP 0
36 : #define HTTPD_CONF_REQ__TYPE_BUILD_PATH_ASSIGN 1
37 : #define HTTPD_CONF_REQ__TYPE_BUILD_PATH_APPEND 2
38 :
39 : static int httpd__conf_req_single_str(Httpd_req_data *req,
40 : Conf_parse *conf, Conf_token *token,
41 : const Vstr_base **s1,
42 : size_t *pos, size_t *len)
43 16512 : {
44 16512 : Vstr_base *xs1 = req->xtra_content;
45 :
46 8256 : ASSERT(s1 && pos && len);
47 8256 : ASSERT((*s1 == xs1) || !*s1);
48 :
49 : /* always delete, so don't call http_req_xtra_content() as it might do a
50 : copy */
51 16512 : if (!req->xtra_content && !(req->xtra_content = vstr_make_base(NULL)))
52 0 : return (FALSE);
53 16512 : xs1 = req->xtra_content;
54 :
55 16512 : if (*len && (vstr_sc_poslast(*pos, *len) == xs1->len))
56 32 : vstr_del(req->xtra_content, *pos, *len);
57 :
58 16512 : *pos = xs1->len;
59 16512 : *len = 0;
60 16512 : if (conf_sc_token_app_vstr(conf, token, xs1, s1, pos, len))
61 0 : return (FALSE);
62 :
63 16512 : if ((token->type == CONF_TOKEN_TYPE_QUOTE_ESC_D) ||
64 : (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_DDD) ||
65 : (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_S) ||
66 : (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_SSS) ||
67 : FALSE)
68 1152 : if (!*s1 || !conf_sc_conv_unesc(xs1, *pos, *len, len))
69 0 : return (FALSE);
70 :
71 16512 : return (TRUE);
72 : }
73 :
74 : /* if we aren't the last string in the XTRA_CONTENT, copy to the last bit
75 : * Then pass the last bit to make_str */
76 : static int httpd__conf_req_make_str(Httpd_req_data *req,
77 : Conf_parse *conf, Conf_token *token,
78 : const Vstr_base **s1,
79 : size_t *pos, size_t *len)
80 12032 : {
81 12032 : Opt_serv_opts *opts = req->policy->s->beg;
82 12032 : size_t xpos = 0;
83 :
84 12032 : if (!(xpos = http_req_xtra_content(req, *s1, *pos, len)))
85 0 : return (FALSE);
86 :
87 12032 : if (!opt_serv_sc_make_str(opts, conf, token, req->xtra_content, xpos, *len))
88 0 : return (FALSE);
89 :
90 12032 : *s1 = req->xtra_content;
91 12032 : *pos = xpos;
92 12032 : *len = (req->xtra_content->len - xpos) + 1;
93 :
94 12032 : return (TRUE);
95 : }
96 :
97 :
98 : static void httpd__conf_req_reset_expires(struct Httpd_req_data *req,
99 : unsigned int off)
100 0 : {
101 0 : Vstr_base *s1 = req->xtra_content;
102 0 : size_t pos = req->expires_pos;
103 0 : size_t len = req->expires_len;
104 0 : Opt_serv_opts *opts = req->policy->s->beg;
105 0 : Date_store *date = ((Httpd_opts *)opts)->date;
106 :
107 0 : ASSERT(vstr_sc_poslast(pos, len) == s1->len);
108 :
109 0 : if (off > (60 * 60 * 24 * 365))
110 0 : off = (60 * 60 * 24 * 365);
111 :
112 0 : if (vstr_sub_cstr_buf(s1, pos, len, date_rfc1123(date, req->now + off)))
113 0 : req->expires_len = vstr_sc_posdiff(pos, s1->len);
114 0 : }
115 :
116 : static void httpd__conf_req_reset_cache_control(struct Httpd_req_data *req,
117 : unsigned int val)
118 0 : {
119 0 : Vstr_base *s1 = req->xtra_content;
120 0 : size_t pos = req->cache_control_pos;
121 0 : size_t len = req->cache_control_len;
122 :
123 0 : ASSERT(pos && len);
124 0 : ASSERT(vstr_sc_poslast(pos, len) == s1->len);
125 :
126 0 : if (val > (60 * 60 * 24 * 365))
127 0 : val = (60 * 60 * 24 * 365);
128 :
129 0 : if (vstr_add_fmt(s1, pos - 1, "max-age=%u", val))
130 : {
131 0 : vstr_sc_reduce(s1, 1, s1->len, len);
132 0 : req->cache_control_len = vstr_sc_posdiff(pos, s1->len);
133 : }
134 0 : }
135 :
136 : static int httpd__build_path(struct Con *con, Httpd_req_data *req,
137 : const Conf_parse *conf, Conf_token *token,
138 : Vstr_base *s1, size_t pos, size_t len,
139 : unsigned int lim, int full, Vstr_ref *ref,
140 : int uri_fname, int *type)
141 11968 : {
142 : int dummy_type;
143 11968 : int clist = FALSE;
144 :
145 11968 : if (!type) type = &dummy_type;
146 11968 : *type = HTTPD_CONF_REQ__TYPE_BUILD_PATH_SKIP;
147 :
148 11968 : if (uri_fname)
149 : {
150 4864 : int slash_dot_safe = FALSE;
151 :
152 4864 : if (req->chk_encoded_slash && req->chk_encoded_dot)
153 4288 : slash_dot_safe = TRUE;
154 4864 : if (!httpd_policy_uri_lim_eq(s1, &pos, &len, lim, slash_dot_safe, ref))
155 : {
156 0 : int ret = conf_parse_end_token(conf, token, conf_token_at_depth(token));
157 0 : ASSERT(ret);
158 0 : return (TRUE);
159 : }
160 : }
161 : else
162 : {
163 7104 : size_t vhost_len = req->vhost_prefix_len;
164 :
165 7104 : if (!httpd_policy_path_lim_eq(s1, &pos, &len, lim, vhost_len, ref))
166 : {
167 960 : int ret = conf_parse_end_token(conf, token, conf_token_at_depth(token));
168 480 : ASSERT(ret);
169 960 : return (TRUE);
170 : }
171 :
172 6144 : if (full && vhost_len)
173 : { /* don't want to keep the vhost data */
174 32 : if (lim != HTTPD_POLICY_PATH_LIM_NONE)
175 0 : pos -= vhost_len;
176 : else
177 32 : len -= vhost_len;
178 :
179 16 : ASSERT(req->fname == s1);
180 32 : vstr_del(req->fname, 1, vhost_len);
181 32 : req->vhost_prefix_len = 0;
182 : }
183 : }
184 11008 : *type = HTTPD_CONF_REQ__TYPE_BUILD_PATH_ASSIGN;
185 :
186 11008 : CONF_SC_TOGGLE_CLIST_VAR(clist);
187 :
188 : if (0) { }
189 :
190 13312 : else if (OPT_SERV_SYM_EQ("assign") || OPT_SERV_SYM_EQ("="))
191 : {
192 4608 : if (!httpd_policy_build_path(con, req, conf, token, NULL, NULL))
193 0 : return (FALSE);
194 :
195 4608 : if (!vstr_sub_vstr(s1, pos, len,
196 : conf->tmp, 1, conf->tmp->len, VSTR_TYPE_SUB_BUF_REF))
197 0 : return (FALSE);
198 : }
199 6400 : else if (OPT_SERV_SYM_EQ("append") || OPT_SERV_SYM_EQ("+=") ||
200 : OPT_SERV_SYM_EQ(".=") || OPT_SERV_SYM_EQ(">>="))
201 : {
202 288 : *type = HTTPD_CONF_REQ__TYPE_BUILD_PATH_APPEND;
203 :
204 288 : if (!httpd_policy_build_path(con, req, conf, token, NULL, NULL))
205 0 : return (FALSE);
206 :
207 288 : return (vstr_add_vstr(s1, vstr_sc_poslast(pos, len),
208 : conf->tmp, 1, conf->tmp->len, VSTR_TYPE_ADD_BUF_REF));
209 : }
210 6112 : else if (OPT_SERV_SYM_EQ("prepend") || OPT_SERV_SYM_EQ("<<="))
211 : {
212 768 : *type = HTTPD_CONF_REQ__TYPE_BUILD_PATH_APPEND;
213 :
214 768 : if (!httpd_policy_build_path(con, req, conf, token, NULL, NULL))
215 0 : return (FALSE);
216 :
217 768 : return (vstr_add_vstr(s1, pos - 1,
218 : conf->tmp, 1, conf->tmp->len, VSTR_TYPE_ADD_BUF_REF));
219 : }
220 5344 : else if (!clist)
221 : {
222 5344 : const Vstr_sect_node *pv = conf_token_value(token);
223 :
224 5344 : if (!pv || !vstr_sub_vstr(s1, pos, len, conf->data, pv->pos, pv->len,
225 : VSTR_TYPE_SUB_BUF_REF))
226 0 : return (FALSE);
227 5344 : OPT_SERV_X__ESC_VSTR(s1, pos, pv->len);
228 :
229 2672 : goto fin_overwrite;
230 : }
231 : else
232 0 : return (FALSE);
233 :
234 9952 : fin_overwrite:
235 9952 : if (lim == HTTPD_POLICY_PATH_LIM_NONE)
236 1056 : req->vhost_prefix_len = 0; /* replaced everything */
237 :
238 9952 : return (TRUE);
239 : }
240 :
241 : static int httpd__meta_build_path(struct Con *con, Httpd_req_data *req,
242 : Conf_parse *conf, Conf_token *token,
243 : int *full, int *canon,
244 : unsigned int *lim, Vstr_ref **ret_ref)
245 11968 : {
246 11968 : unsigned int depth = token->depth_num;
247 :
248 5984 : ASSERT(ret_ref && !*ret_ref);
249 :
250 11968 : if (token->type != CONF_TOKEN_TYPE_SLIST)
251 2624 : return (TRUE);
252 :
253 24320 : while (conf_token_list_num(token, depth))
254 : {
255 10304 : int clist = FALSE;
256 :
257 10304 : CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, TRUE);
258 10304 : CONF_SC_TOGGLE_CLIST_VAR(clist);
259 :
260 : if (0) { }
261 10336 : else if (full && (OPT_SERV_SYM_EQ("skip-virtual-hosts") ||
262 : OPT_SERV_SYM_EQ("skip-vhosts")))
263 32 : OPT_SERV_X_TOGGLE(*full);
264 11296 : else if (canon && (OPT_SERV_SYM_EQ("make-abs-url") ||
265 : OPT_SERV_SYM_EQ("make-absolute-url")))
266 1024 : OPT_SERV_X_TOGGLE(*canon);
267 9312 : else if (full && OPT_SERV_SYM_EQ("skip-document-root"))
268 64 : OPT_SERV_X_TOGGLE(req->skip_document_root);
269 9184 : else if (OPT_SERV_SYM_EQ("limit"))
270 : {
271 9184 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
272 :
273 9184 : vstr_ref_del(*ret_ref); *ret_ref = NULL;
274 9184 : if (token->type >= CONF_TOKEN_TYPE_USER_BEG)
275 : {
276 4172 : unsigned int type = token->type - CONF_TOKEN_TYPE_USER_BEG;
277 4172 : unsigned int nxt = 0;
278 4172 : Vstr_ref *ref = conf_token_get_user_value(conf, token, &nxt);
279 :
280 4172 : switch (type)
281 : {
282 : case HTTPD_POLICY_REQ_PATH_BEG:
283 : case HTTPD_POLICY_REQ_PATH_END:
284 : case HTTPD_POLICY_REQ_PATH_EQ:
285 :
286 : case HTTPD_POLICY_REQ_NAME_BEG:
287 : case HTTPD_POLICY_REQ_NAME_END:
288 : case HTTPD_POLICY_REQ_NAME_EQ:
289 :
290 : case HTTPD_POLICY_REQ_BWEN_BEG:
291 : case HTTPD_POLICY_REQ_BWEN_END:
292 : case HTTPD_POLICY_REQ_BWEN_EQ:
293 :
294 : case HTTPD_POLICY_REQ_BWES_BEG:
295 : case HTTPD_POLICY_REQ_BWES_END:
296 : case HTTPD_POLICY_REQ_BWES_EQ:
297 :
298 : case HTTPD_POLICY_REQ_EXTN_BEG:
299 : case HTTPD_POLICY_REQ_EXTN_END:
300 : case HTTPD_POLICY_REQ_EXTN_EQ:
301 :
302 : case HTTPD_POLICY_REQ_EXTS_BEG:
303 : case HTTPD_POLICY_REQ_EXTS_END:
304 : case HTTPD_POLICY_REQ_EXTS_EQ:
305 4172 : *lim = httpd_policy_path_req2lim(type);
306 : break;
307 :
308 : default:
309 0 : vstr_ref_del(ref);
310 0 : return (FALSE);
311 : }
312 4172 : *ret_ref = ref;
313 8344 : if (nxt && !conf_parse_num_token(conf, token, nxt))
314 0 : return (FALSE);
315 : }
316 :
317 5108 : else if (OPT_SERV_SYM_EQ("<none>") || OPT_SERV_SYM_EQ("none"))
318 96 : *lim = HTTPD_POLICY_PATH_LIM_NONE;
319 5876 : else if (OPT_SERV_SYM_EQ("<path>") || OPT_SERV_SYM_EQ("path"))
320 960 : *lim = HTTPD_POLICY_PATH_LIM_PATH_FULL;
321 3956 : else if (OPT_SERV_SYM_EQ("<basename>") || OPT_SERV_SYM_EQ("basename"))
322 0 : *lim = HTTPD_POLICY_PATH_LIM_NAME_FULL;
323 4212 : else if (OPT_SERV_SYM_EQ("<extension>") || OPT_SERV_SYM_EQ("extension"))
324 256 : *lim = HTTPD_POLICY_PATH_LIM_EXTN_FULL;
325 3956 : else if (OPT_SERV_SYM_EQ("<extensions>") || OPT_SERV_SYM_EQ("extensions"))
326 256 : *lim = HTTPD_POLICY_PATH_LIM_EXTS_FULL;
327 3444 : else if (OPT_SERV_SYM_EQ("<basename-without-extension>") ||
328 : OPT_SERV_SYM_EQ("basename-without-extension"))
329 0 : *lim = HTTPD_POLICY_PATH_LIM_BWEN_FULL;
330 3444 : else if (OPT_SERV_SYM_EQ("<basename-without-extensions>") ||
331 : OPT_SERV_SYM_EQ("basename-without-extensions"))
332 0 : *lim = HTTPD_POLICY_PATH_LIM_BWES_FULL;
333 : else
334 : {
335 3444 : unsigned int type = HTTPD_POLICY_REQ_PATH_BEG;
336 :
337 : if (0) { }
338 3484 : else if (OPT_SERV_SYM_EQ("<path>-beg") || OPT_SERV_SYM_EQ("path-beg"))
339 40 : type = HTTPD_POLICY_REQ_PATH_BEG;
340 6808 : else if (OPT_SERV_SYM_EQ("<path>-end") || OPT_SERV_SYM_EQ("path-end"))
341 3404 : type = HTTPD_POLICY_REQ_PATH_END;
342 0 : else if (OPT_SERV_SYM_EQ("<path>-eq") || OPT_SERV_SYM_EQ("path-eq") ||
343 : OPT_SERV_SYM_EQ("<path>==") || OPT_SERV_SYM_EQ("path=="))
344 0 : type = HTTPD_POLICY_REQ_PATH_EQ;
345 0 : else if (OPT_SERV_SYM_EQ("<basename>-beg") ||
346 : OPT_SERV_SYM_EQ("basename-beg") ||
347 : OPT_SERV_SYM_EQ("<basename>==") ||
348 : OPT_SERV_SYM_EQ("basename=="))
349 0 : type = HTTPD_POLICY_REQ_NAME_BEG;
350 0 : else if (OPT_SERV_SYM_EQ("<basename>-end") ||
351 : OPT_SERV_SYM_EQ("basename-end"))
352 0 : type = HTTPD_POLICY_REQ_NAME_END;
353 0 : else if (OPT_SERV_SYM_EQ("<basename>-eq") ||
354 : OPT_SERV_SYM_EQ("basename-eq") ||
355 : OPT_SERV_SYM_EQ("<basename>==") ||
356 : OPT_SERV_SYM_EQ("basename=="))
357 0 : type = HTTPD_POLICY_REQ_NAME_EQ;
358 0 : else if (OPT_SERV_SYM_EQ("<extension>-beg") ||
359 : OPT_SERV_SYM_EQ("extension-beg"))
360 0 : type = HTTPD_POLICY_REQ_EXTN_BEG;
361 0 : else if (OPT_SERV_SYM_EQ("<extension>-end") ||
362 : OPT_SERV_SYM_EQ("extension-end"))
363 0 : type = HTTPD_POLICY_REQ_EXTN_END;
364 0 : else if (OPT_SERV_SYM_EQ("<extension>-eq") ||
365 : OPT_SERV_SYM_EQ("extension-eq") ||
366 : OPT_SERV_SYM_EQ("<extension>==") ||
367 : OPT_SERV_SYM_EQ("extension=="))
368 0 : type = HTTPD_POLICY_REQ_EXTN_EQ;
369 0 : else if (OPT_SERV_SYM_EQ("<extensions>-beg") ||
370 : OPT_SERV_SYM_EQ("extensions-beg"))
371 0 : type = HTTPD_POLICY_REQ_EXTS_BEG;
372 0 : else if (OPT_SERV_SYM_EQ("<extensions>-end") ||
373 : OPT_SERV_SYM_EQ("extensions-end"))
374 0 : type = HTTPD_POLICY_REQ_EXTS_END;
375 0 : else if (OPT_SERV_SYM_EQ("<extensions>-eq") ||
376 : OPT_SERV_SYM_EQ("extensions-eq") ||
377 : OPT_SERV_SYM_EQ("<extensions>==") ||
378 : OPT_SERV_SYM_EQ("extensions=="))
379 0 : type = HTTPD_POLICY_REQ_EXTS_EQ;
380 0 : else if (OPT_SERV_SYM_EQ("<basename-without-extension>-beg") ||
381 : OPT_SERV_SYM_EQ("basename-without-extension-beg"))
382 0 : type = HTTPD_POLICY_REQ_BWEN_BEG;
383 0 : else if (OPT_SERV_SYM_EQ("<basename-without-extension>-end") ||
384 : OPT_SERV_SYM_EQ("basename-without-extension-end"))
385 0 : type = HTTPD_POLICY_REQ_BWEN_END;
386 0 : else if (OPT_SERV_SYM_EQ("<basename-without-extension>-eq") ||
387 : OPT_SERV_SYM_EQ("basename-without-extension-eq") ||
388 : OPT_SERV_SYM_EQ("<basename-without-extension>==") ||
389 : OPT_SERV_SYM_EQ("basename-without-extension=="))
390 0 : type = HTTPD_POLICY_REQ_BWEN_EQ;
391 0 : else if (OPT_SERV_SYM_EQ("<basename-without-extensions>-beg") ||
392 : OPT_SERV_SYM_EQ("basename-without-extensions-beg"))
393 0 : type = HTTPD_POLICY_REQ_BWES_BEG;
394 0 : else if (OPT_SERV_SYM_EQ("<basename-without-extensions>-end") ||
395 : OPT_SERV_SYM_EQ("basename-without-extensions-end"))
396 0 : type = HTTPD_POLICY_REQ_BWES_END;
397 0 : else if (OPT_SERV_SYM_EQ("<basename-without-extensions>-eq") ||
398 : OPT_SERV_SYM_EQ("basename-without-extensions-eq") ||
399 : OPT_SERV_SYM_EQ("<basename-without-extensions>==") ||
400 : OPT_SERV_SYM_EQ("basename-without-extensions=="))
401 0 : type = HTTPD_POLICY_REQ_BWES_EQ;
402 : else
403 0 : return (FALSE);
404 :
405 3444 : if (!httpd_policy_path_make(con, req, conf, token, type, ret_ref))
406 0 : return (FALSE);
407 :
408 3444 : *lim = httpd_policy_path_req2lim(type);
409 : }
410 : }
411 : else
412 0 : return (FALSE);
413 : }
414 :
415 9344 : CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth - 1, FALSE);
416 9344 : return (TRUE);
417 : }
418 :
419 : static int httpd__content_location_valid(Httpd_req_data *req,
420 : size_t *ret_pos, size_t *ret_len)
421 0 : {
422 0 : *ret_pos = req->content_location_pos;
423 0 : *ret_len = req->content_location_len;
424 :
425 0 : *ret_pos = http_req_xtra_content(req, req->xtra_content, *ret_pos, ret_len);
426 :
427 0 : return (!!*ret_pos);
428 : }
429 :
430 : /* we negotiate a few items, and this is the loop for all of them... */
431 : #define HTTPD__NEG_BEG(x) \
432 : unsigned int depth = token->depth_num; \
433 : unsigned int max_qual = 0; \
434 : unsigned int qual_num = 0; \
435 : unsigned int neg_count = 0; \
436 : Conf_token save; \
437 : \
438 : save = *token; \
439 : while (conf_token_list_num(token, depth) && \
440 : (!(x) || (++neg_count <= (x)))) \
441 : { \
442 : unsigned int qual = 0; \
443 : const Vstr_sect_node *val = NULL; \
444 : \
445 : CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, TRUE); \
446 : CONF_SC_TOGGLE_CLIST_VAR(clist); \
447 : \
448 : if (!((token->type == CONF_TOKEN_TYPE_QUOTE_D) || \
449 : (token->type == CONF_TOKEN_TYPE_QUOTE_DDD) || \
450 : (token->type == CONF_TOKEN_TYPE_QUOTE_S) || \
451 : (token->type == CONF_TOKEN_TYPE_QUOTE_SSS) || \
452 : (token->type == CONF_TOKEN_TYPE_SYMBOL))) \
453 : return (FALSE); \
454 : \
455 : val = conf_token_value(token)
456 :
457 :
458 : #define HTTPD__NEG_END() \
459 : if (qual > max_qual) \
460 : { \
461 : max_qual = qual; \
462 : qual_num = token->num - 1; \
463 : } \
464 : \
465 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE); \
466 : } \
467 : if (neg_count) \
468 : { \
469 : int ret = conf_parse_end_token(conf, token, depth); \
470 : ASSERT(ret); \
471 : } \
472 : do { } while (FALSE)
473 :
474 :
475 : /* match with an 's' is it's > 1, otherwise without ... zero special cased */
476 : #define HTTPD__EXPIRES_CMP(x, y) \
477 : (((num == 1) && \
478 : vstr_cmp_cstr_eq(HTTP_REQ__CONT_PARAMS(req, x), "<" y ">")) || \
479 : ((num > 1) && \
480 : vstr_cmp_cstr_eq(HTTP_REQ__CONT_PARAMS(req, x), "<" y "s>")))
481 :
482 : #define HTTPD__CONF_REDIR(req, code) do { \
483 : if ((req)->direct_uri) { \
484 : httpd_req_absolute_uri(con, req, \
485 : (req)->fname, 1, (req)->fname->len); \
486 : HTTPD_REDIR_MSG(req, code, "Req conf"); \
487 : return (FALSE); \
488 : } \
489 : } while (FALSE)
490 :
491 : static int httpd__conf_req_d1(struct Con *con, struct Httpd_req_data *req,
492 : time_t file_timestamp,
493 : Conf_parse *conf, Conf_token *token, int clist)
494 41024 : {
495 : if (0) { }
496 :
497 41024 : else if (OPT_SERV_SYM_EQ("match-init"))
498 0 : OPT_SERV_SC_MATCH_INIT(req->policy->s->beg,
499 : httpd__conf_req_d1(con, req, file_timestamp,
500 : conf, token, clist));
501 :
502 41024 : else if (OPT_SERV_SYM_EQ("match-request"))
503 : {
504 : static unsigned int match_req_rec_depth = 0; /* no inf. recursion */
505 : static int prev_match = TRUE;
506 736 : unsigned int depth = token->depth_num;
507 736 : int matches = TRUE;
508 :
509 736 : if (match_req_rec_depth > 4) /* FIXME: conf */
510 0 : return (FALSE);
511 :
512 736 : CONF_SC_PARSE_SLIST_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
513 736 : ++depth;
514 2208 : while (conf_token_list_num(token, depth))
515 : {
516 736 : CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
517 :
518 736 : if (!httpd_match_request_sc_tst_d1(con, req, conf, token, &matches,
519 : prev_match))
520 0 : return (FALSE);
521 :
522 736 : if (!matches)
523 352 : conf_parse_end_token(conf, token, depth - 1);
524 : }
525 736 : --depth;
526 :
527 736 : prev_match = matches;
528 :
529 1856 : while (conf_token_list_num(token, depth))
530 : {
531 512 : int ret = FALSE;
532 :
533 512 : CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
534 512 : CONF_SC_TOGGLE_CLIST_VAR(clist);
535 :
536 512 : ++match_req_rec_depth;
537 512 : ret = httpd__conf_req_d1(con, req, file_timestamp, conf, token, clist);
538 512 : --match_req_rec_depth;
539 :
540 512 : if (!ret)
541 128 : return (FALSE);
542 : }
543 : }
544 :
545 40288 : else if (OPT_SERV_SYM_EQ("return"))
546 : {
547 4128 : unsigned int code = 0;
548 :
549 4128 : OPT_SERV_X_SYM_UINT_BEG(code);
550 :
551 4800 : else if (OPT_SERV_SYM_EQ("<perm>") ||
552 : OPT_SERV_SYM_EQ("<perm-redirect>") ||
553 : OPT_SERV_SYM_EQ("<permanent>") || /* sp is permanent */
554 : OPT_SERV_SYM_EQ("<permenant>") || /* allow bad sp */
555 : OPT_SERV_SYM_EQ("<permanent-redirect>") ||
556 : OPT_SERV_SYM_EQ("<permenant-redirect>"))
557 1472 : code = 301;
558 1856 : else if (OPT_SERV_SYM_EQ("<found>"))
559 128 : code = 302;
560 1856 : else if (OPT_SERV_SYM_EQ("<other>") || OPT_SERV_SYM_EQ("<see-other>"))
561 128 : code = 303;
562 1856 : else if (OPT_SERV_SYM_EQ("<tmp>") || OPT_SERV_SYM_EQ("<tmp-redirect>") ||
563 : OPT_SERV_SYM_EQ("<temp>") ||
564 : OPT_SERV_SYM_EQ("<temp-redirect>") ||
565 : OPT_SERV_SYM_EQ("<temporary>") ||
566 : OPT_SERV_SYM_EQ("<temporary-redirect>"))
567 256 : code = 307;
568 1344 : else if (OPT_SERV_SYM_EQ("<bad>") || OPT_SERV_SYM_EQ("<bad-request>"))
569 0 : code = 400;
570 1344 : else if (OPT_SERV_SYM_EQ("<forbidden>"))
571 928 : code = 403;
572 416 : else if (OPT_SERV_SYM_EQ("<not-found>"))
573 64 : code = 404;
574 352 : else if (OPT_SERV_SYM_EQ("<not-acceptable>"))
575 0 : code = 406;
576 352 : else if (OPT_SERV_SYM_EQ("<gone>"))
577 352 : code = 410;
578 0 : else if (OPT_SERV_SYM_EQ("<error>") ||
579 : OPT_SERV_SYM_EQ("<internal-server-error>"))
580 0 : code = 500;
581 0 : else if (OPT_SERV_SYM_EQ("<service-unavailable>"))
582 0 : code = 503;
583 :
584 0 : OPT_SERV_X_SYM_NUM_END();
585 :
586 4128 : req->user_return_error_code = TRUE;
587 2064 : ASSERT(!req->error_code);
588 4128 : req->error_code = 0;
589 4128 : switch (code)
590 : {
591 1888 : case 301: HTTPD__CONF_REDIR(req, 301);
592 256 : case 302: HTTPD__CONF_REDIR(req, 302);
593 256 : case 303: HTTPD__CONF_REDIR(req, 303);
594 384 : case 307: HTTPD__CONF_REDIR(req, 307);
595 : default:
596 0 : req->user_return_error_code = FALSE;
597 0 : return (FALSE);
598 :
599 0 : case 400: HTTPD_ERR_MSG_RET(req, 400, "Req conf", FALSE);
600 928 : case 403: HTTPD_ERR_MSG_RET(req, 403, "Req conf", FALSE);
601 64 : case 404: HTTPD_ERR_MSG_RET(req, 404, "Req conf", FALSE);
602 0 : case 406: HTTPD_ERR_MSG_RET(req, 406, "Req conf", FALSE);
603 352 : case 410: HTTPD_ERR_MSG_RET(req, 410, "Req conf", FALSE);
604 0 : case 500: HTTPD_ERR_MSG_RET(req, 500, "Req conf", FALSE);
605 0 : case 503: HTTPD_ERR_MSG_RET(req, 503, "Req conf", FALSE);
606 : }
607 : }
608 36160 : else if (OPT_SERV_SYM_EQ("Location:"))
609 : {
610 4864 : unsigned int lim = HTTPD_POLICY_PATH_LIM_NONE;
611 4864 : Vstr_ref *ref = NULL;
612 4864 : size_t orig_len = 0;
613 4864 : int bp_type = HTTPD_CONF_REQ__TYPE_BUILD_PATH_SKIP;
614 4864 : int canon = FALSE;
615 :
616 4864 : if (req->direct_filename)
617 0 : return (FALSE);
618 :
619 4864 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
620 4864 : if (!httpd__meta_build_path(con, req, conf, token,
621 : NULL, &canon, &lim, &ref))
622 : {
623 0 : vstr_ref_del(ref);
624 0 : return (FALSE);
625 : }
626 4864 : if (!req->direct_uri)
627 : {
628 2784 : if (lim == HTTPD_POLICY_PATH_LIM_NONE)
629 160 : orig_len = req->fname->len; /* don't do more than we need */
630 : else
631 : {
632 2624 : if (!vstr_sub_vstr(req->fname, 1, req->fname->len,
633 : con->evnt->io_r, req->path_pos, req->path_len, 0))
634 : {
635 0 : vstr_ref_del(ref);
636 0 : return (FALSE);
637 : }
638 2624 : req->vhost_prefix_len = 0;
639 : }
640 : }
641 4864 : if (!httpd__build_path(con, req, conf, token,
642 : req->fname, 1, req->fname->len,
643 : lim, FALSE, ref, TRUE, &bp_type))
644 0 : return (FALSE);
645 4864 : if (!req->direct_uri && (lim == HTTPD_POLICY_PATH_LIM_NONE) &&
646 : (bp_type != HTTPD_CONF_REQ__TYPE_BUILD_PATH_ASSIGN))
647 : { /* we needed to do the above sub */
648 0 : if (!vstr_sub_vstr(req->fname, 1, orig_len,
649 : con->evnt->io_r, req->path_pos, req->path_len, 0))
650 0 : return (FALSE);
651 : }
652 4864 : req->vhost_prefix_len = 0;
653 :
654 4864 : req->direct_uri = TRUE;
655 4864 : HTTP_REQ__X_HDR_CHK(req->fname, 1, req->fname->len);
656 :
657 4864 : if (canon)
658 1024 : httpd_req_absolute_uri(con, req, req->fname, 1, req->fname->len);
659 : }
660 31296 : else if (OPT_SERV_SYM_EQ("Cache-Control:"))
661 : {
662 0 : unsigned int num = 1;
663 0 : unsigned int tmp = 0;
664 0 : Conf_token save = *token;
665 0 : int ern = 0;
666 :
667 0 : if ((ern = conf_sc_token_parse_uint(conf, token, &tmp)))
668 : { /* reset, as though we didn't try */
669 0 : *token = save;
670 0 : HTTPD_CONF_REQ__X_CONTENT_VSTR(cache_control);
671 : }
672 0 : else if (!(num = tmp))
673 0 : return (FALSE);
674 : else
675 0 : HTTPD_CONF_REQ__X_CONTENT_SINGLE_VSTR(cache_control);
676 :
677 : if (0) { /* nothing */ }
678 0 : else if (HTTPD__EXPIRES_CMP(cache_control, "expire-minute"))
679 0 : httpd__conf_req_reset_cache_control(req, (num * 60 * 1));
680 0 : else if (HTTPD__EXPIRES_CMP(cache_control, "expire-hour"))
681 0 : httpd__conf_req_reset_cache_control(req, (num * 60 * 60));
682 0 : else if (HTTPD__EXPIRES_CMP(cache_control, "expire-day"))
683 0 : httpd__conf_req_reset_cache_control(req, (num * 60 * 60 * 24));
684 0 : else if (HTTPD__EXPIRES_CMP(cache_control, "expire-week"))
685 0 : httpd__conf_req_reset_cache_control(req, (num * 60 * 60 * 24 * 7));
686 0 : else if (!ern) /* must be one of the above symbols */
687 0 : return (FALSE);
688 0 : else if (vstr_cmp_cstr_eq(HTTP_REQ__CONT_PARAMS(req, cache_control),
689 : "<expires-now>"))
690 0 : httpd__conf_req_reset_cache_control(req, 0);
691 0 : else if (vstr_cmp_cstr_eq(HTTP_REQ__CONT_PARAMS(req, cache_control),
692 : "<expires-never>"))
693 0 : httpd__conf_req_reset_cache_control(req, (60 * 60 * 24 * 365));
694 : else
695 0 : HTTP_REQ__X_CONTENT_HDR_CHK(cache_control);
696 : }
697 31296 : else if (OPT_SERV_SYM_EQ("Content-Disposition:"))
698 : {
699 0 : HTTPD_CONF_REQ__X_CONTENT_VSTR(content_disposition);
700 0 : HTTP_REQ__X_CONTENT_HDR_CHK(content_disposition);
701 : }
702 31296 : else if (OPT_SERV_SYM_EQ("Content-Language:"))
703 : {
704 0 : HTTPD_CONF_REQ__X_CONTENT_VSTR(content_language);
705 0 : HTTP_REQ__X_CONTENT_HDR_CHK(content_language);
706 : }
707 31296 : else if (OPT_SERV_SYM_EQ("Content-Location:"))
708 : {
709 0 : unsigned int lim = HTTPD_POLICY_PATH_LIM_NONE;
710 0 : size_t pos = 0;
711 0 : size_t len = 0;
712 0 : Vstr_ref *ref = NULL;
713 :
714 0 : if (req->direct_uri || req->direct_filename)
715 0 : return (FALSE);
716 :
717 0 : if (!httpd__content_location_valid(req, &pos, &len))
718 0 : return (FALSE);
719 :
720 0 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
721 0 : if (!httpd__meta_build_path(con, req, conf, token, NULL, NULL, &lim, &ref))
722 : {
723 0 : vstr_ref_del(ref);
724 0 : return (FALSE);
725 : }
726 0 : if (!httpd__build_path(con, req, conf, token, req->xtra_content, pos, len,
727 : lim, FALSE, ref, TRUE, NULL))
728 0 : return (FALSE);
729 :
730 0 : len = vstr_sc_posdiff(pos, req->xtra_content->len);
731 :
732 0 : req->content_location_vs1 = req->xtra_content;
733 0 : req->content_location_pos = pos;
734 0 : req->content_location_len = len;
735 0 : HTTP_REQ__X_CONTENT_HDR_CHK(content_location);
736 : }
737 31872 : else if (OPT_SERV_SYM_EQ("Content-MD5:") ||
738 : OPT_SERV_SYM_EQ("identity/Content-MD5:"))
739 : {
740 1152 : req->content_md5_time = file_timestamp;
741 1152 : HTTPD_CONF_REQ__X_CONTENT_SINGLE_VSTR(content_md5);
742 1152 : HTTP_REQ__X_CONTENT_HDR_CHK(content_md5);
743 : }
744 30144 : else if (OPT_SERV_SYM_EQ("gzip/Content-MD5:"))
745 : {
746 1152 : req->content_md5_time = file_timestamp;
747 1152 : HTTPD_CONF_REQ__X_CONTENT_SINGLE_VSTR(gzip_content_md5);
748 1152 : HTTP_REQ__X_CONTENT_HDR_CHK(gzip_content_md5);
749 : }
750 28992 : else if (OPT_SERV_SYM_EQ("bzip2/Content-MD5:"))
751 : {
752 1152 : req->content_md5_time = file_timestamp;
753 1152 : HTTPD_CONF_REQ__X_CONTENT_SINGLE_VSTR(bzip2_content_md5);
754 1152 : HTTP_REQ__X_CONTENT_HDR_CHK(bzip2_content_md5);
755 : }
756 27840 : else if (OPT_SERV_SYM_EQ("Content-Type:"))
757 : {
758 3296 : HTTPD_CONF_REQ__X_CONTENT_VSTR(content_type);
759 3296 : HTTP_REQ__X_CONTENT_HDR_CHK(content_type);
760 : }
761 24544 : else if (OPT_SERV_SYM_EQ("ETag:"))
762 : {
763 1696 : req->etag_time = file_timestamp;
764 1696 : HTTPD_CONF_REQ__X_CONTENT_VSTR(etag);
765 1696 : HTTP_REQ__X_CONTENT_HDR_CHK(etag);
766 : }
767 22848 : else if (OPT_SERV_SYM_EQ("Expires:"))
768 : { /* note that rfc2616 says only go upto a year into the future */
769 0 : unsigned int num = 1;
770 0 : unsigned int tmp = 0;
771 0 : Conf_token save = *token;
772 0 : int ern = 0;
773 :
774 0 : if ((ern = conf_sc_token_parse_uint(conf, token, &tmp)))
775 : { /* reset, as though we didn't try */
776 0 : *token = save;
777 0 : HTTPD_CONF_REQ__X_CONTENT_VSTR(expires);
778 : }
779 0 : else if (!(num = tmp))
780 0 : return (FALSE);
781 : else
782 0 : HTTPD_CONF_REQ__X_CONTENT_SINGLE_VSTR(expires);
783 :
784 : /* if we dynamically generate use current timestamp, else filetimestamp */
785 0 : req->expires_time = req->now;
786 : if (0) { /* nothing */ }
787 0 : else if (HTTPD__EXPIRES_CMP(expires, "minute"))
788 0 : httpd__conf_req_reset_expires(req, (num * 60 * 1));
789 0 : else if (HTTPD__EXPIRES_CMP(expires, "hour"))
790 0 : httpd__conf_req_reset_expires(req, (num * 60 * 60));
791 0 : else if (HTTPD__EXPIRES_CMP(expires, "day"))
792 0 : httpd__conf_req_reset_expires(req, (num * 60 * 60 * 24));
793 0 : else if (HTTPD__EXPIRES_CMP(expires, "week"))
794 0 : httpd__conf_req_reset_expires(req, (num * 60 * 60 * 24 * 7));
795 0 : else if (!ern) /* must be one of the above symbols */
796 0 : return (FALSE);
797 0 : else if (vstr_cmp_cstr_eq(HTTP_REQ__CONT_PARAMS(req, expires), "<now>"))
798 0 : httpd__conf_req_reset_expires(req, 0);
799 0 : else if (vstr_cmp_cstr_eq(HTTP_REQ__CONT_PARAMS(req, expires), "<never>"))
800 0 : httpd__conf_req_reset_expires(req, (60 * 60 * 24 * 365));
801 : else
802 : {
803 0 : req->expires_time = file_timestamp;
804 0 : HTTP_REQ__X_CONTENT_HDR_CHK(expires);
805 : }
806 : }
807 22848 : else if (OPT_SERV_SYM_EQ("Link:")) /* rfc2068 -- old, but still honored */
808 : {
809 640 : HTTPD_CONF_REQ__X_CONTENT_VSTR(link);
810 640 : HTTP_REQ__X_CONTENT_HDR_CHK(link);
811 : }
812 22208 : else if (OPT_SERV_SYM_EQ("P3P:")) /* http://www.w3.org/TR/P3P/ */
813 : {
814 0 : HTTPD_CONF_REQ__X_CONTENT_VSTR(p3p);
815 0 : HTTP_REQ__X_CONTENT_HDR_CHK(p3p);
816 : }
817 22208 : else if (OPT_SERV_SYM_EQ("filename"))
818 : {
819 7104 : int full = req->skip_document_root;
820 7104 : unsigned int lim = HTTPD_POLICY_PATH_LIM_NAME_FULL;
821 7104 : Vstr_ref *ref = NULL;
822 :
823 7104 : if (req->direct_uri)
824 0 : return (FALSE);
825 7104 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
826 7104 : if (!httpd__meta_build_path(con, req, conf, token, &full, NULL, &lim, &ref))
827 : {
828 0 : vstr_ref_del(ref);
829 0 : return (FALSE);
830 : }
831 7104 : if (!httpd__build_path(con, req, conf, token,
832 : req->fname, 1, req->fname->len,
833 : lim, full, ref, FALSE, NULL))
834 0 : return (FALSE);
835 7104 : if (!req->skip_document_root &&
836 : !(req->conf_flags & HTTPD_CONF_REQ_FLAGS_PARSE_FILE_DIRECT) &&
837 : (!req->fname->len || !vstr_cmp_cstr_eq(req->fname, 1, 1, "/")))
838 32 : vstr_add_cstr_ptr(req->fname, 0, "/");
839 7104 : req->direct_filename = TRUE;
840 : }
841 15104 : else if (OPT_SERV_SYM_EQ("parse-accept"))
842 0 : OPT_SERV_X_TOGGLE(req->parse_accept);
843 15104 : else if (OPT_SERV_SYM_EQ("parse-accept-language"))
844 0 : OPT_SERV_X_TOGGLE(req->parse_accept_language);
845 15232 : else if (OPT_SERV_SYM_EQ("allow-accept-encoding") ||
846 : OPT_SERV_SYM_EQ("parse-accept-encoding"))
847 128 : OPT_SERV_X_TOGGLE(req->allow_accept_encoding);
848 14976 : else if (OPT_SERV_SYM_EQ("Vary:_*"))
849 0 : OPT_SERV_X_TOGGLE(req->vary_star);
850 14976 : else if (OPT_SERV_SYM_EQ("Vary:_Accept"))
851 96 : OPT_SERV_X_TOGGLE(req->vary_a);
852 14880 : else if (OPT_SERV_SYM_EQ("Vary:_Accept-Charset"))
853 96 : OPT_SERV_X_TOGGLE(req->vary_ac);
854 14784 : else if (OPT_SERV_SYM_EQ("Vary:_Accept-Encoding")) /* doesn't help */
855 96 : OPT_SERV_X_TOGGLE(req->vary_ae);
856 14688 : else if (OPT_SERV_SYM_EQ("Vary:_Accept-Language"))
857 96 : OPT_SERV_X_TOGGLE(req->vary_al);
858 14688 : else if (OPT_SERV_SYM_EQ("Vary:_Referer") ||
859 : OPT_SERV_SYM_EQ("Vary:_Referrer"))
860 96 : OPT_SERV_X_TOGGLE(req->vary_rf);
861 14496 : else if (OPT_SERV_SYM_EQ("Vary:_User-Agent"))
862 96 : OPT_SERV_X_TOGGLE(req->vary_ua);
863 14400 : else if (OPT_SERV_SYM_EQ("Vary:_If-Modified-Since"))
864 96 : OPT_SERV_X_TOGGLE(req->vary_ims);
865 14304 : else if (OPT_SERV_SYM_EQ("Vary:_If-Unmodified-Since"))
866 96 : OPT_SERV_X_TOGGLE(req->vary_ius);
867 14208 : else if (OPT_SERV_SYM_EQ("Vary:_If-Range"))
868 96 : OPT_SERV_X_TOGGLE(req->vary_ir);
869 14112 : else if (OPT_SERV_SYM_EQ("Vary:_If-Match"))
870 96 : OPT_SERV_X_TOGGLE(req->vary_im);
871 14016 : else if (OPT_SERV_SYM_EQ("Vary:_If-None-Match"))
872 96 : OPT_SERV_X_TOGGLE(req->vary_inm);
873 15520 : else if (OPT_SERV_SYM_EQ("content-lang-ext") ||
874 : OPT_SERV_SYM_EQ("content-language-ext") ||
875 : OPT_SERV_SYM_EQ("content-language-extension"))
876 3200 : HTTPD_CONF_REQ__X_CONTENT_VSTR(ext_vary_al);
877 12320 : else if (OPT_SERV_SYM_EQ("content-type-ext") ||
878 : OPT_SERV_SYM_EQ("content-type-extension"))
879 3200 : HTTPD_CONF_REQ__X_CONTENT_VSTR(ext_vary_a);
880 9360 : else if (OPT_SERV_SYM_EQ("content-type-neg") ||
881 : OPT_SERV_SYM_EQ("content-type-negotiate") ||
882 : OPT_SERV_SYM_EQ("negotiate-content-type"))
883 : {
884 3680 : if (req->neg_content_type_done)
885 0 : return (FALSE);
886 14720 : HTTPD__NEG_BEG(req->policy->max_neg_A_nodes);
887 7360 : qual = http_parse_accept(req, conf->data, val->pos, val->len);
888 11040 : HTTPD__NEG_END();
889 :
890 3680 : req->neg_content_type_done = TRUE;
891 3680 : req->vary_a = TRUE;
892 3680 : if (qual_num)
893 : {
894 2848 : unsigned int last = token->num;
895 :
896 2848 : req->parse_accept = FALSE;
897 2848 : *token = save;
898 2848 : conf_parse_num_token(conf, token, qual_num);
899 2848 : HTTPD_CONF_REQ__X_CONTENT_SINGLE_VSTR(content_type);
900 2848 : HTTP_REQ__X_CONTENT_HDR_CHK(content_type);
901 2848 : HTTPD_CONF_REQ__X_CONTENT_SINGLE_VSTR(ext_vary_a);
902 2848 : conf_parse_num_token(conf, token, last);
903 : }
904 : }
905 : /* else if (OPT_SERV_SYM_EQ("negotiate-charset"))
906 : return (FALSE); */
907 5760 : else if (OPT_SERV_SYM_EQ("content-lang-neg") ||
908 : OPT_SERV_SYM_EQ("content-lang-negotiate") ||
909 : OPT_SERV_SYM_EQ("content-language-negotiate") ||
910 : OPT_SERV_SYM_EQ("negotiate-content-language"))
911 : {
912 3840 : if (req->neg_content_lang_done)
913 0 : return (FALSE);
914 29440 : HTTPD__NEG_BEG(req->policy->max_neg_AL_nodes);
915 21760 : qual = http_parse_accept_language(req, conf->data, val->pos, val->len);
916 25600 : HTTPD__NEG_END();
917 :
918 3840 : req->neg_content_lang_done = TRUE;
919 3840 : req->vary_al = TRUE;
920 3840 : if (qual_num)
921 : {
922 3680 : unsigned int last = token->num;
923 :
924 3680 : req->parse_accept_language = FALSE;
925 3680 : *token = save;
926 3680 : conf_parse_num_token(conf, token, qual_num);
927 3680 : HTTPD_CONF_REQ__X_CONTENT_SINGLE_VSTR(content_language);
928 3680 : HTTP_REQ__X_CONTENT_HDR_CHK(content_language);
929 3680 : HTTPD_CONF_REQ__X_CONTENT_SINGLE_VSTR(ext_vary_al);
930 3680 : conf_parse_num_token(conf, token, last);
931 : }
932 : }
933 : else
934 0 : return (FALSE);
935 :
936 36768 : return (TRUE);
937 : }
938 : #undef HTTPD__CONF_REDIR
939 : #undef HTTPD__EXPIRES_CMP
940 : #undef HTTPD__NEG_BEG
941 : #undef HTTPD__NEG_END
942 :
943 : int httpd_conf_req_d0(struct Con *con, Httpd_req_data *req,
944 : time_t timestamp,
945 : Conf_parse *conf, Conf_token *token)
946 13216 : {
947 13216 : unsigned int cur_depth = token->depth_num;
948 :
949 13216 : if (!OPT_SERV_SYM_EQ("org.and.httpd-conf-req-1.0") &&
950 : !OPT_SERV_SYM_EQ("org.and.jhttpd-conf-req-1.0"))
951 0 : return (FALSE);
952 :
953 56208 : while (conf_token_list_num(token, cur_depth))
954 : {
955 40512 : int clist = FALSE;
956 :
957 40512 : CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, cur_depth, FALSE);
958 40512 : CONF_SC_TOGGLE_CLIST_VAR(clist);
959 :
960 40512 : if (!httpd__conf_req_d1(con, req, timestamp, conf, token, clist))
961 4128 : return (FALSE);
962 : }
963 :
964 9088 : if (req->content_location_vs1)
965 : { /* absolute URI content-location header */
966 0 : size_t pos = 0;
967 0 : size_t len = 0;
968 :
969 0 : if (!httpd__content_location_valid(req, &pos, &len))
970 0 : return (FALSE);
971 :
972 0 : httpd_req_absolute_uri(con, req, req->xtra_content, pos, len);
973 0 : req->content_location_len = vstr_sc_posdiff(pos, req->xtra_content->len);
974 : }
975 :
976 9088 : return (TRUE);
977 : }
978 :
979 : int httpd_conf_req_parse_file(Conf_parse *conf,
980 : struct Con *con, Httpd_req_data *req,
981 : size_t del_len)
982 38777 : {
983 38777 : Conf_token token[1] = {CONF_TOKEN_INIT};
984 38777 : Vstr_base *fname = req->fname;
985 38777 : Vstr_base *s1 = NULL;
986 38777 : const char *fname_cstr = NULL;
987 38777 : int fd = -1;
988 : struct stat64 cf_stat[1];
989 38777 : int open_flags = O_NONBLOCK;
990 :
991 19396 : ASSERT(conf && con && req && fname && (del_len < fname->len));
992 :
993 38777 : s1 = conf->tmp;
994 :
995 38777 : if (req->conf_flags & HTTPD_CONF_REQ_FLAGS_PARSE_FILE_DIRECT)
996 10904 : HTTPD_APP_REF_VSTR(s1, fname, 1, fname->len - del_len);
997 : else
998 : {
999 27873 : Vstr_base *dir = req->policy->req_conf_dir;
1000 :
1001 13944 : ASSERT(dir);
1002 :
1003 27873 : if (!dir->len ||
1004 : !req->policy->use_req_conf || req->skip_document_root)
1005 6577 : return (TRUE);
1006 :
1007 21296 : HTTPD_APP_REF_ALLVSTR(s1, dir);
1008 10648 : ASSERT((dir->len >= 1) && vstr_cmp_cstr_eq(dir, dir->len, 1, "/"));
1009 10648 : ASSERT((fname->len >= 1) && vstr_cmp_cstr_eq(fname, 1, 1, "/"));
1010 21296 : HTTPD_APP_REF_VSTR(s1, fname, 2, fname->len - (1 + del_len));
1011 : }
1012 :
1013 32200 : if (s1->conf->malloc_bad ||
1014 : !(fname_cstr = vstr_export_cstr_ptr(s1, 1, s1->len)))
1015 : goto read_fail;
1016 :
1017 32200 : if (req->policy->use_noatime)
1018 0 : open_flags |= O_NOATIME;
1019 :
1020 32200 : fd = io__open(fname_cstr, open_flags);
1021 32200 : if ((fd == -1) && (errno == EISDIR))
1022 0 : goto fin_dir;
1023 :
1024 32200 : if ((fd == -1) &&
1025 : ((errno == ENOTDIR) || /* part of path was not a dir */
1026 : (errno == ENAMETOOLONG)))
1027 0 : goto fin_file; /* ignore these errors, not local users fault */
1028 :
1029 32200 : if ((fd == -1) && (errno == ENOENT))
1030 27208 : goto fin_ok; /* ignore these errors, not local users fault */
1031 :
1032 4992 : if (fd == -1)
1033 0 : goto read_fail; /* this is "bad" */
1034 :
1035 4992 : if (fstat64(fd, cf_stat) == -1)
1036 0 : goto close_read_fail; /* this is "bad" */
1037 :
1038 4992 : if (S_ISDIR(cf_stat->st_mode))
1039 32 : goto fin_close_dir; /* ignore */
1040 :
1041 4960 : if (!S_ISREG(cf_stat->st_mode))
1042 0 : goto close_read_fail; /* this is "bad" */
1043 :
1044 4960 : if ((cf_stat->st_size < strlen("org.and.httpd-conf-req-1.0")) ||
1045 : (cf_stat->st_size > req->policy->max_req_conf_sz))
1046 : goto close_read_fail; /* this is "bad" */
1047 :
1048 4960 : s1 = conf->data;
1049 4960 : vstr_del(conf->tmp, 1, conf->tmp->len); /* filename */
1050 :
1051 14880 : while (cf_stat->st_size > s1->len)
1052 : {
1053 4960 : size_t len = cf_stat->st_size - s1->len;
1054 :
1055 4960 : if (!vstr_sc_read_len_fd(s1, s1->len, fd, len, NULL) ||
1056 : (len == (cf_stat->st_size - s1->len)))
1057 : goto close_read_fail;
1058 : }
1059 :
1060 4960 : close(fd);
1061 :
1062 4960 : if (!conf_parse_lex(conf, 1, conf->data->len))
1063 0 : goto conf_fail;
1064 :
1065 12176 : while (conf_parse_token(conf, token))
1066 : {
1067 4960 : if ((token->type != CONF_TOKEN_TYPE_CLIST) || (token->depth_num != 1))
1068 : goto conf_fail;
1069 :
1070 4960 : if (!conf_parse_token(conf, token))
1071 0 : goto conf_fail;
1072 :
1073 4960 : if (!conf_token_cmp_sym_cstr_eq(conf, token,
1074 : "org.and.httpd-conf-req-1.0") &&
1075 : !conf_token_cmp_sym_cstr_eq(conf, token,
1076 : "org.and.jhttpd-conf-req-1.0"))
1077 0 : goto conf_fail;
1078 :
1079 4960 : if (!httpd_conf_req_d0(con, req, cf_stat->st_mtime, conf, token))
1080 224 : goto conf_fail;
1081 : }
1082 :
1083 : /* And they all live together ... dum dum */
1084 4736 : if (conf->data->conf->malloc_bad)
1085 0 : goto read_fail;
1086 :
1087 4736 : return (TRUE);
1088 :
1089 32 : fin_close_dir:
1090 32 : close(fd);
1091 32 : fin_dir:
1092 32 : req->conf_friendly_file = TRUE;
1093 32 : if (req->policy->use_secure_dirs &&
1094 : !(req->conf_flags & HTTPD_CONF_REQ_FLAGS_PARSE_FILE_NONMAIN))
1095 : { /* check if conf file exists inside the directory given,
1096 : * so we can re-direct without leaking info. */
1097 : struct stat64 d_stat[1];
1098 :
1099 32 : vstr_add_cstr_buf(s1, s1->len, "/");
1100 32 : HTTPD_APP_REF_ALLVSTR(s1, req->policy->dir_filename);
1101 :
1102 32 : fname_cstr = vstr_export_cstr_ptr(s1, 1, s1->len);
1103 32 : if (s1->conf->malloc_bad)
1104 0 : goto read_fail;
1105 32 : if ((stat64(fname_cstr, d_stat) != -1) && S_ISREG(d_stat->st_mode))
1106 32 : req->conf_secure_dirs = TRUE;
1107 : }
1108 :
1109 16 : ASSERT(s1 == conf->tmp);
1110 32 : vstr_del(s1, 1, s1->len);
1111 32 : return (TRUE);
1112 :
1113 0 : fin_file:
1114 0 : if (req->policy->use_friendly_dirs &&
1115 : !(req->conf_flags & HTTPD_CONF_REQ_FLAGS_PARSE_FILE_NONMAIN))
1116 : { /* check if conf file exists as a file, so we can re-direct backwards */
1117 : struct stat64 d_stat[1];
1118 0 : size_t len = vstr_cspn_cstr_chrs_rev(s1, 1, s1->len, "/") + 1;
1119 :
1120 0 : if ((len > 1) && (len < (s1->len - req->vhost_prefix_len)))
1121 : { /* must be a filename, can't be toplevel */
1122 0 : vstr_sc_reduce(s1, 1, s1->len, len);
1123 :
1124 0 : fname_cstr = vstr_export_cstr_ptr(s1, 1, s1->len);
1125 0 : if (s1->conf->malloc_bad)
1126 0 : goto read_fail;
1127 0 : if ((stat64(fname_cstr, d_stat) != -1) && S_ISREG(d_stat->st_mode))
1128 0 : req->conf_friendly_dirs = TRUE;
1129 : }
1130 : }
1131 :
1132 27208 : fin_ok:
1133 13604 : ASSERT(s1 == conf->tmp);
1134 27208 : vstr_del(s1, 1, s1->len);
1135 27208 : return (TRUE);
1136 :
1137 0 : close_read_fail:
1138 0 : vstr_del(conf->data, 1, conf->data->len);
1139 0 : vstr_del(conf->tmp, 1, conf->tmp->len);
1140 0 : close(fd);
1141 0 : goto read_fail;
1142 :
1143 224 : conf_fail:
1144 224 : vstr_del(conf->tmp, 1, conf->tmp->len);
1145 224 : if (!req->user_return_error_code &&
1146 : !(req->conf_flags & HTTPD_CONF_REQ_FLAGS_PARSE_FILE_NONMAIN))
1147 0 : conf_parse_backtrace(conf->tmp, "<conf-request>", conf, token);
1148 224 : read_fail:
1149 224 : if (!req->user_return_error_code)
1150 0 : HTTPD_ERR_MSG(req, 503, "Req conf parse error");
1151 224 : conf->data->conf->malloc_bad = FALSE;
1152 224 : return (FALSE);
1153 : }
|