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