Commit df790bbf authored by Libor Peltan's avatar Libor Peltan Committed by Daniel Salzman

conf: allow configuring acl with a remote

parent cf5788cf
......@@ -652,6 +652,26 @@ struct sockaddr_storage conf_addr(
return out;
}
bool conf_addr_match(
conf_val_t *match,
const struct sockaddr_storage *addr)
{
if (match == NULL || addr == NULL) {
return false;
}
while (match->code == KNOT_EOK) {
struct sockaddr_storage maddr = conf_addr(match, NULL);
if (sockaddr_cmp(&maddr, addr, true) == 0) {
return true;
}
conf_val_next(match);
}
return false;
}
struct sockaddr_storage conf_addr_range(
conf_val_t *val,
struct sockaddr_storage *max_ss,
......
......@@ -489,6 +489,19 @@ struct sockaddr_storage conf_addr(
const char *sock_base_dir
);
/*!
* Checks the configured address if equal to given one (except port).
*
* \param[in] match Configured address.
* \param[in] addr Address to check.
*
* \return True if matches.
*/
bool conf_addr_match(
conf_val_t *match,
const struct sockaddr_storage *addr
);
/*!
* Gets the socket address range value of the item.
*
......
......@@ -254,6 +254,7 @@ static const yp_item_t desc_acl[] = {
{ C_ID, YP_TSTR, YP_VNONE, CONF_IO_FREF },
{ C_ADDR, YP_TNET, YP_VNONE, YP_FMULTI },
{ C_KEY, YP_TREF, YP_VREF = { C_KEY }, YP_FMULTI, { check_ref } },
{ C_RMT, YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI, { check_ref } },
{ C_ACTION, YP_TOPT, YP_VOPT = { acl_actions, ACL_ACTION_NONE }, YP_FMULTI },
{ C_DENY, YP_TBOOL, YP_VNONE },
{ C_UPDATE_OWNER, YP_TOPT, YP_VOPT = { acl_update_owner, ACL_UPDATE_OWNER_NONE } },
......@@ -405,8 +406,8 @@ const yp_item_t conf_schema[] = {
{ C_DB, YP_TGRP, YP_VGRP = { desc_database }, CONF_IO_FRLD_SRV },
{ C_KEYSTORE, YP_TGRP, YP_VGRP = { desc_keystore }, YP_FMULTI, { check_keystore } },
{ C_KEY, YP_TGRP, YP_VGRP = { desc_key }, YP_FMULTI, { check_key } },
{ C_ACL, YP_TGRP, YP_VGRP = { desc_acl }, YP_FMULTI, { check_acl } },
{ C_RMT, YP_TGRP, YP_VGRP = { desc_remote }, YP_FMULTI, { check_remote } },
{ C_ACL, YP_TGRP, YP_VGRP = { desc_acl }, YP_FMULTI, { check_acl } },
{ C_SBM, YP_TGRP, YP_VGRP = { desc_submission }, YP_FMULTI },
{ C_POLICY, YP_TGRP, YP_VGRP = { desc_policy }, YP_FMULTI, { check_policy } },
{ C_TPL, YP_TGRP, YP_VGRP = { desc_template }, YP_FMULTI, { check_template } },
......
......@@ -520,6 +520,18 @@ int check_acl(
return KNOT_EINVAL;
}
conf_val_t addr = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_ACL,
C_ADDR, args->id, args->id_len);
conf_val_t key = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_ACL,
C_KEY, args->id, args->id_len);
conf_val_t remote = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_ACL,
C_RMT, args->id, args->id_len);
if (remote.code != KNOT_ENOENT &&
(addr.code != KNOT_ENOENT || key.code != KNOT_ENOENT)) {
args->err_str = "specified ACL/remote together with address or key";
return KNOT_EINVAL;
}
return KNOT_EOK;
}
......
......@@ -154,6 +154,62 @@ static bool update_match(conf_t *conf, conf_val_t *acl, knot_dname_t *key_name,
return true;
}
static bool check_addr_key(conf_t *conf, conf_val_t *addr_val, conf_val_t *key_val,
bool remote, const struct sockaddr_storage *addr,
const knot_tsig_key_t *tsig)
{
/* Check if the address matches the acl address list or remote addresses. */
if (addr_val->code != KNOT_ENOENT) {
if (remote) {
if (!conf_addr_match(addr_val, addr)) {
return false;
}
} else {
if (!conf_addr_range_match(addr_val, addr)) {
return false;
}
}
}
/* Check if the key matches the acl key list or remote key. */
while (key_val->code == KNOT_EOK) {
/* No key provided, but required. */
if (tsig->name == NULL) {
goto next_key;
}
/* Compare key names (both in lower-case). */
const knot_dname_t *key_name = conf_dname(key_val);
if (!knot_dname_is_equal(key_name, tsig->name)) {
goto next_key;
}
/* Compare key algorithms. */
conf_val_t alg_val = conf_id_get(conf, C_KEY, C_ALG, key_val);
if (conf_opt(&alg_val) != tsig->algorithm) {
goto next_key;
}
break;
next_key:
if (remote) {
assert(!(key_val->item->flags & YP_FMULTI));
key_val->code = KNOT_EOF;
break;
} else {
assert(key_val->item->flags & YP_FMULTI);
conf_val_next(key_val);
}
}
/* Check for key match or empty list without key provided. */
if (key_val->code != KNOT_EOK &&
!(key_val->code == KNOT_ENOENT && tsig->name == NULL)) {
return false;
}
return true;
}
bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action,
const struct sockaddr_storage *addr, knot_tsig_key_t *tsig,
const knot_dname_t *zone_name, knot_pkt_t *query)
......@@ -163,47 +219,34 @@ bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action,
}
while (acl->code == KNOT_EOK) {
/* Check if the address matches the current acl address list. */
conf_val_t val = conf_id_get(conf, C_ACL, C_ADDR, acl);
if (val.code != KNOT_ENOENT && !conf_addr_range_match(&val, addr)) {
goto next_acl;
}
/* Check if the key matches the current acl key list. */
conf_val_t key_val = conf_id_get(conf, C_ACL, C_KEY, acl);
while (key_val.code == KNOT_EOK) {
/* No key provided, but required. */
if (tsig->name == NULL) {
conf_val_next(&key_val);
continue;
}
/* Compare key names (both in lower-case). */
const knot_dname_t *key_name = conf_dname(&key_val);
if (!knot_dname_is_equal(key_name, tsig->name)) {
conf_val_next(&key_val);
continue;
}
/* Compare key algorithms. */
conf_val_t alg_val = conf_id_get(conf, C_KEY, C_ALG,
&key_val);
if (conf_opt(&alg_val) != tsig->algorithm) {
conf_val_next(&key_val);
continue;
conf_val_t rmt_val = conf_id_get(conf, C_ACL, C_RMT, acl);
bool remote = (rmt_val.code == KNOT_EOK);
/* Check if a remote matches given address and key. */
conf_val_t addr_val, key_val;
while (rmt_val.code == KNOT_EOK) {
addr_val = conf_id_get(conf, C_RMT, C_ADDR, &rmt_val);
key_val = conf_id_get(conf, C_RMT, C_KEY, &rmt_val);
if (check_addr_key(conf, &addr_val, &key_val, remote, addr, tsig)) {
break;
}
break;
conf_val_next(&rmt_val);
}
/* Check for key match or empty list without key provided. */
if (key_val.code != KNOT_EOK &&
!(key_val.code == KNOT_ENOENT && tsig->name == NULL)) {
if (rmt_val.code == KNOT_EOF) {
goto next_acl;
}
/* Or check if acl address/key matches given address and key. */
if (!remote) {
addr_val = conf_id_get(conf, C_ACL, C_ADDR, acl);
key_val = conf_id_get(conf, C_ACL, C_KEY, acl);
if (!check_addr_key(conf, &addr_val, &key_val, remote, addr, tsig)) {
goto next_acl;
}
}
/* Check if the action is allowed. */
if (action != ACL_ACTION_NONE) {
val = conf_id_get(conf, C_ACL, C_ACTION, acl);
conf_val_t val = conf_id_get(conf, C_ACL, C_ACTION, acl);
while (val.code == KNOT_EOK) {
if (conf_opt(&val) != action) {
conf_val_next(&val);
......@@ -229,7 +272,7 @@ bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action,
}
/* Check if denied. */
val = conf_id_get(conf, C_ACL, C_DENY, acl);
conf_val_t val = conf_id_get(conf, C_ACL, C_DENY, acl);
if (conf_bool(&val)) {
return false;
}
......
......@@ -93,10 +93,17 @@ static void test_acl_allowed(void)
" algorithm: hmac-sha256\n"
" secret: Zm8=\n"
"\n"
"remote:\n"
" - id: remote_v6_ko\n"
" address: [ 2009::1 ]\n"
" key: key1_md5\n"
" - id: remote_v6_ok\n"
" address: [ 127.0.0.1, 2001::1 ]\n"
" key: key1_md5\n"
"\n"
"acl:\n"
" - id: acl_key_addr\n"
" address: [ 2001::1 ]\n"
" key: [ key1_md5 ]\n"
" remote: [ remote_v6_ko, remote_v6_ok ]\n"
" action: [ transfer ]\n"
" - id: acl_deny\n"
" address: [ 240.0.0.2 ]\n"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment