Change manager so that registered accounts are stored in memory. This opens for a
[asterisk/asterisk.git] / main / manager.c
index 4a7c594..d46ae37 100644 (file)
@@ -167,10 +167,10 @@ static AST_LIST_HEAD_STATIC(sessions, mansession);
 struct ast_manager_user {
        char username[80];
        char *secret;
-       char *deny;
-       char *permit;
-       char *read;
-       char *write;
+       struct ast_ha *ha;              /*!< ACL setting */
+       int readperm;                   /*! Authorization for reading */
+       int writeperm;                  /*! Authorization for writing */
+       int writetimeout;               /*! Per user Timeout for ast_carefulwrite() */
        int displayconnects;    /*!< XXX unused */
        int keep;       /*!< mark entries created on a reload */
        AST_RWLIST_ENTRY(ast_manager_user) list;
@@ -519,6 +519,9 @@ static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli
        struct ast_manager_user *user = NULL;
        int l, which;
        char *ret = NULL;
+       struct ast_str *rauthority = ast_str_alloca(80);
+       struct ast_str *wauthority = ast_str_alloca(80);
+
        switch (cmd) {
        case CLI_INIT:
                e->command = "manager show user";
@@ -557,17 +560,15 @@ static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli
        ast_cli(a->fd,
                "       username: %s\n"
                "         secret: %s\n"
-               "           deny: %s\n"
-               "         permit: %s\n"
-               "           read: %s\n"
-               "          write: %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->deny ? user->deny : "(N/A)"),
-               (user->permit ? user->permit : "(N/A)"),
-               (user->read ? user->read : "(N/A)"),
-               (user->write ? user->write : "(N/A)"),
+               (user->ha ? "yes" : "no"),
+               authority_to_str(user->readperm, &rauthority),
+               authority_to_str(user->writeperm, &wauthority),
                (user->displayconnects ? "yes" : "no"));
 
        AST_RWLIST_UNLOCK(&users);
@@ -956,118 +957,22 @@ static int set_eventmask(struct mansession *s, const char *eventmask)
 /* helper function for action_login() */
 static int authenticate(struct mansession *s, const struct message *m)
 {
-       const char *user = astman_get_header(m, "Username");
+       const char *username = astman_get_header(m, "Username");
+       const char *password = astman_get_header(m, "Secret");
        int error = -1;
-       struct ast_ha *ha = NULL;
-       char *password = NULL;
-       int readperm = 0, writeperm = 0;
-       struct ast_flags config_flags = { 0 };
-
-       if (ast_strlen_zero(user))      /* missing username */
-               return -1;
-
-    {
-       /*
-        * XXX there should be no need to scan the config file again here,
-        * suffices to call get_manager_by_name_locked() to fetch
-        * the user's entry.
-        */
-       struct ast_config *cfg = ast_config_load("manager.conf", config_flags);
-       char *cat = NULL;
-       struct ast_variable *v;
+       struct ast_manager_user *user = NULL;
 
-       if (!cfg)
+       if (ast_strlen_zero(username))  /* missing username */
                return -1;
-       while ( (cat = ast_category_browse(cfg, cat)) ) {
-               /* "general" is not a valid user */
-               if (strcasecmp(cat, user) || !strcasecmp(cat, "general"))
-                       continue;
-               /* collect parameters for the user's entry */
-               for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
-                       if (!strcasecmp(v->name, "secret"))
-                               password = ast_strdupa(v->value);
-                       else if (!strcasecmp(v->name, "read"))
-                               readperm = get_perm(v->value);
-                       else if (!strcasecmp(v->name, "write"))
-                               writeperm = get_perm(v->value);
-                       else if (!strcasecmp(v->name, "permit") ||
-                                  !strcasecmp(v->name, "deny")) {
-                               ha = ast_append_ha(v->name, v->value, ha, NULL);
-                       } else if (!strcasecmp(v->name, "writetimeout")) {
-                               int val = atoi(v->value);
-       
-                               if (val < 100)
-                                       ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
-                               else
-                                       s->writetimeout = val;
-                       }
-               }
-               break;
-       }
 
-       ast_config_destroy(cfg);
-       if (!cat) {
-               /* Didn't find the user in manager.conf, check users.conf */
-               int hasmanager = 0;
-               cfg = ast_config_load("users.conf", config_flags);
-               if (!cfg)
-                       return -1;
-               while ( (cat = ast_category_browse(cfg, cat)) ) {
-                       if (!strcasecmp(cat, user) && strcasecmp(cat, "general"))
-                               break;
-               }
-               if (!cat) {
-                       ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->sin.sin_addr), user);
-                       ast_config_destroy(cfg);
-                       return -1;
-               }
-               /* collect parameters for the user's entry from users.conf */
-               for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
-                       if (!strcasecmp(v->name, "secret"))
-                               password = ast_strdupa(v->value);
-                       else if (!strcasecmp(v->name, "read"))
-                               readperm = get_perm(v->value);
-                       else if (!strcasecmp(v->name, "write"))
-                               writeperm = get_perm(v->value);
-                       else if (!strcasecmp(v->name, "permit") ||
-                                  !strcasecmp(v->name, "deny")) {
-                               ha = ast_append_ha(v->name, v->value, ha, NULL);
-                       } else if (!strcasecmp(v->name, "writetimeout")) {
-                               int val = atoi(v->value);
-       
-                               if (val < 100)
-                                       ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
-                               else
-                                       s->writetimeout = val;
-                       } else if (!strcasecmp(v->name, "hasmanager"))
-                               hasmanager = ast_true(v->value);
-                       else if (!strcasecmp(v->name, "managerread"))
-                               readperm = get_perm(v->value);
-                       else if (!strcasecmp(v->name, "managerwrite"))
-                               writeperm = get_perm(v->value);
-               }
-               ast_config_destroy(cfg);
-               if (!hasmanager) {
-                       ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->sin.sin_addr), user);
-                       return -1;
-               }
-               if (!readperm)
-                       readperm = -1;
-               if (!writeperm)
-                       writeperm = -1;
-       }
-
-       }
+       /* locate user in locked state */
+       AST_RWLIST_WRLOCK(&users);
 
