1 : #define EX_UTILS_NO_FUNCS 1
2 : #include "ex_utils.h"
3 :
4 : #include "opt_policy.h"
5 :
6 : #include "mk.h"
7 :
8 : #include <stddef.h> /* offsetof */
9 :
10 : void opt_policy_exit(Opt_serv_policy_opts *opts)
11 144 : {
12 72 : ASSERT(opts);
13 :
14 144 : vstr_free_base(opts->policy_name); opts->policy_name = NULL;
15 144 : opts->beg = NULL;
16 :
17 72 : ASSERT( opts->ref_io_limit);
18 144 : vstr_ref_del(opts->ref_io_limit);
19 72 : ASSERT(!opts->ref_io_limit);
20 144 : }
21 :
22 : static void opt_policy__io_lim_ref_cb(struct Vstr_ref *ref)
23 144 : {
24 144 : Opt_serv_policy_opts *opts = NULL;
25 144 : struct Evnt_limit *lim = NULL;
26 :
27 144 : if (!ref)
28 0 : return;
29 :
30 144 : lim = ref->ptr;
31 72 : ASSERT(lim);
32 :
33 : /* ISO C magic, converts a ptr to io_limit into a pointer to policy_opts */
34 144 : opts = (Opt_serv_policy_opts *)(((char *)lim) -
35 : offsetof(Opt_serv_policy_opts, io_limit));
36 144 : opts->ref_io_limit = NULL; /* more magic */
37 : }
38 :
39 : int opt_policy_init(Opt_serv_opts *beg_opts, Opt_serv_policy_opts *opts)
40 162 : {
41 81 : ASSERT(beg_opts);
42 :
43 162 : opts->ref_io_limit = NULL;
44 :
45 162 : opts->policy_name = vstr_make_base(NULL);
46 162 : opts->ref_io_limit = vstr_ref_make_ptr(&opts->io_limit,
47 : opt_policy__io_lim_ref_cb);
48 162 : if (!opts->policy_name ||
49 : !opts->ref_io_limit ||
50 : FALSE)
51 : goto fail;
52 :
53 162 : opts->io_limit.io_r_cur = 0;
54 162 : opts->io_limit.io_r_max = 0;
55 162 : opts->io_limit.io_r_tm.tv_sec = 0;
56 162 : opts->io_limit.io_w_cur = 0;
57 162 : opts->io_limit.io_w_max = 0;
58 162 : opts->io_limit.io_w_tm.tv_sec = 0;
59 :
60 162 : opts->io_nslimit.io_r_cur = 0;
61 162 : opts->io_nslimit.io_r_max = 0;
62 162 : opts->io_nslimit.io_r_tm.tv_sec = 0;
63 162 : opts->io_nslimit.io_w_cur = 0;
64 162 : opts->io_nslimit.io_w_max = 0;
65 162 : opts->io_nslimit.io_w_tm.tv_sec = 0;
66 :
67 162 : opts->idle_timeout = OPT_SERV_CONF_DEF_IDLE_TIMEOUT;
68 162 : opts->max_timeout = OPT_SERV_CONF_DEF_MAX_TIMEOUT;
69 :
70 162 : opts->max_connections = OPT_SERV_CONF_DEF_MAX_CONNECTIONS;
71 :
72 162 : opts->use_insta_close = OPT_SERV_CONF_USE_INSTA_CLOSE;
73 :
74 162 : opts->beg = beg_opts;
75 162 : opts->next = NULL;
76 :
77 162 : return (TRUE);
78 :
79 0 : fail:
80 0 : opt_policy_exit(opts);
81 0 : return (FALSE);
82 : }
83 :
84 : static void opt_policy_free(Vstr_ref *ref)
85 0 : {
86 0 : Opt_serv_policy_opts *opts = NULL;
87 :
88 0 : if (!ref)
89 0 : return;
90 :
91 0 : if ((opts = ref->ptr))
92 0 : opt_policy_exit(opts);
93 0 : F(opts);
94 0 : free(ref);
95 : }
96 :
97 : Opt_serv_policy_opts *opt_policy_make(Opt_serv_opts *beg)
98 0 : {
99 0 : Opt_serv_policy_opts *opts = MK(sizeof(Opt_serv_policy_opts));
100 0 : Vstr_ref *ref = NULL;
101 :
102 0 : if (!opts)
103 0 : goto mk_opts_fail;
104 :
105 0 : if (!(ref = vstr_ref_make_ptr(opts, opt_policy_free)))
106 0 : goto mk_ref_fail;
107 0 : opts->ref = ref;
108 :
109 0 : if (!opt_policy_init(beg, opts))
110 0 : goto policy_init_fail;
111 :
112 0 : return (opts);
113 :
114 0 : policy_init_fail:
115 0 : ref->ptr = NULL;
116 0 : vstr_ref_del(ref);
117 0 : mk_ref_fail:
118 0 : F(opts);
119 0 : mk_opts_fail:
120 0 : return (NULL);
121 : }
122 :
123 : void opt_policy_add(Opt_serv_opts *beg, Opt_serv_policy_opts *opts)
124 98 : {
125 98 : Opt_serv_policy_opts **ins = NULL;
126 :
127 98 : opts->next = beg->def_policy;
128 98 : ins = &opts->next; /* hacky, fix when def_policy is a real pointer */
129 49 : ASSERT(*ins);
130 :
131 709 : while ((ins = &(*ins)->next) && *ins)
132 : {
133 570 : Vstr_base *s1 = opts->policy_name;
134 570 : Vstr_base *s2 = (*ins)->policy_name;
135 :
136 285 : ASSERT(!(*ins)->next ||
137 : ((*ins)->policy_name->len < (*ins)->next->policy_name->len) ||
138 : (((*ins)->policy_name->len == (*ins)->next->policy_name->len) &&
139 : vstr_cmp((*ins)->policy_name, 1, (*ins)->policy_name->len,
140 : (*ins)->next->policy_name, 1,
141 : (*ins)->next->policy_name->len) < 0));
142 :
143 570 : if (s1->len > s2->len)
144 274 : continue;
145 296 : if (s1->len < s2->len)
146 8 : break;
147 288 : if (vstr_cmp(s1, 1, s1->len, s2, 1, s2->len) <= 0)
148 0 : break;
149 : }
150 49 : ASSERT(ins != &opts->next);
151 98 : opts->next = *ins;
152 98 : *ins = opts;
153 98 : }
154 :
155 : int opt_policy_ipv4_make(Conf_parse *conf, Conf_token *token,
156 : unsigned int type, struct sockaddr *sa, int *matches)
157 350 : {
158 350 : Conf_token save = *token;
159 350 : Vstr_ref *ref = NULL;
160 350 : Opt_policy_ipv4 *data = NULL;
161 350 : int ret = FALSE;
162 :
163 350 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
164 :
165 350 : if (!(ref = vstr_ref_make_malloc(sizeof(Opt_policy_ipv4))))
166 0 : return (FALSE);
167 350 : data = ref->ptr;
168 :
169 350 : ret = vstr_parse_ipv4(conf->data, token->u.node->pos, token->u.node->len,
170 : data->ipv4, &data->cidr,
171 : VSTR_FLAG05(PARSE_IPV4, CIDR, CIDR_FULL,
172 : NETMASK, NETMASK_FULL, ONLY), NULL, NULL);
173 :
174 350 : if (ret)
175 : {
176 350 : *matches = opt_policy_ipv4_cidr_eq(data, sa);
177 :
178 350 : ret = conf_token_set_user_value(conf, &save, type, ref, token->num);
179 : }
180 :
181 350 : vstr_ref_del(ref);
182 :
183 350 : return (!!ret);
184 : }
185 :
186 : int opt_policy_ipv4_cidr_eq(Opt_policy_ipv4 *data, struct sockaddr *sa)
187 40836 : {
188 40836 : struct sockaddr_in *sa_in = NULL;
189 : uint32_t tst_addr_ipv4;
190 : unsigned char tst_ipv4[4];
191 40836 : unsigned int scan = 0;
192 40836 : unsigned int cidr = data->cidr;
193 :
194 20418 : ASSERT(cidr <= 32);
195 :
196 40836 : if (!sa || (sa->sa_family != AF_INET))
197 0 : return (FALSE);
198 40836 : sa_in = (struct sockaddr_in *)sa;
199 :
200 40836 : tst_addr_ipv4 = ntohl(sa_in->sin_addr.s_addr);
201 :
202 40836 : tst_ipv4[3] = (tst_addr_ipv4 >> 0) & 0xFF;
203 40836 : tst_ipv4[2] = (tst_addr_ipv4 >> 8) & 0xFF;
204 40836 : tst_ipv4[1] = (tst_addr_ipv4 >> 16) & 0xFF;
205 40836 : tst_ipv4[0] = (tst_addr_ipv4 >> 24) & 0xFF;
206 :
207 40836 : scan = 0;
208 189344 : while (cidr >= 8)
209 : {
210 139828 : if (tst_ipv4[scan] != data->ipv4[scan])
211 32156 : return (FALSE);
212 :
213 107672 : ++scan;
214 107672 : cidr -= 8;
215 : }
216 4340 : ASSERT(!cidr || (scan < 4));
217 :
218 8680 : if (cidr)
219 : { /* x/7 == (1 << 7) - 1 == 0b0111_1111 */
220 0 : unsigned int mask = ((1 << cidr) - 1) << (8 - cidr);
221 0 : if ((tst_ipv4[scan] & mask) != (data->ipv4[scan] & mask))
222 0 : return (FALSE);
223 : }
224 :
225 8680 : return (TRUE);
226 : }
227 :
228 : Opt_serv_policy_opts *opt_policy_sc_conf_make(Opt_serv_opts *opts,
229 : const Conf_parse *conf,
230 : const Conf_token *token,
231 : const Vstr_sect_node *pv)
232 98 : {
233 98 : Opt_serv_policy_opts *popts = opts->make_policy(opts);
234 98 : Vstr_base *name = NULL;
235 :
236 49 : ASSERT(conf && token && pv);
237 :
238 98 : if (!popts)
239 0 : goto init_failure;
240 :
241 98 : if (!(*opts->copy_policy)(popts, opts->def_policy))
242 0 : goto copy_failure;
243 :
244 49 : ASSERT(pv);
245 :
246 98 : name = popts->policy_name;
247 98 : if (!vstr_sub_vstr(name, 1, name->len, conf->data, pv->pos, pv->len,
248 : VSTR_TYPE_SUB_BUF_REF))
249 0 : goto name_failure;
250 98 : if ((token->type == CONF_TOKEN_TYPE_QUOTE_ESC_D) ||
251 : (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_DDD) ||
252 : (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_S) ||
253 : (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_SSS) ||
254 : FALSE)
255 0 : if (!conf_sc_conv_unesc(name, 1, pv->len, NULL))
256 0 : goto name_failure;
257 :
258 98 : opt_policy_add(opts, popts);
259 :
260 98 : return (popts);
261 :
262 0 : name_failure:
263 0 : copy_failure:
264 0 : vstr_ref_del(popts->ref);
265 0 : init_failure:
266 0 : return (NULL);
267 : }
268 :
269 : unsigned int opt_policy_sc_conf_parse(Opt_serv_opts *opts,
270 : const Conf_parse *conf, Conf_token *token,
271 : Opt_serv_policy_opts **ret_popts,
272 : Conf_token **ntoken)
273 174 : {
274 174 : Opt_serv_policy_opts *popts = NULL;
275 174 : unsigned int cur_depth = token->depth_num;
276 : Conf_token save;
277 174 : const Vstr_sect_node *pv = NULL;
278 174 : int created_now = FALSE;
279 : static Conf_token policy_list_save;
280 :
281 87 : ASSERT(opts && opts->def_policy && ret_popts && ntoken);
282 :
283 174 : *ret_popts = NULL;
284 :
285 174 : if (*ntoken)
286 : { /* comming back for the next name... */
287 0 : ASSERT(*ntoken == &policy_list_save);
288 :
289 0 : *token = **ntoken;
290 : }
291 : else
292 : {
293 174 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, 0);
294 :
295 174 : if (token->type == CONF_TOKEN_TYPE_CLIST)
296 : { /* have a list of policy names... */
297 0 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, 0);
298 :
299 0 : *ntoken = &policy_list_save;
300 0 : **ntoken = *token;
301 : }
302 : }
303 :
304 174 : if (!(pv = conf_token_value(token)))
305 0 : return (0);
306 :
307 174 : if (!(popts = opt_policy_conf_find(opts, conf, token)))
308 : {
309 98 : if (!(popts = opt_policy_sc_conf_make(opts, conf, token, pv)))
310 0 : return (0);
311 98 : created_now = TRUE;
312 : }
313 :
314 174 : if (*ntoken)
315 : {
316 0 : unsigned int depth = (*ntoken)->depth_num;
317 0 : if (!conf_parse_token(conf, *ntoken) || (depth != (*ntoken)->depth_num))
318 0 : *ntoken = NULL;
319 0 : if (!conf_parse_end_token(conf, token, token->depth_num))
320 0 : return (0);
321 : }
322 :
323 174 : save = *token;
324 174 : if (!conf_parse_token(conf, token) || (token->depth_num < cur_depth))
325 0 : return (cur_depth);
326 174 : if (token->type != CONF_TOKEN_TYPE_SLIST)
327 130 : *token = save; /* restore ... */
328 : else
329 : { /* allow set of attributes */
330 44 : int clist = FALSE;
331 :
332 132 : CONF_SC_MAKE_CLIST_BEG(policy, clist);
333 :
334 44 : else if (OPT_SERV_SYM_EQ("inherit"))
335 : {
336 40 : const Opt_serv_policy_opts *frm_opts = NULL;
337 40 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, 0);
338 40 : if (!(frm_opts = opt_policy_conf_find(opts, conf, token)))
339 0 : return (0);
340 40 : if (frm_opts == popts)
341 0 : return (0);
342 40 : if (created_now && !(*opts->copy_policy)(popts, frm_opts))
343 0 : return (0);
344 : }
345 4 : else if (OPT_SERV_SYM_EQ("copy"))
346 : {
347 4 : const Opt_serv_policy_opts *frm_opts = NULL;
348 4 : CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, 0);
349 4 : if (!(frm_opts = opt_policy_conf_find(opts, conf, token)))
350 0 : return (0);
351 4 : if (frm_opts == popts)
352 0 : return (0);
353 4 : if (!(*opts->copy_policy)(popts, frm_opts))
354 0 : return (0);
355 : }
356 :
357 0 : CONF_SC_MAKE_CLIST_END();
358 : }
359 :
360 174 : *ret_popts = popts;
361 174 : return (cur_depth);
362 : }
363 :
364 : void opt_policy_sc_all_ref_del(Opt_serv_opts *opts)
365 44 : {
366 44 : Opt_serv_policy_opts *scan = opts->def_policy;
367 :
368 44 : opts->def_policy = NULL;
369 232 : while (scan)
370 : {
371 144 : Opt_serv_policy_opts *scan_next = scan->next;
372 :
373 144 : vstr_ref_del(scan->ref);
374 :
375 144 : scan = scan_next;
376 : }
377 44 : }
378 :
|