1 #ifndef HTTPD_POLICY_H
2 #define HTTPD_POLICY_H
3 
4 #include "opt_policy.h"
5 
6 #define HTTPD_POLICY__PATH_LIM_FULL 0
7 #define HTTPD_POLICY__PATH_LIM_BEG  1
8 #define HTTPD_POLICY__PATH_LIM_END  2
9 #define HTTPD_POLICY__PATH_LIM_EQ   3
10 #define HTTPD_POLICY__PATH_LIM_MASK 3
11 #define HTTPD_POLICY_PATH_LIM_NONE       0
12 #define HTTPD_POLICY_PATH_LIM_PATH_FULL (0x4  | HTTPD_POLICY__PATH_LIM_FULL)
13 #define HTTPD_POLICY_PATH_LIM_PATH_BEG  (0x4  | HTTPD_POLICY__PATH_LIM_BEG)
14 #define HTTPD_POLICY_PATH_LIM_PATH_END  (0x4  | HTTPD_POLICY__PATH_LIM_END)
15 #define HTTPD_POLICY_PATH_LIM_PATH_EQ   (0x4  | HTTPD_POLICY__PATH_LIM_EQ)
16 #define HTTPD_POLICY_PATH_LIM_NAME_FULL (0x8  | HTTPD_POLICY__PATH_LIM_FULL)
17 #define HTTPD_POLICY_PATH_LIM_NAME_BEG  (0x8  | HTTPD_POLICY__PATH_LIM_BEG)
18 #define HTTPD_POLICY_PATH_LIM_NAME_END  (0x8  | HTTPD_POLICY__PATH_LIM_END)
19 #define HTTPD_POLICY_PATH_LIM_NAME_EQ   (0x8  | HTTPD_POLICY__PATH_LIM_EQ)
20 #define HTTPD_POLICY_PATH_LIM_EXTN_FULL (0xc  | HTTPD_POLICY__PATH_LIM_FULL)
21 #define HTTPD_POLICY_PATH_LIM_EXTN_BEG  (0xc  | HTTPD_POLICY__PATH_LIM_BEG)
22 #define HTTPD_POLICY_PATH_LIM_EXTN_END  (0xc  | HTTPD_POLICY__PATH_LIM_END)
23 #define HTTPD_POLICY_PATH_LIM_EXTN_EQ   (0xc  | HTTPD_POLICY__PATH_LIM_EQ)
24 #define HTTPD_POLICY_PATH_LIM_EXTS_FULL (0x14 | HTTPD_POLICY__PATH_LIM_FULL)
25 #define HTTPD_POLICY_PATH_LIM_EXTS_BEG  (0x14 | HTTPD_POLICY__PATH_LIM_BEG)
26 #define HTTPD_POLICY_PATH_LIM_EXTS_END  (0x14 | HTTPD_POLICY__PATH_LIM_END)
27 #define HTTPD_POLICY_PATH_LIM_EXTS_EQ   (0x14 | HTTPD_POLICY__PATH_LIM_EQ)
28 #define HTTPD_POLICY_PATH_LIM_BWEN_FULL (0x18 | HTTPD_POLICY__PATH_LIM_FULL)
29 #define HTTPD_POLICY_PATH_LIM_BWEN_BEG  (0x18 | HTTPD_POLICY__PATH_LIM_BEG)
30 #define HTTPD_POLICY_PATH_LIM_BWEN_END  (0x18 | HTTPD_POLICY__PATH_LIM_END)
31 #define HTTPD_POLICY_PATH_LIM_BWEN_EQ   (0x18 | HTTPD_POLICY__PATH_LIM_EQ)
32 #define HTTPD_POLICY_PATH_LIM_BWES_FULL (0x1c | HTTPD_POLICY__PATH_LIM_FULL)
33 #define HTTPD_POLICY_PATH_LIM_BWES_BEG  (0x1c | HTTPD_POLICY__PATH_LIM_BEG)
34 #define HTTPD_POLICY_PATH_LIM_BWES_END  (0x1c | HTTPD_POLICY__PATH_LIM_END)
35 #define HTTPD_POLICY_PATH_LIM_BWES_EQ   (0x1c | HTTPD_POLICY__PATH_LIM_EQ)
36 
37 /* choosing (1024) as a offset ... kinda hackyish */
38 #define HTTPD_POLICY_REQ_PATH_BEG (1024 +  0)
39 #define HTTPD_POLICY_REQ_PATH_END (1024 +  1)
40 #define HTTPD_POLICY_REQ_PATH_EQ  (1024 +  2)
41 #define HTTPD_POLICY_REQ_NAME_BEG (1024 +  3)
42 #define HTTPD_POLICY_REQ_NAME_END (1024 +  4)
43 #define HTTPD_POLICY_REQ_NAME_EQ  (1024 +  5)
44 #define HTTPD_POLICY_REQ_BWEN_BEG (1024 +  6)
45 #define HTTPD_POLICY_REQ_BWEN_END (1024 +  7)
46 #define HTTPD_POLICY_REQ_BWEN_EQ  (1024 +  8)
47 #define HTTPD_POLICY_REQ_BWES_BEG (1024 +  9)
48 #define HTTPD_POLICY_REQ_BWES_END (1024 + 10)
49 #define HTTPD_POLICY_REQ_BWES_EQ  (1024 + 11)
50 #define HTTPD_POLICY_REQ_EXTN_BEG (1024 + 12)
51 #define HTTPD_POLICY_REQ_EXTN_END (1024 + 13)
52 #define HTTPD_POLICY_REQ_EXTN_EQ  (1024 + 14)
53 #define HTTPD_POLICY_REQ_EXTS_BEG (1024 + 15)
54 #define HTTPD_POLICY_REQ_EXTS_END (1024 + 16)
55 #define HTTPD_POLICY_REQ_EXTS_EQ  (1024 + 17)
56 
57 typedef struct Httpd_policy_path
58 {
59  Vstr_base *s1;
60  void (*ref_func)(Vstr_ref *);
61 } Httpd_policy_path;
62 
63 extern void httpd_policy_change_con(struct Con *, const Httpd_policy_opts *);
64 extern void httpd_policy_change_req(Httpd_req_data *,
65                                     const Httpd_policy_opts *);
66 
67 extern int httpd_policy_build_path(struct Con *, Httpd_req_data *,
68                                    const Conf_parse *, Conf_token *,
69                                    int *, int *);
70 extern int httpd_policy_path_make(struct Con *con, Httpd_req_data *req,
71                                   Conf_parse *, Conf_token *, unsigned int,
72                                   Vstr_ref **);
73 
74 extern int httpd_policy_path_eq(const Vstr_base *,
75                                 const Vstr_base *, size_t *, size_t *);
76 extern int httpd_policy_path_beg_eq(const Vstr_base *,
77                                     const Vstr_base *, size_t *, size_t *);
78 extern int httpd_policy_path_end_eq(const Vstr_base *,
79                                     const Vstr_base *, size_t *, size_t *);
80 
81 extern void httpd_policy_path_mod_name(const Vstr_base *, size_t *, size_t *);
82 extern void httpd_policy_path_mod_dirn(const Vstr_base *, size_t *, size_t *);
83 extern void httpd_policy_path_mod_extn(const Vstr_base *, size_t *, size_t *);
84 extern void httpd_policy_path_mod_exts(const Vstr_base *, size_t *, size_t *);
85 extern void httpd_policy_path_mod_bwen(const Vstr_base *, size_t *, size_t *);
86 extern void httpd_policy_path_mod_bwes(const Vstr_base *, size_t *, size_t *);
87 
88 extern int  httpd_policy_path_lim_eq(const Vstr_base *, size_t *, size_t *,
89                                      unsigned int, size_t, Vstr_ref *);
90 
91 extern int httpd_policy_uri_eq(const Vstr_base *,
92                                const Vstr_base *, size_t *, size_t *);
93 extern int httpd_policy_uri_beg_eq(const Vstr_base *,
94                                    const Vstr_base *, size_t *, size_t *);
95 extern int httpd_policy_uri_end_eq(const Vstr_base *,
96                                    const Vstr_base *, size_t *, size_t *);
97 
98 extern void httpd_policy_uri_mod_name(const Vstr_base *, size_t *, size_t *);
99 extern void httpd_policy_uri_mod_dirn(const Vstr_base *, size_t *, size_t *);
100 extern void httpd_policy_uri_mod_extn(const Vstr_base *, size_t *, size_t *);
101 extern void httpd_policy_uri_mod_exts(const Vstr_base *, size_t *, size_t *);
102 extern void httpd_policy_uri_mod_bwen(const Vstr_base *, size_t *, size_t *);
103 extern void httpd_policy_uri_mod_bwes(const Vstr_base *, size_t *, size_t *);
104 
105 extern int  httpd_policy_uri_lim_eq(const Vstr_base *, size_t *, size_t *,
106                                     unsigned int, int, Vstr_ref *);
107 
108 extern int httpd_policy_path_req2lim(unsigned int);
109 
110 extern int httpd_policy_ipv4_make(struct Con *, Httpd_req_data *,
111                                   Conf_parse *, Conf_token *,
112                                   unsigned int, struct sockaddr *, int *);
113 extern int httpd_policy_ipv4_cidr_eq(struct Con *, Httpd_req_data *,
114                                      Opt_policy_ipv4 *, struct sockaddr *);
115 
116 extern void httpd_policy_exit(Httpd_policy_opts *);
117 extern int httpd_policy_init(Httpd_opts *, Httpd_policy_opts *);
118 extern Opt_serv_policy_opts *httpd_policy_make(Opt_serv_opts *);
119 extern int httpd_policy_copy(Opt_serv_policy_opts *,
120                              const Opt_serv_policy_opts *);
121 
122 #if !defined(HTTPD_POLICY_COMPILE_INLINE)
123 # ifdef VSTR_AUTOCONF_NDEBUG
124 #  define HTTPD_POLICY_COMPILE_INLINE 1
125 # else
126 #  define HTTPD_POLICY_COMPILE_INLINE 0
127 # endif
128 #endif
129 
130 #if defined(VSTR_AUTOCONF_HAVE_INLINE) && HTTPD_POLICY_COMPILE_INLINE
131 
132 #ifndef VSTR_AUTOCONF_NDEBUG
133 # define HTTPD_POLICY__ASSERT ASSERT
134 #else
135 # define HTTPD_POLICY__ASSERT(x)
136 #endif
137 
138 #define HTTPD_POLICY__TRUE  1
139 #define HTTPD_POLICY__FALSE 0
140 
httpd_policy_change_con(struct Con * con,const Httpd_policy_opts * policy)141 extern inline void httpd_policy_change_con(struct Con *con,
142                                            const Httpd_policy_opts *policy)
143 {
144   con->use_sendfile      = policy->use_sendfile;
145   con->use_posix_fadvise = policy->use_posix_fadvise;
146   con->policy            = policy;
147 }
148 
httpd_policy_change_req(Httpd_req_data * req,const Httpd_policy_opts * policy)149 extern inline void httpd_policy_change_req(Httpd_req_data *req,
150                                            const Httpd_policy_opts *policy)
151 {
152   req->parse_accept          = policy->use_err_406;
153   req->parse_accept_language = policy->use_err_406;
154   req->allow_accept_encoding = policy->use_enc_content_replacement;
155   if (req->vhost_prefix_len && !policy->use_vhosts_name)
156   { /* NOTE: doesn't do chk_host properly */
157     vstr_del(req->fname, 1, req->vhost_prefix_len);
158     req->vhost_prefix_len = 0;
159   }
160   if (!req->chked_encoded_path)
161   {
162     req->chk_encoded_slash   = policy->chk_encoded_slash;
163     req->chk_encoded_dot     = policy->chk_encoded_dot;
164   }
165   req->policy                = policy;
166 }
167 
httpd_policy_path_eq(const Vstr_base * s1,const Vstr_base * s2,size_t * p2,size_t * l2)168 extern inline int httpd_policy_path_eq(const Vstr_base *s1,
169                                        const Vstr_base *s2,
170                                        size_t *p2, size_t *l2)
171 {
172   return (vstr_cmp_eq(s1, 1, s1->len, s2, *p2, *l2));
173 }
174 
175 /* if the s1 is equal to the begining of s2 */
httpd_policy_path_beg_eq(const Vstr_base * s1,const Vstr_base * s2,size_t * p2,size_t * l2)176 extern inline int httpd_policy_path_beg_eq(const Vstr_base *s1,
177                                            const Vstr_base *s2,
178                                            size_t *p2, size_t *l2)
179 {
180   if (*l2 > s1->len)
181     *l2 = s1->len;
182   return (vstr_cmp_eq(s1, 1, s1->len, s2, *p2, *l2));
183 }
184 
185 /* if the s1 is equal to the end of s2 */
httpd_policy_path_end_eq(const Vstr_base * s1,const Vstr_base * s2,size_t * p2,size_t * l2)186 extern inline int httpd_policy_path_end_eq(const Vstr_base *s1,
187                                            const Vstr_base *s2,
188                                            size_t *p2, size_t *l2)
189 {
190   if (*l2 > s1->len)
191   {
192     *p2 += (*l2 - s1->len);
193     *l2 = s1->len;
194   }
195   return (vstr_cmp_eq(s1, 1, s1->len, s2, *p2, *l2));
196 }
197 
httpd_policy_path_mod_name(const Vstr_base * s1,size_t * pos,size_t * len)198 extern inline void httpd_policy_path_mod_name(const Vstr_base *s1,
199                                               size_t *pos, size_t *len)
200 {
201   size_t srch = vstr_srch_chr_rev(s1, *pos, *len, '/');
202   HTTPD_POLICY__ASSERT(srch);
203 
204   *len -= vstr_sc_posdiff(*pos, srch);
205   *pos += vstr_sc_posdiff(*pos, srch);
206 }
207 
httpd_policy_path_mod_dirn(const Vstr_base * s1,size_t * pos,size_t * len)208 extern inline void httpd_policy_path_mod_dirn(const Vstr_base *s1,
209                                               size_t *pos, size_t *len)
210 {
211   size_t srch = vstr_srch_chr_rev(s1, *pos, *len, '/');
212   HTTPD_POLICY__ASSERT(srch);
213 
214   *len = vstr_sc_posdiff(*pos, srch);
215 }
216 
httpd_policy_path_mod_extn(const Vstr_base * s1,size_t * pos,size_t * len)217 extern inline void httpd_policy_path_mod_extn(const Vstr_base *s1,
218                                               size_t *pos, size_t *len)
219 {
220   size_t srch = 0;
221 
222   httpd_policy_path_mod_name(s1, pos, len);
223 
224   if ((srch = vstr_srch_chr_rev(s1, *pos, *len, '.')))
225   { /* include '.' */
226     *len -= srch - *pos;
227     *pos = srch;
228   }
229   else
230   { /* at point just after basename */
231     *pos = vstr_sc_poslast(*pos, *len);
232     *len = 0;
233   }
234 }
235 
httpd_policy_path_mod_exts(const Vstr_base * s1,size_t * pos,size_t * len)236 extern inline void httpd_policy_path_mod_exts(const Vstr_base *s1,
237                                               size_t *pos, size_t *len)
238 {
239   size_t srch = 0;
240 
241   httpd_policy_path_mod_name(s1, pos, len);
242 
243   if ((srch = vstr_srch_chr_fwd(s1, *pos, *len, '.')))
244   { /* include '.' */
245     *len -= srch - *pos;
246     *pos = srch;
247   }
248   else
249   { /* at point just after basename */
250     *pos = vstr_sc_poslast(*pos, *len);
251     *len = 0;
252   }
253 }
254 
httpd_policy_path_mod_bwen(const Vstr_base * s1,size_t * pos,size_t * len)255 extern inline void httpd_policy_path_mod_bwen(const Vstr_base *s1,
256                                               size_t *pos, size_t *len)
257 {
258   size_t srch = 0;
259 
260   httpd_policy_path_mod_name(s1, pos, len);
261 
262   if ((srch = vstr_srch_chr_rev(s1, *pos, *len, '.')))
263     *len = vstr_sc_posdiff(*pos, srch) - 1; /* don't include '.' */
264 }
265 
httpd_policy_path_mod_bwes(const Vstr_base * s1,size_t * pos,size_t * len)266 extern inline void httpd_policy_path_mod_bwes(const Vstr_base *s1,
267                                               size_t *pos, size_t *len)
268 {
269   size_t srch = 0;
270 
271   httpd_policy_path_mod_name(s1, pos, len);
272 
273   if ((srch = vstr_srch_chr_fwd(s1, *pos, *len, '.')))
274     *len = vstr_sc_posdiff(*pos, srch) - 1; /* don't include '.' */
275 }
276 
httpd_policy_path_lim_eq(const Vstr_base * s1,size_t * pos,size_t * len,unsigned int lim,size_t vhost_prefix_len,Vstr_ref * ref)277 extern inline int httpd_policy_path_lim_eq(const Vstr_base *s1,
278                                            size_t *pos, size_t *len,
279                                            unsigned int lim,
280                                            size_t vhost_prefix_len,
281                                            Vstr_ref *ref)
282 {
283   const Httpd_policy_path *srch = NULL;
284 
285   if (lim == HTTPD_POLICY_PATH_LIM_NONE)
286     return (HTTPD_POLICY__TRUE);
287 
288   *len -= vhost_prefix_len;
289   *pos += vhost_prefix_len;
290 
291   switch (lim)
292   {
293     default: HTTPD_POLICY__ASSERT(HTTPD_POLICY__FALSE);
294 
295     case HTTPD_POLICY_PATH_LIM_PATH_FULL:
296     case HTTPD_POLICY_PATH_LIM_PATH_BEG:
297     case HTTPD_POLICY_PATH_LIM_PATH_END:
298     case HTTPD_POLICY_PATH_LIM_PATH_EQ:
299       break;
300 
301     case HTTPD_POLICY_PATH_LIM_NAME_FULL:
302     case HTTPD_POLICY_PATH_LIM_NAME_BEG:
303     case HTTPD_POLICY_PATH_LIM_NAME_END:
304     case HTTPD_POLICY_PATH_LIM_NAME_EQ:
305       httpd_policy_path_mod_name(s1, pos, len);
306       break;
307 
308     case HTTPD_POLICY_PATH_LIM_EXTN_FULL:
309     case HTTPD_POLICY_PATH_LIM_EXTN_BEG:
310     case HTTPD_POLICY_PATH_LIM_EXTN_END:
311     case HTTPD_POLICY_PATH_LIM_EXTN_EQ:
312       httpd_policy_path_mod_extn(s1, pos, len);
313       break;
314 
315     case HTTPD_POLICY_PATH_LIM_EXTS_FULL:
316     case HTTPD_POLICY_PATH_LIM_EXTS_BEG:
317     case HTTPD_POLICY_PATH_LIM_EXTS_END:
318     case HTTPD_POLICY_PATH_LIM_EXTS_EQ:
319       httpd_policy_path_mod_exts(s1, pos, len);
320       break;
321 
322     case HTTPD_POLICY_PATH_LIM_BWEN_FULL:
323     case HTTPD_POLICY_PATH_LIM_BWEN_BEG:
324     case HTTPD_POLICY_PATH_LIM_BWEN_END:
325     case HTTPD_POLICY_PATH_LIM_BWEN_EQ:
326       httpd_policy_path_mod_bwen(s1, pos, len);
327       break;
328 
329     case HTTPD_POLICY_PATH_LIM_BWES_FULL:
330     case HTTPD_POLICY_PATH_LIM_BWES_BEG:
331     case HTTPD_POLICY_PATH_LIM_BWES_END:
332     case HTTPD_POLICY_PATH_LIM_BWES_EQ:
333       httpd_policy_path_mod_bwes(s1, pos, len);
334       break;
335   }
336 
337   if ((lim & HTTPD_POLICY__PATH_LIM_MASK) == HTTPD_POLICY__PATH_LIM_FULL)
338     return (HTTPD_POLICY__TRUE);
339 
340   HTTPD_POLICY__ASSERT(ref);
341   srch = ref->ptr;
342 
343   if (0) { }
344   else if ((lim & HTTPD_POLICY__PATH_LIM_MASK) == HTTPD_POLICY__PATH_LIM_BEG)
345   {
346     if (!httpd_policy_path_beg_eq(srch->s1, s1, pos, len))
347       goto path_no_match;
348   }
349   else if ((lim & HTTPD_POLICY__PATH_LIM_MASK) == HTTPD_POLICY__PATH_LIM_END)
350   {
351     if (!httpd_policy_path_end_eq(srch->s1, s1, pos, len))
352       goto path_no_match;
353   }
354   else if ((lim & HTTPD_POLICY__PATH_LIM_MASK) == HTTPD_POLICY__PATH_LIM_EQ)
355   {
356     if (!httpd_policy_path_eq(srch->s1, s1, pos, len))
357       goto path_no_match;
358   }
359   else
360     HTTPD_POLICY__ASSERT(HTTPD_POLICY__FALSE);
361 
362   vstr_ref_del(ref); ref = NULL;
363   return (HTTPD_POLICY__TRUE);
364  path_no_match:
365   vstr_ref_del(ref); ref = NULL;
366   return (HTTPD_POLICY__FALSE);
367 }
368 
httpd_policy__uri_eq(const Vstr_base * s1,const Vstr_base * s2,size_t p2,size_t l2,size_t * ret_len)369 static inline int httpd_policy__uri_eq(const Vstr_base *s1,
370                                        const Vstr_base *s2,
371                                        size_t p2, size_t l2, size_t *ret_len)
372 {
373   size_t p1 = 1;
374   size_t l1 = s1->len;
375 
376   while (l1 && (l2 >= l1))
377   {
378     size_t tmp = vstr_cspn_cstr_chrs_fwd(s2, p2, l1, "%");
379     unsigned int val1 = 0;
380     unsigned int val2 = 0;
381     unsigned int num_flags = VSTR_FLAG02(PARSE_NUM_NO, BEG_ZERO, BEG_PM);
382 
383     if (tmp)
384     {
385       if (!vstr_cmp_eq(s1, p1, tmp, s2, p2, tmp))
386         return (HTTPD_POLICY__FALSE);
387       l1 -= tmp; p1 += tmp;
388       l2 -= tmp; p2 += tmp;
389       continue;
390     }
391 
392     if (l2 < 3)
393       return (HTTPD_POLICY__FALSE);
394     HTTPD_POLICY__ASSERT(vstr_export_chr(s2, p2) == '%');
395 
396     val1 = (unsigned char)vstr_export_chr(s1, p1);
397     val2 = vstr_parse_ushort(s2, p2 + 1, 2, 16 | num_flags, &tmp, NULL);
398 
399     if ((tmp != 2) || (val1 != val2))
400       return (HTTPD_POLICY__FALSE);
401 
402     l1 -= 1; p1 += 1;
403     l2 -= 3; p2 += 3;
404   }
405 
406   *ret_len = l2;
407   return (!l1);
408 }
409 
httpd_policy_uri_eq(const Vstr_base * s1,const Vstr_base * s2,size_t * p2,size_t * l2)410 extern inline int httpd_policy_uri_eq(const Vstr_base *s1,
411                                       const Vstr_base *s2,
412                                       size_t *p2, size_t *l2)
413 {
414   size_t tmp = 0;
415   return (httpd_policy__uri_eq(s1, s2, *p2, *l2, &tmp) && !tmp);
416 }
417 
418 /* if the s1 is equal to the begining of s2 */
httpd_policy_uri_beg_eq(const Vstr_base * s1,const Vstr_base * s2,size_t * p2,size_t * l2)419 extern inline int httpd_policy_uri_beg_eq(const Vstr_base *s1,
420                                           const Vstr_base *s2,
421                                           size_t *p2, size_t *l2)
422 {
423   size_t tmp = 0;
424 
425   if (!httpd_policy__uri_eq(s1, s2, *p2, *l2, &tmp))
426     return (HTTPD_POLICY__FALSE);
427 
428   if (tmp) *l2 -= tmp;
429 
430   return (HTTPD_POLICY__TRUE);
431 }
432 
433 /* if the s1 is equal to the end of s2 */
httpd_policy_uri_end_eq(const Vstr_base * s1,const Vstr_base * s2,size_t * p2,size_t * l2)434 extern inline int httpd_policy_uri_end_eq(const Vstr_base *s1,
435                                           const Vstr_base *s2,
436                                           size_t *p2, size_t *l2)
437 {
438   if (!vstr_srch_chr_fwd(s2, *p2, *l2, '%'))
439   {
440     if (*l2 > s1->len)
441     {
442       *p2 += (*l2 - s1->len);
443       *l2 = s1->len;
444     }
445     return (vstr_cmp_eq(s1, 1, s1->len, s2, *p2, *l2));
446   }
447 
448   if (*l2 > (s1->len * 3))
449   {
450     *p2 += (*l2 - (s1->len * 3));
451     *l2 = (s1->len * 3);
452   }
453 
454   while (*l2 >= s1->len)
455   {
456     size_t tmp = 0;
457     if (httpd_policy__uri_eq(s1, s2, *p2, *l2, &tmp) && !tmp)
458       return (HTTPD_POLICY__TRUE);
459     *l2 -= 1; *p2 += 1;
460   }
461 
462   return (HTTPD_POLICY__FALSE);
463 }
464 
httpd_policy_uri_mod_name(const Vstr_base * s1,size_t * pos,size_t * len)465 extern inline void httpd_policy_uri_mod_name(const Vstr_base *s1,
466                                              size_t *pos, size_t *len)
467 {
468   size_t srch1 = vstr_srch_chr_rev(s1, *pos, *len, '/');
469   size_t srch2 = vstr_srch_case_cstr_buf_rev(s1, *pos, *len, "%2f");
470   HTTPD_POLICY__ASSERT(srch1);
471 
472   if (srch1 < srch2)
473     srch1 = srch2 + 2;
474 
475   *len -= vstr_sc_posdiff(*pos, srch1);
476   *pos += vstr_sc_posdiff(*pos, srch1);
477 }
478 
httpd_policy_uri_mod_dirn(const Vstr_base * s1,size_t * pos,size_t * len)479 extern inline void httpd_policy_uri_mod_dirn(const Vstr_base *s1,
480                                              size_t *pos, size_t *len)
481 {
482   size_t srch1 = vstr_srch_chr_rev(s1, *pos, *len, '/');
483   size_t srch2 = vstr_srch_case_cstr_buf_rev(s1, *pos, *len, "%2f");
484   HTTPD_POLICY__ASSERT(srch1);
485 
486   if (srch1 < srch2)
487     srch1 = srch2 + 2;
488 
489   *len = vstr_sc_posdiff(*pos, srch1);
490 }
491 
httpd_policy_uri_mod_extn(const Vstr_base * s1,size_t * pos,size_t * len)492 extern inline void httpd_policy_uri_mod_extn(const Vstr_base *s1,
493                                              size_t *pos, size_t *len)
494 {
495   size_t srch1 = 0;
496   size_t srch2 = 0;
497 
498   httpd_policy_uri_mod_name(s1, pos, len);
499 
500   srch1 = vstr_srch_chr_rev(s1, *pos, *len, '.');
501   srch2 = vstr_srch_case_cstr_buf_rev(s1, *pos, *len, "%2e");
502 
503   if (srch1 < srch2)
504     srch1 = srch2;
505 
506   if (srch1)
507   { /* include '.' or "%2e" */
508     *len -= srch1 - *pos;
509     *pos = srch1;
510   }
511   else
512   { /* at point just after basename */
513     *pos = vstr_sc_poslast(*pos, *len);
514     *len = 0;
515   }
516 }
517 
httpd_policy_uri_mod_exts(const Vstr_base * s1,size_t * pos,size_t * len)518 extern inline void httpd_policy_uri_mod_exts(const Vstr_base *s1,
519                                              size_t *pos, size_t *len)
520 {
521   size_t srch1 = 0;
522   size_t srch2 = 0;
523 
524   httpd_policy_uri_mod_name(s1, pos, len);
525 
526   srch1 = vstr_srch_chr_fwd(s1, *pos, *len, '.');
527   srch2 = vstr_srch_case_cstr_buf_fwd(s1, *pos, *len, "%2e");
528 
529   if (srch1 > srch2)
530     srch1 = srch2;
531 
532   if (srch1)
533   { /* include '.' or "%2e" */
534     *len -= srch1 - *pos;
535     *pos = srch1;
536   }
537   else
538   { /* at point just after basename */
539     *pos = vstr_sc_poslast(*pos, *len);
540     *len = 0;
541   }
542 }
543 
httpd_policy_uri_mod_bwen(const Vstr_base * s1,size_t * pos,size_t * len)544 extern inline void httpd_policy_uri_mod_bwen(const Vstr_base *s1,
545                                              size_t *pos, size_t *len)
546 {
547   size_t srch1 = 0;
548   size_t srch2 = 0;
549   unsigned int num = 1;
550 
551   httpd_policy_uri_mod_name(s1, pos, len);
552 
553   srch1 = vstr_srch_chr_rev(s1, *pos, *len, '.');
554   srch2 = vstr_srch_case_cstr_buf_rev(s1, *pos, *len, "%2e");
555 
556   if (srch1 < srch2)
557   {
558     srch1 = srch2;
559     num   = 3;
560   }
561 
562   if (srch1)
563     *len = vstr_sc_posdiff(*pos, srch1) - num; /* don't include '.' */
564 }
565 
httpd_policy_uri_mod_bwes(const Vstr_base * s1,size_t * pos,size_t * len)566 extern inline void httpd_policy_uri_mod_bwes(const Vstr_base *s1,
567                                              size_t *pos, size_t *len)
568 {
569   size_t srch1 = 0;
570   size_t srch2 = 0;
571   unsigned int num = 1;
572 
573   httpd_policy_uri_mod_name(s1, pos, len);
574 
575   srch1 = vstr_srch_chr_fwd(s1, *pos, *len, '.');
576   srch2 = vstr_srch_case_cstr_buf_fwd(s1, *pos, *len, "%2e");
577 
578   if (srch1 > srch2)
579   {
580     srch1 = srch2;
581     num   = 3;
582   }
583 
584   if (srch1)
585     *len = vstr_sc_posdiff(*pos, srch1) - num; /* don't include '.' */
586 }
587 
httpd_policy_uri_lim_eq(const Vstr_base * s1,size_t * pos,size_t * len,unsigned int lim,int slash_dot_safe,Vstr_ref * ref)588 extern inline int httpd_policy_uri_lim_eq(const Vstr_base *s1,
589                                           size_t *pos, size_t *len,
590                                           unsigned int lim, int slash_dot_safe,
591                                           Vstr_ref *ref)
592 {
593   const Httpd_policy_path *srch = NULL;
594 
595   switch (lim)
596   {
597     default: HTTPD_POLICY__ASSERT(HTTPD_POLICY__FALSE);
598     case HTTPD_POLICY_PATH_LIM_NONE:
599       HTTPD_POLICY__ASSERT(!ref);
600       return (HTTPD_POLICY__TRUE);
601 
602     case HTTPD_POLICY_PATH_LIM_PATH_FULL:
603     case HTTPD_POLICY_PATH_LIM_PATH_BEG:
604     case HTTPD_POLICY_PATH_LIM_PATH_END:
605     case HTTPD_POLICY_PATH_LIM_PATH_EQ:
606       break;
607 
608     case HTTPD_POLICY_PATH_LIM_NAME_FULL:
609     case HTTPD_POLICY_PATH_LIM_NAME_BEG:
610     case HTTPD_POLICY_PATH_LIM_NAME_END:
611     case HTTPD_POLICY_PATH_LIM_NAME_EQ:
612       if (slash_dot_safe)
613         httpd_policy_path_mod_name(s1, pos, len);
614       else
615         httpd_policy_uri_mod_name(s1, pos, len);
616       break;
617 
618     case HTTPD_POLICY_PATH_LIM_EXTN_FULL:
619     case HTTPD_POLICY_PATH_LIM_EXTN_BEG:
620     case HTTPD_POLICY_PATH_LIM_EXTN_END:
621     case HTTPD_POLICY_PATH_LIM_EXTN_EQ:
622       if (slash_dot_safe)
623         httpd_policy_path_mod_extn(s1, pos, len);
624       else
625         httpd_policy_uri_mod_extn(s1, pos, len);
626       break;
627 
628     case HTTPD_POLICY_PATH_LIM_EXTS_FULL:
629     case HTTPD_POLICY_PATH_LIM_EXTS_BEG:
630     case HTTPD_POLICY_PATH_LIM_EXTS_END:
631     case HTTPD_POLICY_PATH_LIM_EXTS_EQ:
632       if (slash_dot_safe)
633         httpd_policy_path_mod_exts(s1, pos, len);
634       else
635         httpd_policy_uri_mod_exts(s1, pos, len);
636       break;
637 
638     case HTTPD_POLICY_PATH_LIM_BWEN_FULL:
639     case HTTPD_POLICY_PATH_LIM_BWEN_BEG:
640     case HTTPD_POLICY_PATH_LIM_BWEN_END:
641     case HTTPD_POLICY_PATH_LIM_BWEN_EQ:
642       if (slash_dot_safe)
643         httpd_policy_path_mod_bwen(s1, pos, len);
644       else
645         httpd_policy_uri_mod_bwen(s1, pos, len);
646       break;
647 
648     case HTTPD_POLICY_PATH_LIM_BWES_FULL:
649     case HTTPD_POLICY_PATH_LIM_BWES_BEG:
650     case HTTPD_POLICY_PATH_LIM_BWES_END:
651     case HTTPD_POLICY_PATH_LIM_BWES_EQ:
652       if (slash_dot_safe)
653         httpd_policy_path_mod_bwes(s1, pos, len);
654       else
655         httpd_policy_uri_mod_bwes(s1, pos, len);
656       break;
657   }
658 
659   if ((lim & HTTPD_POLICY__PATH_LIM_MASK) == HTTPD_POLICY__PATH_LIM_FULL)
660   {
661     HTTPD_POLICY__ASSERT(!ref);
662     return (HTTPD_POLICY__TRUE);
663   }
664 
665   HTTPD_POLICY__ASSERT(ref);
666   srch = ref->ptr;
667 
668   if (0) { }
669   else if ((lim & HTTPD_POLICY__PATH_LIM_MASK) == HTTPD_POLICY__PATH_LIM_BEG)
670   {
671     if (!httpd_policy_uri_beg_eq(srch->s1, s1, pos, len))
672       goto path_no_match;
673   }
674   else if ((lim & HTTPD_POLICY__PATH_LIM_MASK) == HTTPD_POLICY__PATH_LIM_END)
675   {
676     if (!httpd_policy_uri_end_eq(srch->s1, s1, pos, len))
677       goto path_no_match;
678   }
679   else if ((lim & HTTPD_POLICY__PATH_LIM_MASK) == HTTPD_POLICY__PATH_LIM_EQ)
680   {
681     if (!httpd_policy_uri_eq(srch->s1, s1, pos, len))
682       goto path_no_match;
683   }
684   else
685     HTTPD_POLICY__ASSERT(HTTPD_POLICY__FALSE);
686 
687   vstr_ref_del(ref); ref = NULL;
688   return (HTTPD_POLICY__TRUE);
689  path_no_match:
690   vstr_ref_del(ref); ref = NULL;
691   return (HTTPD_POLICY__FALSE);
692 }
693 
httpd_policy_path_req2lim(unsigned int type)694 extern inline int httpd_policy_path_req2lim(unsigned int type)
695 {
696   unsigned int lim = HTTPD_POLICY_PATH_LIM_NONE;
697 
698   switch (type)
699   {
700     case HTTPD_POLICY_REQ_PATH_BEG: lim = HTTPD_POLICY_PATH_LIM_PATH_BEG; break;
701     case HTTPD_POLICY_REQ_PATH_END: lim = HTTPD_POLICY_PATH_LIM_PATH_END; break;
702     case HTTPD_POLICY_REQ_PATH_EQ:  lim = HTTPD_POLICY_PATH_LIM_PATH_EQ;  break;
703 
704     case HTTPD_POLICY_REQ_NAME_BEG: lim = HTTPD_POLICY_PATH_LIM_NAME_BEG; break;
705     case HTTPD_POLICY_REQ_NAME_END: lim = HTTPD_POLICY_PATH_LIM_NAME_END; break;
706     case HTTPD_POLICY_REQ_NAME_EQ:  lim = HTTPD_POLICY_PATH_LIM_NAME_EQ;  break;
707 
708     case HTTPD_POLICY_REQ_BWEN_BEG: lim = HTTPD_POLICY_PATH_LIM_BWEN_BEG; break;
709     case HTTPD_POLICY_REQ_BWEN_END: lim = HTTPD_POLICY_PATH_LIM_BWEN_END; break;
710     case HTTPD_POLICY_REQ_BWEN_EQ:  lim = HTTPD_POLICY_PATH_LIM_BWEN_EQ;  break;
711 
712     case HTTPD_POLICY_REQ_BWES_BEG: lim = HTTPD_POLICY_PATH_LIM_BWES_BEG; break;
713     case HTTPD_POLICY_REQ_BWES_END: lim = HTTPD_POLICY_PATH_LIM_BWES_END; break;
714     case HTTPD_POLICY_REQ_BWES_EQ:  lim = HTTPD_POLICY_PATH_LIM_BWES_EQ;  break;
715 
716     case HTTPD_POLICY_REQ_EXTN_BEG: lim = HTTPD_POLICY_PATH_LIM_EXTN_BEG; break;
717     case HTTPD_POLICY_REQ_EXTN_END: lim = HTTPD_POLICY_PATH_LIM_EXTN_END; break;
718     case HTTPD_POLICY_REQ_EXTN_EQ:  lim = HTTPD_POLICY_PATH_LIM_EXTN_EQ;  break;
719 
720     case HTTPD_POLICY_REQ_EXTS_BEG: lim = HTTPD_POLICY_PATH_LIM_EXTS_BEG; break;
721     case HTTPD_POLICY_REQ_EXTS_END: lim = HTTPD_POLICY_PATH_LIM_EXTS_END; break;
722     case HTTPD_POLICY_REQ_EXTS_EQ:  lim = HTTPD_POLICY_PATH_LIM_EXTS_EQ;  break;
723 
724     default:
725       HTTPD_POLICY__ASSERT(HTTPD_POLICY__FALSE);
726   }
727 
728   return (lim);
729 }
730 
httpd_policy_ipv4_make(struct Con * con,Httpd_req_data * req,Conf_parse * conf,Conf_token * token,unsigned int type,struct sockaddr * sa,int * matches)731 extern inline int httpd_policy_ipv4_make(struct Con *con, Httpd_req_data *req,
732                                          Conf_parse *conf, Conf_token *token,
733                                          unsigned int type,
734                                          struct sockaddr *sa, int *matches)
735 {
736   HTTPD_POLICY__ASSERT(con);
737 
738   if (sa == EVNT_SA(con->evnt))
739   {
740     if (req)
741       req->vary_star = HTTPD_POLICY__TRUE;
742     else
743       con->vary_star = HTTPD_POLICY__TRUE;
744   }
745 
746   return (opt_policy_ipv4_make(conf, token, type, sa, matches));
747 }
748 
httpd_policy_ipv4_cidr_eq(struct Con * con,Httpd_req_data * req,Opt_policy_ipv4 * ipv4,struct sockaddr * sa)749 extern inline int httpd_policy_ipv4_cidr_eq(struct Con *con,Httpd_req_data *req,
750                                             Opt_policy_ipv4 *ipv4,
751                                             struct sockaddr *sa)
752 {
753   HTTPD_POLICY__ASSERT(con);
754 
755   if (sa == EVNT_SA(con->evnt))
756   {
757     if (req)
758       req->vary_star = HTTPD_POLICY__TRUE;
759     else
760       con->vary_star = HTTPD_POLICY__TRUE;
761   }
762 
763   return (opt_policy_ipv4_cidr_eq(ipv4, sa));
764 }
765 
766 
767 #endif
768 
769 #endif
770