summaryrefslogtreecommitdiff
path: root/main/acl.c
diff options
context:
space:
mode:
authorJonathan Rose <jrose@digium.com>2012-07-11 18:33:36 +0000
committerJonathan Rose <jrose@digium.com>2012-07-11 18:33:36 +0000
commit10afdf3a2abd7e45d5c1841b29744de5b852d722 (patch)
treeefd6960cc2e8a9f2642d8ac950904ba6c51371e9 /main/acl.c
parent6190ae4430f2bdfb02d2ce8f4941cd9b4e65f5a0 (diff)
Named ACLs: Introduces a system for creating and sharing ACLs
This patch adds Named ACL functionality to Asterisk. This allows system administrators to define an ACL and refer to it by a unique name. Configurable items can then refer to that name when specifying access control lists. It also includes updates to all core supported consumers of ACLs. That includes manager, chan_sip, and chan_iax2. This feature is based on the deluxepine-trunk by Olle E. Johansson and provides a subset of the Named ACL functionality implemented in that branch. For more information on this feature, see acl.conf and/or the Asterisk wiki. Review: https://reviewboard.asterisk.org/r/1978/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@369959 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/acl.c')
-rw-r--r--main/acl.c244
1 files changed, 240 insertions, 4 deletions
diff --git a/main/acl.c b/main/acl.c
index e27ed0cc0..4b14ac575 100644
--- a/main/acl.c
+++ b/main/acl.c
@@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 1999 - 2006, Digium, Inc.
+ * Copyright (C) 1999 - 2012, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
@@ -230,6 +230,28 @@ void ast_free_ha(struct ast_ha *ha)
}
}
+/* Free ACL list structure */
+struct ast_acl_list *ast_free_acl_list(struct ast_acl_list *acl_list)
+{
+ struct ast_acl *current;
+
+ if (!acl_list) {
+ return NULL;
+ }
+
+ AST_LIST_LOCK(acl_list);
+ while ((current = AST_LIST_REMOVE_HEAD(acl_list, list))) {
+ ast_free_ha(current->acl);
+ ast_free(current);
+ }
+ AST_LIST_UNLOCK(acl_list);
+
+ AST_LIST_HEAD_DESTROY(acl_list);
+ ast_free(acl_list);
+
+ return NULL;
+}
+
/* Copy HA structure */
void ast_copy_ha(const struct ast_ha *from, struct ast_ha *to)
{
@@ -275,6 +297,56 @@ struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
return ret; /* Return start of list */
}
+static int acl_new(struct ast_acl **pointer, const char *name) {
+ struct ast_acl *acl;
+ if (!(acl = ast_calloc(1, sizeof(*acl)))) {
+ return 1;
+ }
+
+ *pointer = acl;
+ ast_copy_string(acl->name, name, ACL_NAME_LENGTH);
+ return 0;
+}
+
+struct ast_acl_list *ast_duplicate_acl_list(struct ast_acl_list *original)
+{
+ struct ast_acl_list *clone;
+ struct ast_acl *current_cursor;
+ struct ast_acl *current_clone;
+
+ /* Early return if we receive a duplication request for a NULL original. */
+ if (!original) {
+ return NULL;
+ }
+
+ if (!(clone = ast_calloc(1, sizeof(*clone)))) {
+ ast_log(LOG_WARNING, "Failed to allocate ast_acl_list struct while cloning an ACL\n");
+ return NULL;
+ }
+ AST_LIST_HEAD_INIT(clone);
+
+ AST_LIST_LOCK(original);
+
+ AST_LIST_TRAVERSE(original, current_cursor, list) {
+ if ((acl_new(&current_clone, current_cursor->name))) {
+ ast_log(LOG_WARNING, "Failed to allocate ast_acl struct while cloning an ACL.");
+ continue;
+ }
+
+ /* Copy data from original ACL to clone ACL */
+ current_clone->acl = ast_duplicate_ha_list(current_cursor->acl);
+
+ current_clone->is_invalid = current_cursor->is_invalid;
+ current_clone->is_realtime = current_cursor->is_realtime;
+
+ AST_LIST_INSERT_TAIL(clone, current_clone, list);
+ }
+
+ AST_LIST_UNLOCK(original);
+
+ return clone;
+}
+
/*!
* \brief
* Isolate a 32-bit section of an IPv6 address
@@ -396,6 +468,135 @@ static int parse_cidr_mask(struct ast_sockaddr *addr, int is_v4, const char *mas
return 0;
}
+
+
+void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag)
+{
+ struct ast_acl *acl = NULL;
+ struct ast_acl *current;
+ struct ast_acl_list *working_list;
+
+ char *tmp, *list;
+
+ /* If the ACL list is currently uninitialized, it must be initialized. */
+ if (*path == NULL) {
+ struct ast_acl_list *list;
+ list = ast_calloc(1, sizeof(*list));
+ if (!list) {
+ /* Allocation Error */
+ if (error) {
+ *error = 1;
+ }
+ return;
+ }
+
+ AST_LIST_HEAD_INIT(list);
+ *path = list;
+ }
+
+ working_list = *path;
+
+ AST_LIST_LOCK(working_list);
+
+ /* First we need to determine if we will need to add a new ACL node or if we can use an existing one. */
+ if (strncasecmp(sense, "a", 1)) {
+ /* The first element in the path should be the unnamed, base ACL. If that's the case, we use it. If not,
+ * we have to make one and link it up appropriately. */
+ current = AST_LIST_FIRST(working_list);
+
+ if (!current || !ast_strlen_zero(current->name)) {
+ if (acl_new(&acl, "")) {
+ if (error) {
+ *error = 1;
+ }
+ }
+ // Need to INSERT the ACL at the head here.
+ AST_LIST_INSERT_HEAD(working_list, acl, list);
+ } else {
+ /* If the first element was already the unnamed base ACL, we just use that one. */
+ acl = current;
+ }
+
+ /* With the proper ACL set for modification, we can just pass this off to the ast_ha append function. */
+ acl->acl = ast_append_ha(sense, stuff, acl->acl, error);
+
+ AST_LIST_UNLOCK(working_list);
+ return;
+ }
+
+ /* We are in ACL append mode, so we know we'll be adding one or more named ACLs. */
+ list = ast_strdupa(stuff);
+
+ while ((tmp = strsep(&list, ","))) {
+ struct ast_ha *named_ha;
+ int already_included = 0;
+
+ /* Remove leading whitespace from the string in case the user put spaces between items */
+ tmp = ast_skip_blanks(tmp);
+
+ /* The first step is to check for a duplicate */
+ AST_LIST_TRAVERSE(working_list, current, list) {
+ if (!strcasecmp(current->name, tmp)) { /* ACL= */
+ /* Inclusion of the same ACL multiple times isn't a catastrophic error, but it will raise the error flag and skip the entry. */
+ ast_log(LOG_ERROR, "Named ACL '%s' is already included in the ast_acl container.", tmp);
+ if (error) {
+ *error = 1;
+ }
+ already_included = 1;
+ break;
+ }
+ }
+
+ if (already_included) {
+ continue;
+ }
+
+ if (acl_new(&acl, tmp)) {
+ /* This is a catastrophic allocation error and we'll return immediately if this happens. */
+ if (error) {
+ *error = 1;
+ }
+ AST_LIST_UNLOCK(working_list);
+ return;
+ }
+
+ /* Attempt to grab the Named ACL we are looking for. */
+ named_ha = ast_named_acl_find(tmp, &acl->is_realtime, &acl->is_invalid);
+
+ /* Set the ACL's ast_ha to the duplicated named ACL retrieved above. */
+ acl->acl = named_ha;
+
+ /* Raise the named_acl_flag since we are adding a named ACL to the ACL container. */
+ if (named_acl_flag) {
+ *named_acl_flag = 1;
+ }
+
+ /* Now insert the new ACL at the end of the list. */
+ AST_LIST_INSERT_TAIL(working_list, acl, list);
+ }
+
+ AST_LIST_UNLOCK(working_list);
+}
+
+int ast_acl_list_is_empty(struct ast_acl_list *acl_list)
+{
+ struct ast_acl *head;
+
+ if (!acl_list) {
+ return 1;
+ }
+
+ AST_LIST_LOCK(acl_list);
+ head = AST_LIST_FIRST(acl_list);
+ AST_LIST_UNLOCK(acl_list);
+
+ if (head) {
+ return 0;
+ }
+
+ return 1;
+}
+
struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error)
{
struct ast_ha *ha;
@@ -509,16 +710,51 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
const char *addr = ast_strdupa(ast_sockaddr_stringify(&ha->addr));
const char *mask = ast_strdupa(ast_sockaddr_stringify(&ha->netmask));
- ast_debug(1, "%s/%s sense %d appended to acl for peer\n", addr, mask, ha->sense);
+ ast_debug(3, "%s/%s sense %d appended to acl\n", addr, mask, ha->sense);
}
return ret;
}
-int ast_apply_ha(const struct ast_ha *ha, const struct ast_sockaddr *addr)
+enum ast_acl_sense ast_apply_acl(struct ast_acl_list *acl_list, const struct ast_sockaddr *addr, const char *purpose)
+{
+ struct ast_acl *acl;
+
+ /* If the list is NULL, there are no rules, so we'll allow automatically. */
+ if (!acl_list) {
+ return AST_SENSE_ALLOW;
+ }
+
+ AST_LIST_LOCK(acl_list);
+
+ AST_LIST_TRAVERSE(acl_list, acl, list) {
+ if (acl->is_invalid) {
+ /* In this case, the baseline ACL shouldn't ever trigger this, but if that somehow happens, it'll still be shown. */
+ ast_log(LOG_WARNING, "%sRejecting '%s' due to use of an invalid ACL '%s'.\n", purpose ? purpose : "", ast_sockaddr_stringify_addr(addr),
+ ast_strlen_zero(acl->name) ? "(BASELINE)" : acl->name);
+ AST_LIST_UNLOCK(acl_list);
+ return AST_SENSE_DENY;
+ }
+
+ if (acl->acl) {
+ if (ast_apply_ha(acl->acl, addr) == AST_SENSE_DENY) {
+ ast_log(LOG_NOTICE, "%sRejecting '%s' due to a failure to pass ACL '%s'\n", purpose ? purpose : "", ast_sockaddr_stringify_addr(addr),
+ ast_strlen_zero(acl->name) ? "(BASELINE)" : acl->name);
+ AST_LIST_UNLOCK(acl_list);
+ return AST_SENSE_DENY;
+ }
+ }
+ }
+
+ AST_LIST_UNLOCK(acl_list);
+
+ return AST_SENSE_ALLOW;
+}
+
+enum ast_acl_sense ast_apply_ha(const struct ast_ha *ha, const struct ast_sockaddr *addr)
{
/* Start optimistic */
- int res = AST_SENSE_ALLOW;
+ enum ast_acl_sense res = AST_SENSE_ALLOW;
const struct ast_ha *current_ha;
for (current_ha = ha; current_ha; current_ha = current_ha->next) {