-       if (ha) {
-               int good = ast_apply_ha(ha, &(s->sin));
-               ast_free_ha(ha);
-               if (!good) {
-                       ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), user);
-                       return -1;
-               }
-       }
-       if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
+       if (!(user = get_manager_by_name_locked(username))) {
+               ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->sin.sin_addr), username);
+       } else if (user->ha && !ast_apply_ha(user->ha, &(s->sin))) {
+               ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), username);
+       } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
                const char *key = astman_get_header(m, "Key");
                if (!ast_strlen_zero(key) && !ast_strlen_zero(s->challenge) &&
                    !ast_strlen_zero(password)) {
@@ -1088,22 +993,26 @@ static int authenticate(struct mansession *s, const struct message *m)
                } else {
                        ast_debug(1, "MD5 authentication is not possible.  challenge: '%s'\n", 
                                S_OR(s->challenge, ""));
-                       return -1;
                }
-       } else if (password) {
-               const char *pass = astman_get_header(m, "Secret");
-               if (!strcmp(password, pass))
-                       error = 0;
-       }
+       } else if (password && user->secret && !strcmp(password, user->secret))
+               error = 0;
+
        if (error) {
-               ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), user);
+               ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), username);
+               AST_RWLIST_UNLOCK(&users);
                return -1;
        }
-       ast_copy_string(s->username, user, sizeof(s->username));
-       s->readperm = readperm;
-       s->writeperm = writeperm;
+
+       /* auth complete */
+       
+       ast_copy_string(s->username, username, sizeof(s->username));
+       s->readperm = user->readperm;
+       s->writeperm = user->writeperm;
+       s->writetimeout = user->writetimeout;
        s->sessionstart = time(NULL);
        set_eventmask(s, astman_get_header(m, "Events"));
+       
+       AST_RWLIST_UNLOCK(&users);
        return 0;
 }
 
