acl.c 2.95 KB
Newer Older
1
/*  Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

17
#include "knot/updates/acl.h"
18

19
bool acl_allowed(conf_t *conf, conf_val_t *acl, acl_action_t action,
20
                 const struct sockaddr_storage *addr, knot_tsig_key_t *tsig)
21
{
22
	if (acl == NULL || addr == NULL || tsig == NULL) {
23
		return NULL;
24 25
	}

26
	while (acl->code == KNOT_EOK) {
27
		/* Check if the address matches the current acl address list. */
28 29
		conf_val_t val = conf_id_get(conf, C_ACL, C_ADDR, acl);
		if (val.code != KNOT_ENOENT && !conf_addr_range_match(&val, addr)) {
30
			goto next_acl;
31
		}
32

33
		/* Check if the key matches the current acl key list. */
34
		conf_val_t key_val = conf_id_get(conf, C_ACL, C_KEY, acl);
35
		while (key_val.code == KNOT_EOK) {
36 37
			/* No key provided, but required. */
			if (tsig->name == NULL) {
38
				conf_val_next(&key_val);
Marek Vavrusa's avatar
Marek Vavrusa committed
39 40 41
				continue;
			}

42
			/* Compare key names (both in lower-case). */
43
			const knot_dname_t *key_name = conf_dname(&key_val);
44
			if (!knot_dname_is_equal(key_name, tsig->name)) {
45
				conf_val_next(&key_val);
46
				continue;
47
			}
48 49

			/* Compare key algorithms. */
50
			conf_val_t alg_val = conf_id_get(conf, C_KEY, C_ALG,
51 52
			                                 &key_val);
			if (conf_opt(&alg_val) != tsig->algorithm) {
53
				conf_val_next(&key_val);
54 55
				continue;
			}
56 57 58 59 60 61 62

			break;
		}
		/* Check for key match or empty list without key provided. */
		if (key_val.code != KNOT_EOK &&
		    !(key_val.code == KNOT_ENOENT && tsig->name == NULL)) {
			goto next_acl;
63 64
		}

65
		/* Check if the action is allowed. */
66
		if (action != ACL_ACTION_NONE) {
67
			val = conf_id_get(conf, C_ACL, C_ACTION, acl);
68 69 70 71 72
			while (val.code == KNOT_EOK) {
				if (conf_opt(&val) != action) {
					conf_val_next(&val);
					continue;
				}
73

74 75
				break;
			}
76 77 78 79 80 81
			switch (val.code) {
			case KNOT_EOK: /* Check for action match. */
				break;
			case KNOT_ENOENT: /* Empty action list allowed with deny only. */
				return false;
			default: /* No match. */
82 83
				goto next_acl;
			}
84 85 86
		}

		/* Check if denied. */
87
		val = conf_id_get(conf, C_ACL, C_DENY, acl);
88 89
		if (conf_bool(&val)) {
			return false;
90
		}
91

92
		/* Fill the output with tsig secret if provided. */
93
		if (tsig->name != NULL) {
94
			val = conf_id_get(conf, C_KEY, C_SECRET, &key_val);
95
			tsig->secret.data = (uint8_t *)conf_bin(&val, &tsig->secret.size);
96 97 98
		}

		return true;
99 100
next_acl:
		conf_val_next(acl);
101 102
	}

103
	return false;
104
}