Change manager so that registered accounts are stored in memory. This opens for a

manager realtime implementation.

If you change accounts in manager.conf, you now need to reload to activate the
changes (deletions, additions). This was not the case with 1.4.

Reported by: ys
Patches: 
      trunk93163_manager_reload.c.diff uploaded by ys (license 281)
(closes issue #11414)


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@93165 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Olle Johansson
2007-12-16 13:32:48 +00:00
parent df17bc73f0
commit 130fe4000a
2 changed files with 152 additions and 166 deletions

13
CHANGES
View File

@@ -11,7 +11,7 @@ AMI - The manager (TCP/TLS/HTTP)
* Added the URI redirect option for the built-in HTTP server * Added the URI redirect option for the built-in HTTP server
* The output of CallerID in Manager events is now more consistent. * The output of CallerID in Manager events is now more consistent.
CallerIDNum is used for number and CallerIDName for name. CallerIDNum is used for number and CallerIDName for name.
* enable https support for builtin web server. * Enable https support for builtin web server.
See configs/http.conf.sample for details. See configs/http.conf.sample for details.
* Added a new action, GetConfigJSON, which can return the contents of an * Added a new action, GetConfigJSON, which can return the contents of an
Asterisk configuration file in JSON format. This is intended to help Asterisk configuration file in JSON format. This is intended to help
@@ -27,6 +27,10 @@ AMI - The manager (TCP/TLS/HTTP)
* Added 'DBDel' and 'DBDelTree' manager commands. * Added 'DBDel' and 'DBDelTree' manager commands.
* cdr_manager now reports events via the "cdr" level, separating it from * cdr_manager now reports events via the "cdr" level, separating it from
the very verbose "call" level. the very verbose "call" level.
* Manager users are now stored in memory. If you change the manager account
list (delete or add accounts) you need to reload manager.
* Added Masquerade manager event for when a masquerade happens between
two channels.
Dialplan functions Dialplan functions
------------------ ------------------
@@ -112,6 +116,10 @@ IAX2 changes
* Added support for OSP. The token is set and retrieved through the CHANNEL() * Added support for OSP. The token is set and retrieved through the CHANNEL()
dialplan function. dialplan function.
XMPP Google Talk/Jingle changes
-------------------------------
* Added the bindaddr option to gtalk.conf.
Skinny changes Skinny changes
------------- -------------
* Added skinny show device, skinny show line, and skinny show settings CLI commands. * Added skinny show device, skinny show line, and skinny show settings CLI commands.
@@ -337,7 +345,6 @@ AGI Changes
Miscellaneous Miscellaneous
------------- -------------
* Added the bindaddr option to gtalk.conf.
* Ability to use libcap to set high ToS bits when non-root * Ability to use libcap to set high ToS bits when non-root
on Linux. If configure is unable to find libcap then you on Linux. If configure is unable to find libcap then you
can use --with-cap to specify the path. can use --with-cap to specify the path.
@@ -349,8 +356,6 @@ Miscellaneous
command to be run after rotation. This is primarily useful with command to be run after rotation. This is primarily useful with
rotatestrategry=rotate, to allow a limit on the number of logfiles kept rotatestrategry=rotate, to allow a limit on the number of logfiles kept
and to ensure that the oldest log file gets deleted. and to ensure that the oldest log file gets deleted.
* Added Masquerade manager event for when a masquerade happens between
two channels.
* Added maxfiles option to options section of asterisk.conf which allows you to specify * Added maxfiles option to options section of asterisk.conf which allows you to specify
what Asterisk should set as the maximum number of open files when it loads. what Asterisk should set as the maximum number of open files when it loads.
* Added the jittertargetextra configuration option. * Added the jittertargetextra configuration option.

View File

@@ -167,10 +167,10 @@ static AST_LIST_HEAD_STATIC(sessions, mansession);
struct ast_manager_user { struct ast_manager_user {
char username[80]; char username[80];
char *secret; char *secret;
char *deny; struct ast_ha *ha; /*!< ACL setting */
char *permit; int readperm; /*! Authorization for reading */
char *read; int writeperm; /*! Authorization for writing */
char *write; int writetimeout; /*! Per user Timeout for ast_carefulwrite() */
int displayconnects; /*!< XXX unused */ int displayconnects; /*!< XXX unused */
int keep; /*!< mark entries created on a reload */ int keep; /*!< mark entries created on a reload */
AST_RWLIST_ENTRY(ast_manager_user) list; 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; struct ast_manager_user *user = NULL;
int l, which; int l, which;
char *ret = NULL; char *ret = NULL;
struct ast_str *rauthority = ast_str_alloca(80);
struct ast_str *wauthority = ast_str_alloca(80);
switch (cmd) { switch (cmd) {
case CLI_INIT: case CLI_INIT:
e->command = "manager show user"; 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, ast_cli(a->fd,
" username: %s\n" " username: %s\n"
" secret: %s\n" " secret: %s\n"
" deny: %s\n" " acl: %s\n"
" permit: %s\n" " read perm: %s\n"
" read: %s\n" " write perm: %s\n"
" write: %s\n"
"displayconnects: %s\n", "displayconnects: %s\n",
(user->username ? user->username : "(N/A)"), (user->username ? user->username : "(N/A)"),
(user->secret ? "<Set>" : "(N/A)"), (user->secret ? "<Set>" : "(N/A)"),
(user->deny ? user->deny : "(N/A)"), (user->ha ? "yes" : "no"),
(user->permit ? user->permit : "(N/A)"), authority_to_str(user->readperm, &rauthority),
(user->read ? user->read : "(N/A)"), authority_to_str(user->writeperm, &wauthority),
(user->write ? user->write : "(N/A)"),
(user->displayconnects ? "yes" : "no")); (user->displayconnects ? "yes" : "no"));
AST_RWLIST_UNLOCK(&users); AST_RWLIST_UNLOCK(&users);
@@ -956,118 +957,22 @@ static int set_eventmask(struct mansession *s, const char *eventmask)
/* helper function for action_login() */ /* helper function for action_login() */
static int authenticate(struct mansession *s, const struct message *m) 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; int error = -1;
struct ast_ha *ha = NULL; struct ast_manager_user *user = NULL;
char *password = NULL;
int readperm = 0, writeperm = 0;
struct ast_flags config_flags = { 0 };
if (ast_strlen_zero(user)) /* missing username */ if (ast_strlen_zero(username)) /* missing username */
return -1; return -1;
{ /* locate user in locked state */
/* AST_RWLIST_WRLOCK(&users);
* 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;
if (!cfg) if (!(user = get_manager_by_name_locked(username))) {
return -1; ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->sin.sin_addr), username);
while ( (cat = ast_category_browse(cfg, cat)) ) { } else if (user->ha && !ast_apply_ha(user->ha, &(s->sin))) {
/* "general" is not a valid user */ ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), username);
if (strcasecmp(cat, user) || !strcasecmp(cat, "general")) } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
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;
}
}
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")) {
const char *key = astman_get_header(m, "Key"); const char *key = astman_get_header(m, "Key");
if (!ast_strlen_zero(key) && !ast_strlen_zero(s->challenge) && if (!ast_strlen_zero(key) && !ast_strlen_zero(s->challenge) &&
!ast_strlen_zero(password)) { !ast_strlen_zero(password)) {
@@ -1088,22 +993,26 @@ static int authenticate(struct mansession *s, const struct message *m)
} else { } else {
ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n", ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
S_OR(s->challenge, "")); S_OR(s->challenge, ""));
return -1;
} }
} else if (password) { } else if (password && user->secret && !strcmp(password, user->secret))
const char *pass = astman_get_header(m, "Secret"); error = 0;
if (!strcmp(password, pass))
error = 0;
}
if (error) { 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; return -1;
} }
ast_copy_string(s->username, user, sizeof(s->username));
s->readperm = readperm; /* auth complete */
s->writeperm = writeperm;
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); s->sessionstart = time(NULL);
set_eventmask(s, astman_get_header(m, "Events")); set_eventmask(s, astman_get_header(m, "Events"));
AST_RWLIST_UNLOCK(&users);
return 0; return 0;
} }
@@ -3409,7 +3318,7 @@ static struct server_args amis_desc = {
static int __init_manager(int reload) static int __init_manager(int reload)
{ {
struct ast_config *cfg = NULL; struct ast_config *ucfg = NULL, *cfg = NULL;
const char *val; const char *val;
char *cat = NULL; char *cat = NULL;
int newhttptimeout = 60; int newhttptimeout = 60;
@@ -3461,7 +3370,7 @@ static int __init_manager(int reload)
displayconnects = 1; displayconnects = 1;
if (!cfg) { 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; return 0;
} }
@@ -3537,7 +3446,83 @@ static int __init_manager(int reload)
AST_RWLIST_WRLOCK(&users); 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))) { while ((cat = ast_category_browse(cfg, cat))) {
struct ast_ha *oldha;
if (!strcasecmp(cat, "general")) if (!strcasecmp(cat, "general"))
continue; continue;
@@ -3548,45 +3533,50 @@ static int __init_manager(int reload)
break; break;
/* Copy name over */ /* Copy name over */
ast_copy_string(user->username, cat, sizeof(user->username)); 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 */ /* Insert into list */
AST_RWLIST_INSERT_TAIL(&users, user, list); AST_RWLIST_INSERT_TAIL(&users, user, list);
} }
/* Make sure we keep this user and don't destroy it during cleanup */ /* Make sure we keep this user and don't destroy it during cleanup */
user->keep = 1; user->keep = 1;
/* Default displayconnect to [general] */ oldha = user->ha;
user->displayconnects = displayconnects; user->ha = NULL;
var = ast_variable_browse(cfg, cat); var = ast_variable_browse(cfg, cat);
while (var) { for (; var; var = var->next) {
if (!strcasecmp(var->name, "secret")) { if (!strcasecmp(var->name, "secret")) {
if (user->secret) if (user->secret)
ast_free(user->secret); ast_free(user->secret);
user->secret = ast_strdup(var->value); user->secret = ast_strdup(var->value);
} else if (!strcasecmp(var->name, "deny") ) { } else if (!strcasecmp(var->name, "deny") ||
if (user->deny) !strcasecmp(var->name, "permit")) {
ast_free(user->deny); user->ha = ast_append_ha(var->name, var->value, user->ha, NULL);
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, "read") ) { } else if (!strcasecmp(var->name, "read") ) {
if (user->read) user->readperm = get_perm(var->value);
ast_free(user->read);
user->read = ast_strdup(var->value);
} else if (!strcasecmp(var->name, "write") ) { } else if (!strcasecmp(var->name, "write") ) {
if (user->write) user->writeperm = get_perm(var->value);
ast_free(user->write); } else if (!strcasecmp(var->name, "displayconnects") ) {
user->write = ast_strdup(var->value);
} else if (!strcasecmp(var->name, "displayconnects") )
user->displayconnects = ast_true(var->value); 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); 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 */ /* Perform cleanup - essentially prune out old users that no longer exist */
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) { AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
@@ -3599,22 +3589,13 @@ static int __init_manager(int reload)
/* Free their memory now */ /* Free their memory now */
if (user->secret) if (user->secret)
ast_free(user->secret); ast_free(user->secret);
if (user->deny) ast_free_ha(user->ha);
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(user); ast_free(user);
} }
AST_RWLIST_TRAVERSE_SAFE_END; AST_RWLIST_TRAVERSE_SAFE_END;
AST_RWLIST_UNLOCK(&users); AST_RWLIST_UNLOCK(&users);
ast_config_destroy(cfg);
if (webmanager_enabled && manager_enabled) { if (webmanager_enabled && manager_enabled) {
if (!webregged) { if (!webregged) {
ast_http_uri_link(&rawmanuri); ast_http_uri_link(&rawmanuri);