@@ -3409,7 +3318,7 @@ static struct server_args amis_desc = {
 
 static int __init_manager(int reload)
 {
-       struct ast_config *cfg = NULL;
+       struct ast_config *ucfg = NULL, *cfg = NULL;
        const char *val;
        char *cat = NULL;
        int newhttptimeout = 60;
@@ -3461,7 +3370,7 @@ static int __init_manager(int reload)
 
        displayconnects = 1;
        if (!cfg) {
-               ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf.  Call management disabled.\n");
+               ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf. Asterisk management interface (AMI) disabled.\n");
                return 0;
        }
 
@@ -3537,7 +3446,83 @@ static int __init_manager(int reload)
        
        AST_RWLIST_WRLOCK(&users);
 
+       /* First, get users from users.conf */
+       ucfg = ast_config_load("users.conf", config_flags);
+       if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED)) {
+               const char *hasmanager;
+               int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
+
+               while ((cat = ast_category_browse(ucfg, cat))) {
+                       if (!strcasecmp(cat, "general"))
+                               continue;
+                       
+                       hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
+                       if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
+                               const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
+                               const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
+                               const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
+                               const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
+                               const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
+                               
+                               /* Look for an existing entry,
+                                * if none found - create one and add it to the list
+                                */
+                               if (!(user = get_manager_by_name_locked(cat))) {
+                                       if (!(user = ast_calloc(1, sizeof(*user))))
+                                               break;
+
+                                       /* Copy name over */
+                                       ast_copy_string(user->username, cat, sizeof(user->username));
+                                       /* Insert into list */
+                                       AST_LIST_INSERT_TAIL(&users, user, list);
+                                       user->ha = NULL;
+                                       user->readperm = -1;
+                                       user->writeperm = -1;
+                                       /* Default displayconnect from [general] */
+                                       user->displayconnects = displayconnects;
+                                       user->writetimeout = 100;
+                               }
+
+                               if (!user_secret)
+                                       user_secret = ast_variable_retrieve(ucfg, "general", "secret");
+                               if (!user_read)
+                                       user_read = ast_variable_retrieve(ucfg, "general", "read");
+                               if (!user_write)
+                                       user_write = ast_variable_retrieve(ucfg, "general", "write");
+                               if (!user_displayconnects)
+                                       user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
+                               if (!user_writetimeout)
+                                       user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
+
+                               if (!ast_strlen_zero(user_secret)) {
+                                       if (user->secret)
+                                               ast_free(user->secret);
+                                       user->secret = ast_strdup(user_secret);
+                               }
+
+                               if (user_read)
+                                       user->readperm = get_perm(user_read);
+                               if (user_write)
+                                       user->writeperm = get_perm(user_write);
+                               if (user_displayconnects)
+                                       user->displayconnects = ast_true(user_displayconnects);
+
+                               if (user_writetimeout) {
+                                       int val = atoi(user_writetimeout);
+                                       if (val < 100)
+                                               ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at users.conf line %d\n", var->value, var->lineno);
+                                       else
+                                               user->writetimeout = val;
+                               }
+                       }
+               }
+               ast_config_destroy(ucfg);
+       }
+
+       /* cat is NULL here in any case */
+
        while ((cat = ast_category_browse(cfg, cat))) {
+               struct ast_ha *oldha;
 
                if (!strcasecmp(cat, "general"))
                        continue;
@@ -3548,45 +3533,50 @@ static int __init_manager(int reload)
                                break;
                        /* Copy name over */
                        ast_copy_string(user->username, cat, sizeof(user->username));
+
+                       user->ha = NULL;
+                       user->readperm = 0;
+                       user->writeperm = 0;
+                       /* Default displayconnect from [general] */
+                       user->displayconnects = displayconnects;
+                       user->writetimeout = 100;
+
                        /* Insert into list */
                        AST_RWLIST_INSERT_TAIL(&users, user, list);
                }
 
                /* Make sure we keep this user and don't destroy it during cleanup */
                user->keep = 1;
-               /* Default displayconnect to [general] */
-               user->displayconnects = displayconnects;
+               oldha = user->ha;
+               user->ha = NULL;
 
                var = ast_variable_browse(cfg, cat);
-               while (var) {
+               for (; var; var = var->next) {
                        if (!strcasecmp(var->name, "secret")) {
                                if (user->secret)
                                        ast_free(user->secret);
                                user->secret = ast_strdup(var->value);
-                       } else if (!strcasecmp(var->name, "deny") ) {
-                               if (user->deny)
-                                       ast_free(user->deny);
-                               user->deny = ast_strdup(var->value);
-                       } else if (!strcasecmp(var->name, "permit") ) {
-                               if (user->permit)
-                                       ast_free(user->permit);
-                               user->permit = 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);
                        }  else if (!strcasecmp(var->name, "read") ) {
-                               if (user->read)
-                                       ast_free(user->read);
-                               user->read = ast_strdup(var->value);
+                               user->readperm = get_perm(var->value);
                        }  else if (!strcasecmp(var->name, "write") ) {
-                               if (user->write)
-                                       ast_free(user->write);
-                               user->write = ast_strdup(var->value);
-                       }  else if (!strcasecmp(var->name, "displayconnects") )
+                               user->writeperm = get_perm(var->value);
+                       }  else if (!strcasecmp(var->name, "displayconnects") ) {
                                user->displayconnects = ast_true(var->value);
-                       else {
+                       } else if (!strcasecmp(var->name, "writetimeout")) {
+                               int val = atoi(var->value);
+                               if (val < 100)
+                                       ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
+                               else
+                                       user->writetimeout = val;
+                       } else
                                ast_debug(1, "%s is an unknown option.\n", var->name);
-                       }
-                       var = var->next;
                }
+               ast_free_ha(oldha);
        }
+       ast_config_destroy(cfg);
 
        /* Perform cleanup - essentially prune out old users that no longer exist */
        AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
@@ -3599,22 +3589,13 @@ static int __init_manager(int reload)
                /* Free their memory now */
                if (user->secret)
                        ast_free(user->secret);
-               if (user->deny)
-                       ast_free(user->deny);
-               if (user->permit)
-                       ast_free(user->permit);
-               if (user->read)
-                       ast_free(user->read);
-               if (user->write)
-                       ast_free(user->write);
+               ast_free_ha(user->ha);
                ast_free(user);
        }
        AST_RWLIST_TRAVERSE_SAFE_END;
 
        AST_RWLIST_UNLOCK(&users);
 
-       ast_config_destroy(cfg);
-
        if (webmanager_enabled && manager_enabled) {
                if (!webregged) {
                        ast_http_uri_link(&rawmanuri);