Newer
Older
cfg = ast_config_load2("manager.conf", "manager", config_flags);
if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
return 0;
} else if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid.\n");
/* 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) {
Jonathan Rose
committed
acl_change_stasis_unsubscribe();
if (reload) {
/* Reset all settings before reloading configuration */
tls_was_enabled = ami_tls_cfg.enabled;
manager_set_defaults();
}
ast_sockaddr_parse(&ami_desc_local_address_tmp, "[::]", 0);
ast_sockaddr_set_port(&ami_desc_local_address_tmp, DEFAULT_MANAGER_PORT);
for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
val = var->value;
/* read tls config options while preventing unsupported options from being set */
if (strcasecmp(var->name, "tlscafile")
&& strcasecmp(var->name, "tlscapath")
&& strcasecmp(var->name, "tlscadir")
&& strcasecmp(var->name, "tlsverifyclient")
&& strcasecmp(var->name, "tlsdontverifyserver")
&& strcasecmp(var->name, "tlsclientmethod")
&& strcasecmp(var->name, "sslclientmethod")
&& !ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
continue;
}
if (!strcasecmp(var->name, "enabled")) {
manager_enabled = ast_true(val);
} else if (!strcasecmp(var->name, "webenabled")) {
webmanager_enabled = ast_true(val);
} else if (!strcasecmp(var->name, "port")) {
int bindport;
if (ast_parse_arg(val, PARSE_UINT32|PARSE_IN_RANGE, &bindport, 1024, 65535)) {
ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
}
ast_sockaddr_set_port(&ami_desc_local_address_tmp, bindport);
} else if (!strcasecmp(var->name, "bindaddr")) {
/* remember port if it has already been set */
int setport = ast_sockaddr_port(&ami_desc_local_address_tmp);
if (ast_parse_arg(val, PARSE_ADDR|PARSE_PORT_IGNORE, NULL)) {
ast_log(LOG_WARNING, "Invalid address '%s' specified, default '%s' will be used\n", val,
ast_sockaddr_stringify_addr(&ami_desc_local_address_tmp));
} else {
ast_sockaddr_parse(&ami_desc_local_address_tmp, val, PARSE_PORT_IGNORE);
if (setport) {
ast_sockaddr_set_port(&ami_desc_local_address_tmp, setport);
}
} else if (!strcasecmp(var->name, "brokeneventsaction")) {
broken_events_action = ast_true(val);
} else if (!strcasecmp(var->name, "allowmultiplelogin")) {
allowmultiplelogin = ast_true(val);
} else if (!strcasecmp(var->name, "displayconnects")) {
displayconnects = ast_true(val);
} else if (!strcasecmp(var->name, "timestampevents")) {
timestampevents = ast_true(val);
} else if (!strcasecmp(var->name, "debug")) {
manager_debug = ast_true(val);
} else if (!strcasecmp(var->name, "httptimeout")) {
newhttptimeout = atoi(val);
} else if (!strcasecmp(var->name, "authtimeout")) {
int timeout = atoi(var->value);
if (timeout < 1) {
ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
} else {
authtimeout = timeout;
}
} else if (!strcasecmp(var->name, "authlimit")) {
int limit = atoi(var->value);
if (limit < 1) {
ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
} else {
authlimit = limit;
}
} else if (!strcasecmp(var->name, "channelvars")) {
load_channelvars(var);
} else {
ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
var->name, val);
if (manager_enabled && !subscribed) {
if (subscribe_all() != 0) {
ast_log(LOG_ERROR, "Manager subscription error\n");
return -1;
}
}
ast_sockaddr_copy(&amis_desc_local_address_tmp, &amis_desc.local_address);
/* if the amis address has not been set, default is the same as non secure ami */
if (ast_sockaddr_isnull(&amis_desc_local_address_tmp)) {
ast_sockaddr_copy(&amis_desc_local_address_tmp, &ami_desc_local_address_tmp);
/* if the amis address was not set, it will have non-secure ami port set; if
amis address was set, we need to check that a port was set or not, if not
use the default tls port */
if (ast_sockaddr_port(&amis_desc_local_address_tmp) == 0 ||
(ast_sockaddr_port(&ami_desc_local_address_tmp) == ast_sockaddr_port(&amis_desc_local_address_tmp))) {
ast_sockaddr_set_port(&amis_desc_local_address_tmp, DEFAULT_MANAGER_TLS_PORT);
ast_sockaddr_copy(&ami_desc.local_address, &ami_desc_local_address_tmp);
ast_sockaddr_copy(&amis_desc.local_address, &amis_desc_local_address_tmp);
Olle Johansson
committed
/* First, get users from users.conf */
Tilghman Lesher
committed
ucfg = ast_config_load2("users.conf", "manager", config_flags);
if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
Olle Johansson
committed
const char *hasmanager;
int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
while ((cat = ast_category_browse(ucfg, cat))) {
if (!strcasecmp(cat, "general")) {
Olle Johansson
committed
continue;
}
Olle Johansson
committed
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_allowmultiplelogin = ast_variable_retrieve(ucfg, cat, "allowmultiplelogin");
Olle Johansson
committed
const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
Olle Johansson
committed
/* 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)))) {
Olle Johansson
committed
break;
Olle Johansson
committed
/* Copy name over */
ast_copy_string(user->username, cat, sizeof(user->username));
/* Insert into list */
AST_LIST_INSERT_TAIL(&users, user, list);
user->acl = NULL;
user->keep = 1;
Olle Johansson
committed
user->readperm = -1;
user->writeperm = -1;
/* Default displayconnect from [general] */
user->displayconnects = displayconnects;
/* Default allowmultiplelogin from [general] */
user->allowmultiplelogin = allowmultiplelogin;
Olle Johansson
committed
user->writetimeout = 100;
}
if (!user_secret) {
Olle Johansson
committed
user_secret = ast_variable_retrieve(ucfg, "general", "secret");
}
if (!user_read) {
Olle Johansson
committed
user_read = ast_variable_retrieve(ucfg, "general", "read");
}
if (!user_write) {
Olle Johansson
committed
user_write = ast_variable_retrieve(ucfg, "general", "write");
}
if (!user_displayconnects) {
Olle Johansson
committed
user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
if (!user_allowmultiplelogin) {
user_allowmultiplelogin = ast_variable_retrieve(ucfg, "general", "allowmultiplelogin");
}
if (!user_writetimeout) {
Olle Johansson
committed
user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
Olle Johansson
committed
if (!ast_strlen_zero(user_secret)) {
ast_free(user->secret);
Olle Johansson
committed
user->secret = ast_strdup(user_secret);
}
if (user_read) {
Olle Johansson
committed
user->readperm = get_perm(user_read);
}
if (user_write) {
Olle Johansson
committed
user->writeperm = get_perm(user_write);
}
if (user_displayconnects) {
Olle Johansson
committed
user->displayconnects = ast_true(user_displayconnects);
if (user_allowmultiplelogin) {
user->allowmultiplelogin = ast_true(user_allowmultiplelogin);
}
Olle Johansson
committed
if (user_writetimeout) {
int value = atoi(user_writetimeout);
if (value < 100) {
ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value);
} else {
user->writetimeout = value;
Olle Johansson
committed
}
}
}
ast_config_destroy(ucfg);
}
/* cat is NULL here in any case */
while ((cat = ast_category_browse(cfg, cat))) {
struct ast_acl_list *oldacl;
if (!strcasecmp(cat, "general")) {
/* 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)))) {
/* Copy name over */
ast_copy_string(user->username, cat, sizeof(user->username));
Olle Johansson
committed
user->acl = NULL;
Olle Johansson
committed
user->readperm = 0;
user->writeperm = 0;
/* Default displayconnect from [general] */
user->displayconnects = displayconnects;
/* Default allowmultiplelogin from [general] */
user->allowmultiplelogin = allowmultiplelogin;
Olle Johansson
committed
user->writetimeout = 100;
user->whitefilters = ao2_container_alloc(1, NULL, NULL);
user->blackfilters = ao2_container_alloc(1, NULL, NULL);
if (!user->whitefilters || !user->blackfilters) {
manager_free_user(user);
break;
}
Olle Johansson
committed
AST_RWLIST_INSERT_TAIL(&users, user, list);
} else {
ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
}
/* Make sure we keep this user and don't destroy it during cleanup */
user->keep = 1;
oldacl = user->acl;
user->acl = NULL;
ast_variables_destroy(user->chanvars);
var = ast_variable_browse(cfg, cat);
Olle Johansson
committed
for (; var; var = var->next) {
if (!strcasecmp(var->name, "secret")) {
ast_free(user->secret);
user->secret = ast_strdup(var->value);
Olle Johansson
committed
} else if (!strcasecmp(var->name, "deny") ||
!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") ) {
Olle Johansson
committed
user->readperm = get_perm(var->value);
} else if (!strcasecmp(var->name, "write") ) {
Olle Johansson
committed
user->writeperm = get_perm(var->value);
} else if (!strcasecmp(var->name, "displayconnects") ) {
user->displayconnects = ast_true(var->value);
} else if (!strcasecmp(var->name, "allowmultiplelogin") ) {
user->allowmultiplelogin = ast_true(var->value);
Olle Johansson
committed
} else if (!strcasecmp(var->name, "writetimeout")) {
int value = atoi(var->value);
if (value < 100) {
Olle Johansson
committed
ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
} else {
user->writetimeout = value;
} else if (!strcasecmp(var->name, "setvar")) {
struct ast_variable *tmpvar;
char varbuf[256];
char *varval;
char *varname;
ast_copy_string(varbuf, var->value, sizeof(varbuf));
varname = varbuf;
if ((varval = strchr(varname,'='))) {
*varval++ = '\0';
if ((tmpvar = ast_variable_new(varname, varval, ""))) {
tmpvar->next = user->chanvars;
user->chanvars = tmpvar;
}
}
} else if (!strcasecmp(var->name, "eventfilter")) {
const char *value = var->value;
manager_add_filter(value, user->whitefilters, user->blackfilters);
} else {
ast_debug(1, "%s is an unknown option.\n", var->name);
oldacl = ast_free_acl_list(oldacl);
Olle Johansson
committed
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) {
Jonathan Rose
committed
acl_change_stasis_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 */
/* Calculate A1 for Digest auth */
snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
ast_md5_hash(a1_hash,a1);
ast_free(user->a1_hash);
user->a1_hash = ast_strdup(a1_hash);
continue;
}
/* We do not need to keep this user so take them out of the list */
AST_RWLIST_REMOVE_CURRENT(list);
ast_debug(4, "Pruning user '%s'\n", user->username);
AST_RWLIST_TRAVERSE_SAFE_END;
if (webmanager_enabled && manager_enabled) {
Mark Spencer
committed
if (!webregged) {
ast_http_uri_link(&rawmanuri);
ast_http_uri_link(&manageruri);
ast_http_uri_link(&managerxmluri);
ast_http_uri_link(&arawmanuri);
ast_http_uri_link(&amanageruri);
ast_http_uri_link(&amanagerxmluri);
Mark Spencer
committed
webregged = 1;
}
} else {
if (webregged) {
ast_http_uri_unlink(&rawmanuri);
ast_http_uri_unlink(&manageruri);
ast_http_uri_unlink(&managerxmluri);
ast_http_uri_unlink(&arawmanuri);
ast_http_uri_unlink(&amanageruri);
ast_http_uri_unlink(&amanagerxmluri);
Mark Spencer
committed
webregged = 0;
}
}
if (newhttptimeout > 0) {
Mark Spencer
committed
httptimeout = newhttptimeout;
ast_tcptls_server_start(&ami_desc);
if (tls_was_enabled && !ami_tls_cfg.enabled) {
ast_tcptls_server_stop(&amis_desc);
} else if (ast_ssl_setup(amis_desc.tls_cfg)) {
ast_tcptls_server_start(&amis_desc);
Jonathan Rose
committed
static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
struct stasis_message *message)
Jonathan Rose
committed
if (stasis_message_type(message) != ast_named_acl_change_type()) {
return;
}
/* 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);
}
int init_manager(void)
{
return __init_manager(0, 0);
return __init_manager(1, 0);
Kevin P. Fleming
committed
int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
{
AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
Kevin P. Fleming
committed
return 0;
}
int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
{
return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
Kevin P. Fleming
committed
}
struct ast_datastore *astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
{
struct ast_datastore *datastore = NULL;
Kevin P. Fleming
committed
if (info == NULL)
return NULL;
AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
Kevin P. Fleming
committed
if (datastore->info != info) {
continue;
}
if (uid == NULL) {
/* matched by type only */
break;
}
if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
/* Matched by type AND uid */
break;
}
}
AST_LIST_TRAVERSE_SAFE_END;
return datastore;
}
Richard Mudgett
committed
int ast_str_append_event_header(struct ast_str **fields_string,
const char *header, const char *value)
{
struct ast_str *working_str = *fields_string;
if (!working_str) {
working_str = ast_str_create(128);
if (!working_str) {
return -1;
}
*fields_string = working_str;
}
ast_str_append(&working_str, 0,
"%s: %s\r\n",
header, value);
return 0;
}
Richard Mudgett
committed
static void manager_event_blob_dtor(void *obj)
{
struct ast_manager_event_blob *ev = obj;
Richard Mudgett
committed
ast_string_field_free_memory(ev);
}
struct ast_manager_event_blob *
__attribute__((format(printf, 3, 4)))
ast_manager_event_blob_create(
int event_flags,
const char *manager_event,
const char *extra_fields_fmt,
...)
{
struct ast_manager_event_blob *ev;
Richard Mudgett
committed
va_list argp;
ast_assert(extra_fields_fmt != NULL);
ast_assert(manager_event != NULL);
ev = ao2_alloc_options(sizeof(*ev), manager_event_blob_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
Richard Mudgett
committed
if (!ev) {
return NULL;
}
if (ast_string_field_init(ev, 20)) {
Richard Mudgett
committed
return NULL;
}
ev->manager_event = manager_event;
ev->event_flags = event_flags;
va_start(argp, extra_fields_fmt);
ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt, argp);
Richard Mudgett
committed
va_end(argp);
return ev;
}