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
opt_policy_exit(Opt_serv_policy_opts * opts)9 void opt_policy_exit(Opt_serv_policy_opts *opts)
10 {
11 ASSERT(opts);
12
13 vstr_free_base(opts->policy_name); opts->policy_name = NULL;
14 opts->beg = NULL;
15 }
16
opt_policy_init(Opt_serv_opts * beg_opts,Opt_serv_policy_opts * opts)17 int opt_policy_init(Opt_serv_opts *beg_opts, Opt_serv_policy_opts *opts)
18 {
19 ASSERT(beg_opts);
20
21 opts->policy_name = vstr_make_base(NULL);
22 if (!opts->policy_name ||
23 FALSE)
24 {
25 opt_policy_exit(opts);
26 return (FALSE);
27 }
28
29 opts->idle_timeout = OPT_SERV_CONF_DEF_IDLE_TIMEOUT;
30 opts->max_connections = OPT_SERV_CONF_DEF_MAX_CONNECTIONS;
31
32 opts->beg = beg_opts;
33 opts->next = NULL;
34
35 return (TRUE);
36 }
37
opt_policy_free(Vstr_ref * ref)38 static void opt_policy_free(Vstr_ref *ref)
39 {
40 Opt_serv_policy_opts *opts = NULL;
41
42 if (!ref)
43 return;
44
45 if ((opts = ref->ptr))
46 opt_policy_exit(opts);
47 F(opts);
48 free(ref);
49 }
50
opt_policy_make(Opt_serv_opts * beg)51 Opt_serv_policy_opts *opt_policy_make(Opt_serv_opts *beg)
52 {
53 Opt_serv_policy_opts *opts = MK(sizeof(Opt_serv_policy_opts));
54 Vstr_ref *ref = NULL;
55
56 if (!opts)
57 goto mk_opts_fail;
58
59 if (!(ref = vstr_ref_make_ptr(opts, opt_policy_free)))
60 goto mk_ref_fail;
61 opts->ref = ref;
62
63 if (!opt_policy_init(beg, opts))
64 goto policy_init_fail;
65
66 return (opts);
67
68 policy_init_fail:
69 ref->ptr = NULL;
70 vstr_ref_del(ref);
71 mk_ref_fail:
72 F(opts);
73 mk_opts_fail:
74 return (NULL);
75 }
76
opt_policy_add(Opt_serv_opts * beg,Opt_serv_policy_opts * opts)77 void opt_policy_add(Opt_serv_opts *beg, Opt_serv_policy_opts *opts)
78 {
79 Opt_serv_policy_opts **ins = NULL;
80
81 opts->next = beg->def_policy;
82 ins = &opts->next; /* hacky, fix when def_policy is a real pointer */
83 ASSERT(*ins);
84
85 while ((ins = &(*ins)->next) && *ins)
86 {
87 Vstr_base *s1 = opts->policy_name;
88 Vstr_base *s2 = (*ins)->policy_name;
89
90 ASSERT(!(*ins)->next ||
91 ((*ins)->policy_name->len < (*ins)->next->policy_name->len) ||
92 (((*ins)->policy_name->len == (*ins)->next->policy_name->len) &&
93 vstr_cmp((*ins)->policy_name, 1, (*ins)->policy_name->len,
94 (*ins)->next->policy_name, 1,
95 (*ins)->next->policy_name->len) < 0));
96
97 if (s1->len > s2->len)
98 continue;
99 if (s1->len < s2->len)
100 break;
101 if (vstr_cmp(s1, 1, s1->len, s2, 1, s2->len) <= 0)
102 break;
103 }
104 ASSERT(ins != &opts->next);
105 opts->next = *ins;
106 *ins = opts;
107 }
108
opt_policy_ipv4_make(Conf_parse * conf,Conf_token * token,unsigned int type,struct sockaddr * sa,int * matches)109 int opt_policy_ipv4_make(Conf_parse *conf, Conf_token *token,
110 unsigned int type, struct sockaddr *sa, int *matches)
111 {
112 Conf_token save = *token;
113 Vstr_ref *ref = NULL;
114 Opt_policy_ipv4 *data = NULL;
115 int ret = FALSE;
116
117 CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
118
119 if (!(ref = vstr_ref_make_malloc(sizeof(Opt_policy_ipv4))))
120 return (FALSE);
121 data = ref->ptr;
122
123 ret = vstr_parse_ipv4(conf->data, token->u.node->pos, token->u.node->len,
124 data->ipv4, &data->cidr,
125 VSTR_FLAG05(PARSE_IPV4, CIDR, CIDR_FULL,
126 NETMASK, NETMASK_FULL, ONLY), NULL, NULL);
127
128 if (ret)
129 {
130 *matches = opt_policy_ipv4_cidr_eq(data, sa);
131
132 ret = conf_token_set_user_value(conf, &save, type, ref, token->num);
133 }
134
135 vstr_ref_del(ref);
136
137 return (!!ret);
138 }
139
opt_policy_ipv4_cidr_eq(Opt_policy_ipv4 * data,struct sockaddr * sa)140 int opt_policy_ipv4_cidr_eq(Opt_policy_ipv4 *data, struct sockaddr *sa)
141 {
142 struct sockaddr_in *sa_in = NULL;
143 uint32_t tst_addr_ipv4;
144 unsigned char tst_ipv4[4];
145 unsigned int scan = 0;
146 unsigned int cidr = data->cidr;
147
148 ASSERT(cidr <= 32);
149
150 if (!sa || (sa->sa_family != AF_INET))
151 return (FALSE);
152 sa_in = (struct sockaddr_in *)sa;
153
154 tst_addr_ipv4 = ntohl(sa_in->sin_addr.s_addr);
155
156 tst_ipv4[3] = (tst_addr_ipv4 >> 0) & 0xFF;
157 tst_ipv4[2] = (tst_addr_ipv4 >> 8) & 0xFF;
158 tst_ipv4[1] = (tst_addr_ipv4 >> 16) & 0xFF;
159 tst_ipv4[0] = (tst_addr_ipv4 >> 24) & 0xFF;
160
161 scan = 0;
162 while (cidr >= 8)
163 {
164 if (tst_ipv4[scan] != data->ipv4[scan])
165 return (FALSE);
166
167 ++scan;
168 cidr -= 8;
169 }
170 ASSERT(!cidr || (scan < 4));
171
172 if (cidr)
173 { /* x/7 == (1 << 7) - 1 == 0b0111_1111 */
174 unsigned int mask = ((1 << cidr) - 1) << (8 - cidr);
175 if ((tst_ipv4[scan] & mask) != (data->ipv4[scan] & mask))
176 return (FALSE);
177 }
178
179 return (TRUE);
180 }
181
opt_policy_sc_conf_make(Opt_serv_opts * opts,const Conf_parse * conf,const Conf_token * token,const Vstr_sect_node * pv)182 Opt_serv_policy_opts *opt_policy_sc_conf_make(Opt_serv_opts *opts,
183 const Conf_parse *conf,
184 const Conf_token *token,
185 const Vstr_sect_node *pv)
186 {
187 Opt_serv_policy_opts *popts = opts->make_policy(opts);
188 Vstr_base *name = NULL;
189
190 ASSERT(conf && token && pv);
191
192 if (!popts)
193 goto init_failure;
194
195 if (!(*opts->copy_policy)(popts, opts->def_policy))
196 goto copy_failure;
197
198 ASSERT(pv);
199
200 name = popts->policy_name;
201 if (!vstr_sub_vstr(name, 1, name->len, conf->data, pv->pos, pv->len,
202 VSTR_TYPE_SUB_BUF_REF))
203 goto name_failure;
204 if ((token->type == CONF_TOKEN_TYPE_QUOTE_ESC_D) ||
205 (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_DDD) ||
206 (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_S) ||
207 (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_SSS) ||
208 FALSE)
209 if (!conf_sc_conv_unesc(name, 1, pv->len, NULL))
210 goto name_failure;
211
212 opt_policy_add(opts, popts);
213
214 return (popts);
215
216 name_failure:
217 copy_failure:
218 vstr_ref_del(popts->ref);
219 init_failure:
220 return (NULL);
221 }
222
opt_policy_sc_conf_parse(Opt_serv_opts * opts,const Conf_parse * conf,Conf_token * token,Opt_serv_policy_opts ** ret_popts)223 unsigned int opt_policy_sc_conf_parse(Opt_serv_opts *opts,
224 const Conf_parse *conf, Conf_token *token,
225 Opt_serv_policy_opts **ret_popts)
226 {
227 Opt_serv_policy_opts *popts = NULL;
228 unsigned int cur_depth = token->depth_num;
229 Conf_token save;
230 const Vstr_sect_node *pv = NULL;
231 int created_now = FALSE;
232
233 ASSERT(opts && opts->def_policy && ret_popts);
234
235 *ret_popts = NULL;
236
237 /* name first */
238 CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
239
240 if (!(pv = conf_token_value(token)))
241 return (0);
242
243 if (!(popts = opt_policy_find(opts, conf, token)))
244 {
245 if (!(popts = opt_policy_sc_conf_make(opts, conf, token, pv)))
246 return (0);
247 created_now = TRUE;
248 }
249
250 save = *token;
251 if (!conf_parse_token(conf, token) || (token->depth_num < cur_depth))
252 return (cur_depth);
253 if (token->type != CONF_TOKEN_TYPE_SLIST)
254 *token = save; /* restore ... */
255 else
256 { /* allow set of attributes */
257 int clist = FALSE;
258
259 CONF_SC_MAKE_CLIST_BEG(policy, clist);
260
261 else if (OPT_SERV_SYM_EQ("inherit"))
262 {
263 const Opt_serv_policy_opts *frm_opts = NULL;
264 CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, 0);
265 if (!(frm_opts = opt_policy_find(opts, conf, token)))
266 return (0);
267 if (created_now && !(*opts->copy_policy)(popts, frm_opts))
268 return (0);
269 }
270 else if (OPT_SERV_SYM_EQ("copy"))
271 {
272 const Opt_serv_policy_opts *frm_opts = NULL;
273 CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, 0);
274 if (!(frm_opts = opt_policy_find(opts, conf, token)))
275 return (0);
276 if (!(*opts->copy_policy)(popts, frm_opts))
277 return (0);
278 }
279
280 CONF_SC_MAKE_CLIST_END();
281 }
282
283 *ret_popts = popts;
284 return (cur_depth);
285 }
286
opt_policy_sc_all_ref_del(Opt_serv_opts * opts)287 void opt_policy_sc_all_ref_del(Opt_serv_opts *opts)
288 {
289 Opt_serv_policy_opts *scan = opts->def_policy;
290
291 opts->def_policy = NULL;
292 while (scan)
293 {
294 Opt_serv_policy_opts *scan_next = scan->next;
295
296 vstr_ref_del(scan->ref);
297
298 scan = scan_next;
299 }
300 }
301
302