diff options
Diffstat (limited to 'main/manager.c')
-rw-r--r-- | main/manager.c | 76 |
1 files changed, 57 insertions, 19 deletions
diff --git a/main/manager.c b/main/manager.c index d70ac6d15..c94e94ca2 100644 --- a/main/manager.c +++ b/main/manager.c @@ -80,6 +80,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astobj2.h" #include "asterisk/features.h" #include "asterisk/security_events.h" +#include "asterisk/event.h" #include "asterisk/aoc.h" #include "asterisk/stringfields.h" #include "asterisk/presencestate.h" @@ -990,7 +991,7 @@ static char global_realm[MAXHOSTNAMELEN]; /*!< Default realm */ static int block_sockets; static int unauth_sessions = 0; - +static struct ast_event_sub *acl_change_event_subscription; /*! \brief * Descriptor for a manager session, either on the AMI socket or over HTTP. @@ -1011,6 +1012,23 @@ static const struct { {{ "restart", "gracefully", NULL }}, }; +static void acl_change_event_cb(const struct ast_event *event, void *userdata); + +static void acl_change_event_subscribe(void) +{ + if (!acl_change_event_subscription) { + acl_change_event_subscription = ast_event_subscribe(AST_EVENT_ACL_CHANGE, + acl_change_event_cb, "Manager must react to Named ACL changes", NULL, AST_EVENT_IE_END); + } +} + +static void acl_change_event_unsubscribe(void) +{ + if (acl_change_event_subscription) { + acl_change_event_subscription = ast_event_unsubscribe(acl_change_event_subscription); + } +} + /* In order to understand what the heck is going on with the * mansession_session and mansession structs, we need to have a bit of a history * lesson. @@ -1110,7 +1128,6 @@ static AST_RWLIST_HEAD_STATIC(channelvars, manager_channel_variable); struct ast_manager_user { char username[80]; char *secret; /*!< Secret for logging in */ - struct ast_ha *ha; /*!< ACL setting */ int readperm; /*!< Authorization for reading */ int writeperm; /*!< Authorization for writing */ int writetimeout; /*!< Per user Timeout for ast_carefulwrite() */ @@ -1118,6 +1135,7 @@ struct ast_manager_user { int keep; /*!< mark entries created on a reload */ struct ao2_container *whitefilters; /*!< Manager event filters - white list */ struct ao2_container *blackfilters; /*!< Manager event filters - black list */ + struct ast_acl_list *acl; /*!< ACL setting */ char *a1_hash; /*!< precalculated A1 for Digest auth */ AST_RWLIST_ENTRY(ast_manager_user) list; }; @@ -1666,13 +1684,13 @@ static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli ast_cli(a->fd, " username: %s\n" " secret: %s\n" - " acl: %s\n" + " ACL: %s\n" " read perm: %s\n" " write perm: %s\n" "displayconnects: %s\n", (user->username ? user->username : "(N/A)"), (user->secret ? "<Set>" : "(N/A)"), - (user->ha ? "yes" : "no"), + ((user->acl && !ast_acl_list_is_empty(user->acl)) ? "yes" : "no"), authority_to_str(user->readperm, &rauthority), authority_to_str(user->writeperm, &wauthority), (user->displayconnects ? "yes" : "no")); @@ -2478,7 +2496,7 @@ static int authenticate(struct mansession *s, const struct message *m) if (!(user = get_manager_by_name_locked(username))) { report_invalid_user(s, username); ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username); - } else if (user->ha && !ast_apply_ha(user->ha, &s->session->addr)) { + } else if (user->acl && (ast_apply_acl(user->acl, &s->session->addr, "Manager User ACL: ") == AST_SENSE_DENY)) { report_failed_acl(s, username); ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username); } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) { @@ -6402,7 +6420,7 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser, } /* --- We have User for this auth, now check ACL */ - if (user->ha && !ast_apply_ha(user->ha, remote_address)) { + if (user->acl && !ast_apply_acl(user->acl, remote_address, "Manager User ACL:")) { AST_RWLIST_UNLOCK(&users); ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username); ast_http_error(ser, 403, "Permission denied", "Permission denied\n"); @@ -7070,7 +7088,7 @@ static void load_channelvars(struct ast_variable *var) AST_RWLIST_UNLOCK(&channelvars); } -static int __init_manager(int reload) +static int __init_manager(int reload, int by_external_config) { struct ast_config *ucfg = NULL, *cfg = NULL; #ifdef AST_XML_DOCS @@ -7081,12 +7099,13 @@ static int __init_manager(int reload) int newhttptimeout = 60; struct ast_manager_user *user = NULL; struct ast_variable *var; - struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; + struct ast_flags config_flags = { (reload && !by_external_config) ? CONFIG_FLAG_FILEUNCHANGED : 0 }; char a1[256]; char a1_hash[256]; struct ast_sockaddr ami_desc_local_address_tmp; struct ast_sockaddr amis_desc_local_address_tmp; int tls_was_enabled = 0; + int acl_subscription_flag = 0; manager_enabled = 0; @@ -7160,6 +7179,11 @@ static int __init_manager(int reload) return 0; } + /* If this wasn't performed due to a forced reload (because those can be created by ACL change events, we need to unsubscribe to ACL change events. */ + if (!by_external_config) { + acl_change_event_unsubscribe(); + } + /* default values */ ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm)); ast_sockaddr_setnull(&ami_desc.local_address); @@ -7310,7 +7334,7 @@ static int __init_manager(int reload) ast_copy_string(user->username, cat, sizeof(user->username)); /* Insert into list */ AST_LIST_INSERT_TAIL(&users, user, list); - user->ha = NULL; + user->acl = NULL; user->keep = 1; user->readperm = -1; user->writeperm = -1; @@ -7367,7 +7391,7 @@ static int __init_manager(int reload) /* cat is NULL here in any case */ while ((cat = ast_category_browse(cfg, cat))) { - struct ast_ha *oldha; + struct ast_acl_list *oldacl; if (!strcasecmp(cat, "general")) { continue; @@ -7381,7 +7405,7 @@ static int __init_manager(int reload) /* Copy name over */ ast_copy_string(user->username, cat, sizeof(user->username)); - user->ha = NULL; + user->acl = NULL; user->readperm = 0; user->writeperm = 0; /* Default displayconnect from [general] */ @@ -7399,8 +7423,8 @@ static int __init_manager(int reload) /* Make sure we keep this user and don't destroy it during cleanup */ user->keep = 1; - oldha = user->ha; - user->ha = NULL; + oldacl = user->acl; + user->acl = NULL; var = ast_variable_browse(cfg, cat); for (; var; var = var->next) { @@ -7410,8 +7434,9 @@ static int __init_manager(int reload) } user->secret = ast_strdup(var->value); } else if (!strcasecmp(var->name, "deny") || - !strcasecmp(var->name, "permit")) { - user->ha = ast_append_ha(var->name, var->value, user->ha, NULL); + !strcasecmp(var->name, "permit") || + !strcasecmp(var->name, "acl")) { + ast_append_acl(var->name, var->value, &user->acl, NULL, &acl_subscription_flag); } else if (!strcasecmp(var->name, "read") ) { user->readperm = get_perm(var->value); } else if (!strcasecmp(var->name, "write") ) { @@ -7432,10 +7457,16 @@ static int __init_manager(int reload) ast_debug(1, "%s is an unknown option.\n", var->name); } } - ast_free_ha(oldha); + + oldacl = ast_free_acl_list(oldacl); } ast_config_destroy(cfg); + /* Check the flag for named ACL event subscription and if we need to, register a subscription. */ + if (acl_subscription_flag && !by_external_config) { + acl_change_event_subscribe(); + } + /* Perform cleanup - essentially prune out old users that no longer exist */ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) { if (user->keep) { /* valid record. clear flag for the next round */ @@ -7464,7 +7495,7 @@ static int __init_manager(int reload) ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters"); ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one"); ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one"); - ast_free_ha(user->ha); + user->acl = ast_free_acl_list(user->acl); ast_free(user); } AST_RWLIST_TRAVERSE_SAFE_END; @@ -7516,6 +7547,13 @@ static int __init_manager(int reload) return 0; } +static void acl_change_event_cb(const struct ast_event *event, void *userdata) +{ + /* For now, this is going to be performed simply and just execute a forced reload. */ + ast_log(LOG_NOTICE, "Reloading manager in response to ACL change event.\n"); + __init_manager(1, 1); +} + /* clear out every entry in the channelvar list */ static void free_channelvars(void) { @@ -7529,12 +7567,12 @@ static void free_channelvars(void) int init_manager(void) { - return __init_manager(0); + return __init_manager(0, 0); } int reload_manager(void) { - return __init_manager(1); + return __init_manager(1, 0); } int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore) |