opt_policy.c
#define EX_UTILS_NO_FUNCS 1
#include "ex_utils.h"
#include "opt_policy.h"
#include "mk.h"
void opt_policy_exit(Opt_serv_policy_opts *opts)
{
ASSERT(opts);
vstr_free_base(opts->policy_name); opts->policy_name = NULL;
opts->beg = NULL;
}
int opt_policy_init(Opt_serv_opts *beg_opts, Opt_serv_policy_opts *opts)
{
ASSERT(beg_opts);
opts->policy_name = vstr_make_base(NULL);
if (!opts->policy_name ||
FALSE)
{
opt_policy_exit(opts);
return (FALSE);
}
opts->idle_timeout = OPT_SERV_CONF_DEF_IDLE_TIMEOUT;
opts->max_connections = OPT_SERV_CONF_DEF_MAX_CONNECTIONS;
opts->beg = beg_opts;
opts->next = NULL;
return (TRUE);
}
static void opt_policy_free(Vstr_ref *ref)
{
Opt_serv_policy_opts *opts = NULL;
if (!ref)
return;
if ((opts = ref->ptr))
opt_policy_exit(opts);
F(opts);
free(ref);
}
Opt_serv_policy_opts *opt_policy_make(Opt_serv_opts *beg)
{
Opt_serv_policy_opts *opts = MK(sizeof(Opt_serv_policy_opts));
Vstr_ref *ref = NULL;
if (!opts)
goto mk_opts_fail;
if (!(ref = vstr_ref_make_ptr(opts, opt_policy_free)))
goto mk_ref_fail;
opts->ref = ref;
if (!opt_policy_init(beg, opts))
goto policy_init_fail;
return (opts);
policy_init_fail:
ref->ptr = NULL;
vstr_ref_del(ref);
mk_ref_fail:
F(opts);
mk_opts_fail:
return (NULL);
}
void opt_policy_add(Opt_serv_opts *beg, Opt_serv_policy_opts *opts)
{
Opt_serv_policy_opts **ins = NULL;
opts->next = beg->def_policy;
ins = &opts->next;
ASSERT(*ins);
while ((ins = &(*ins)->next) && *ins)
{
Vstr_base *s1 = opts->policy_name;
Vstr_base *s2 = (*ins)->policy_name;
ASSERT(!(*ins)->next ||
((*ins)->policy_name->len < (*ins)->next->policy_name->len) ||
(((*ins)->policy_name->len == (*ins)->next->policy_name->len) &&
vstr_cmp((*ins)->policy_name, 1, (*ins)->policy_name->len,
(*ins)->next->policy_name, 1,
(*ins)->next->policy_name->len) < 0));
if (s1->len > s2->len)
continue;
if (s1->len < s2->len)
break;
if (vstr_cmp(s1, 1, s1->len, s2, 1, s2->len) <= 0)
break;
}
ASSERT(ins != &opts->next);
opts->next = *ins;
*ins = opts;
}
int opt_policy_ipv4_make(Conf_parse *conf, Conf_token *token,
unsigned int type, struct sockaddr *sa, int *matches)
{
Conf_token save = *token;
Vstr_ref *ref = NULL;
Opt_policy_ipv4 *data = NULL;
int ret = FALSE;
CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
if (!(ref = vstr_ref_make_malloc(sizeof(Opt_policy_ipv4))))
return (FALSE);
data = ref->ptr;
ret = vstr_parse_ipv4(conf->data, token->u.node->pos, token->u.node->len,
data->ipv4, &data->cidr,
VSTR_FLAG05(PARSE_IPV4, CIDR, CIDR_FULL,
NETMASK, NETMASK_FULL, ONLY), NULL, NULL);
if (ret)
{
*matches = opt_policy_ipv4_cidr_eq(data, sa);
ret = conf_token_set_user_value(conf, &save, type, ref, token->num);
}
vstr_ref_del(ref);
return (!!ret);
}
int opt_policy_ipv4_cidr_eq(Opt_policy_ipv4 *data, struct sockaddr *sa)
{
struct sockaddr_in *sa_in = NULL;
uint32_t tst_addr_ipv4;
unsigned char tst_ipv4[4];
unsigned int scan = 0;
unsigned int cidr = data->cidr;
ASSERT(cidr <= 32);
if (!sa || (sa->sa_family != AF_INET))
return (FALSE);
sa_in = (struct sockaddr_in *)sa;
tst_addr_ipv4 = ntohl(sa_in->sin_addr.s_addr);
tst_ipv4[3] = (tst_addr_ipv4 >> 0) & 0xFF;
tst_ipv4[2] = (tst_addr_ipv4 >> 8) & 0xFF;
tst_ipv4[1] = (tst_addr_ipv4 >> 16) & 0xFF;
tst_ipv4[0] = (tst_addr_ipv4 >> 24) & 0xFF;
scan = 0;
while (cidr >= 8)
{
if (tst_ipv4[scan] != data->ipv4[scan])
return (FALSE);
++scan;
cidr -= 8;
}
ASSERT(!cidr || (scan < 4));
if (cidr)
{
unsigned int mask = ((1 << cidr) - 1) << (8 - cidr);
if ((tst_ipv4[scan] & mask) != (data->ipv4[scan] & mask))
return (FALSE);
}
return (TRUE);
}
Opt_serv_policy_opts *opt_policy_sc_conf_make(Opt_serv_opts *opts,
const Conf_parse *conf,
const Conf_token *token,
const Vstr_sect_node *pv)
{
Opt_serv_policy_opts *popts = opts->make_policy(opts);
Vstr_base *name = NULL;
ASSERT(conf && token && pv);
if (!popts)
goto init_failure;
if (!(*opts->copy_policy)(popts, opts->def_policy))
goto copy_failure;
ASSERT(pv);
name = popts->policy_name;
if (!vstr_sub_vstr(name, 1, name->len, conf->data, pv->pos, pv->len,
VSTR_TYPE_SUB_BUF_REF))
goto name_failure;
if ((token->type == CONF_TOKEN_TYPE_QUOTE_ESC_D) ||
(token->type == CONF_TOKEN_TYPE_QUOTE_ESC_DDD) ||
(token->type == CONF_TOKEN_TYPE_QUOTE_ESC_S) ||
(token->type == CONF_TOKEN_TYPE_QUOTE_ESC_SSS) ||
FALSE)
if (!conf_sc_conv_unesc(name, 1, pv->len, NULL))
goto name_failure;
opt_policy_add(opts, popts);
return (popts);
name_failure:
copy_failure:
vstr_ref_del(popts->ref);
init_failure:
return (NULL);
}
unsigned int opt_policy_sc_conf_parse(Opt_serv_opts *opts,
const Conf_parse *conf, Conf_token *token,
Opt_serv_policy_opts **ret_popts)
{
Opt_serv_policy_opts *popts = NULL;
unsigned int cur_depth = token->depth_num;
Conf_token save;
const Vstr_sect_node *pv = NULL;
int created_now = FALSE;
ASSERT(opts && opts->def_policy && ret_popts);
*ret_popts = NULL;
CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
if (!(pv = conf_token_value(token)))
return (0);
if (!(popts = opt_policy_find(opts, conf, token)))
{
if (!(popts = opt_policy_sc_conf_make(opts, conf, token, pv)))
return (0);
created_now = TRUE;
}
save = *token;
if (!conf_parse_token(conf, token) || (token->depth_num < cur_depth))
return (cur_depth);
if (token->type != CONF_TOKEN_TYPE_SLIST)
*token = save;
else
{
OPT_SERV_PRIME_SYM_EQ_DECL();
int clist = FALSE;
CONF_SC_MAKE_CLIST_BEG(policy, clist);
else if (OPT_SERV_SYM_EQ("inherit"))
{
const Opt_serv_policy_opts *frm_opts = NULL;
CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, 0);
if (!(frm_opts = opt_policy_find(opts, conf, token)))
return (0);
if (created_now && !(*opts->copy_policy)(popts, frm_opts))
return (0);
}
else if (OPT_SERV_SYM_EQ("copy"))
{
const Opt_serv_policy_opts *frm_opts = NULL;
CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, 0);
if (!(frm_opts = opt_policy_find(opts, conf, token)))
return (0);
if (!(*opts->copy_policy)(popts, frm_opts))
return (0);
}
CONF_SC_MAKE_CLIST_END();
}
*ret_popts = popts;
return (cur_depth);
}
void opt_policy_sc_all_ref_del(Opt_serv_opts *opts)
{
Opt_serv_policy_opts *scan = opts->def_policy;
opts->def_policy = NULL;
while (scan)
{
Opt_serv_policy_opts *scan_next = scan->next;
vstr_ref_del(scan->ref);
scan = scan_next;
}
}
int opt_policy_sc_tst(Conf_parse *conf, Conf_token *token, int *matches,
int (*tst_func)(Conf_parse *, Conf_token *,
int *, void *), void *data)
{
OPT_SERV_PRIME_SYM_EQ_DECL();
if (0) { }
else if (OPT_SERV_SYM_EQ("not") || OPT_SERV_SYM_EQ("!"))
{
CONF_SC_PARSE_TOP_TOKEN_RET(conf, token, FALSE);
if (!(*tst_func)(conf, token, matches, data))
return (FALSE);
*matches = !*matches;
}
else if (OPT_SERV_SYM_EQ("or") || OPT_SERV_SYM_EQ("||"))
{
unsigned int depth = token->depth_num;
while (conf_token_list_num(token, depth))
{
int or_matches = TRUE;
CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
if (!(*tst_func)(conf, token, &or_matches, data))
return (FALSE);
if (or_matches)
{
conf_parse_end_token(conf, token, depth);
return (TRUE);
}
}
*matches = FALSE;
}
else if (OPT_SERV_SYM_EQ("and") || OPT_SERV_SYM_EQ("&&"))
{
unsigned int depth = token->depth_num;
while (conf_token_list_num(token, depth))
{
CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, depth, FALSE);
if (!(*tst_func)(conf, token, matches, data))
return (FALSE);
if (!*matches)
{
conf_parse_end_token(conf, token, depth);
return (TRUE);
}
}
}
else
return (FALSE);
return (TRUE);
}