Sat Apr 26 2014 22:02:56

Asterisk developer's documentation


manager.c File Reference

The Asterisk Management Interface - AMI. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/paths.h"
#include <ctype.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <regex.h>
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/manager.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/callerid.h"
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/md5.h"
#include "asterisk/acl.h"
#include "asterisk/utils.h"
#include "asterisk/tcptls.h"
#include "asterisk/http.h"
#include "asterisk/ast_version.h"
#include "asterisk/threadstorage.h"
#include "asterisk/linkedlists.h"
#include "asterisk/term.h"
#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"
Include dependency graph for manager.c:

Go to the source code of this file.

Data Structures

struct  actions
 list of actions registered More...
struct  all_events
struct  ast_manager_user
 user descriptor, as read from the config file. More...
struct  channelvars
struct  eventqent
struct  fast_originate_helper
 helper function for originate More...
struct  manager_channel_variable
struct  manager_hooks
 list of hooks registered More...
struct  mansession
 In case you didn't read that giant block of text above the mansession_session struct, the struct mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data. More...
struct  mansession_session::mansession_datastores
struct  mansession_session
struct  permalias
struct  users
 list of users found in the config file More...
struct  variable_count

Defines

#define ASTMAN_APPEND_BUF_INITSIZE   256
 initial allocated size for the astman_append_buf and astman_send_*_va
#define DEFAULT_REALM   "asterisk"
#define FORMAT   " %-25.25s %-15.55s\n"
#define FORMAT2   " %-25.25s %-15d\n"
#define GET_HEADER_FIRST_MATCH   0
#define GET_HEADER_LAST_MATCH   1
#define GET_HEADER_SKIP_EMPTY   2
#define HSMC_FORMAT   " %-15.15s %-15.15s %-55.55s\n"
#define HSMCONN_FORMAT1   " %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
#define HSMCONN_FORMAT2   " %-15.15s %-55.55s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
#define MANAGER_EVENT_BUF_INITSIZE   256
#define MAX_BLACKLIST_CMD_LEN   2
 Descriptor for a manager session, either on the AMI socket or over HTTP.
#define MSG_MOREDATA   ((char *)astman_send_response)
#define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
#define TEST_STRING   "<form action=\"manager\" method=\"post\">\n\ Action: <select name=\"action\">\n\ <option value=\"\">-----&gt;</option>\n\ <option value=\"login\">login</option>\n\ <option value=\"command\">Command</option>\n\ <option value=\"waitevent\">waitevent</option>\n\ <option value=\"listcommands\">listcommands</option>\n\ </select>\n\ or <input name=\"action\"><br/>\n\ CLI Command <input name=\"command\"><br>\n\ user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\ <input type=\"submit\">\n</form>\n"

Enumerations

enum  add_filter_result { FILTER_SUCCESS, FILTER_ALLOC_FAILED, FILTER_COMPILE_FAIL }
enum  error_type {
  UNKNOWN_ACTION = 1, UNKNOWN_CATEGORY, UNSPECIFIED_CATEGORY, UNSPECIFIED_ARGUMENT,
  FAILURE_ALLOCATION, FAILURE_NEWCAT, FAILURE_DELCAT, FAILURE_EMPTYCAT,
  FAILURE_UPDATE, FAILURE_DELETE, FAILURE_APPEND
}
enum  mansession_message_parsing { MESSAGE_OKAY, MESSAGE_LINE_TOO_LONG }
enum  output_format { FORMAT_RAW, FORMAT_HTML, FORMAT_XML }

Functions

int __ast_manager_event_multichan (int category, const char *event, int chancount, struct ast_channel **chans, const char *file, int line, const char *func, const char *fmt,...)
static const char * __astman_get_header (const struct message *m, char *var, int mode)
 Return a matching header value.
static void __init_astman_append_buf (void)
 thread local buffer for astman_append
static int __init_manager (int reload, int by_external_config)
static void __init_manager_event_buf (void)
static void __init_manager_event_funcbuf (void)
static void __init_userevent_buf (void)
static void acl_change_event_cb (const struct ast_event *event, void *userdata)
static void acl_change_event_subscribe (void)
static void acl_change_event_unsubscribe (void)
static int action_aocmessage (struct mansession *s, const struct message *m)
static int action_atxfer (struct mansession *s, const struct message *m)
static int action_challenge (struct mansession *s, const struct message *m)
static int action_command (struct mansession *s, const struct message *m)
 Manager command "command" - execute CLI command.
static int action_coresettings (struct mansession *s, const struct message *m)
 Show PBX core settings information.
static int action_coreshowchannels (struct mansession *s, const struct message *m)
 Manager command "CoreShowChannels" - List currently defined channels and some information about them.
static int action_corestatus (struct mansession *s, const struct message *m)
 Show PBX core status information.
static int action_createconfig (struct mansession *s, const struct message *m)
static void action_destroy (void *obj)
static int action_events (struct mansession *s, const struct message *m)
static int action_extensionstate (struct mansession *s, const struct message *m)
static int action_filter (struct mansession *s, const struct message *m)
 Manager command to add an event filter to a manager session.
static struct manager_actionaction_find (const char *name)
static int action_getconfig (struct mansession *s, const struct message *m)
static int action_getconfigjson (struct mansession *s, const struct message *m)
static int action_getvar (struct mansession *s, const struct message *m)
static int action_hangup (struct mansession *s, const struct message *m)
static int action_listcategories (struct mansession *s, const struct message *m)
static int action_listcommands (struct mansession *s, const struct message *m)
static int action_login (struct mansession *s, const struct message *m)
static int action_logoff (struct mansession *s, const struct message *m)
static int action_mailboxcount (struct mansession *s, const struct message *m)
static int action_mailboxstatus (struct mansession *s, const struct message *m)
static int action_originate (struct mansession *s, const struct message *m)
static int action_ping (struct mansession *s, const struct message *m)
static int action_presencestate (struct mansession *s, const struct message *m)
static int action_redirect (struct mansession *s, const struct message *m)
 action_redirect: The redirect manager command
static int action_reload (struct mansession *s, const struct message *m)
 Send a reload event.
static int action_sendtext (struct mansession *s, const struct message *m)
static int action_setvar (struct mansession *s, const struct message *m)
static int action_status (struct mansession *s, const struct message *m)
 Manager "status" command to show channels.
static int action_timeout (struct mansession *s, const struct message *m)
static int action_updateconfig (struct mansession *s, const struct message *m)
static int action_userevent (struct mansession *s, const struct message *m)
static int action_waitevent (struct mansession *s, const struct message *m)
static struct eventqentadvance_event (struct eventqent *e)
static AO2_GLOBAL_OBJ_STATIC (mgr_sessions)
static AO2_GLOBAL_OBJ_STATIC (event_docs)
 A container of event documentation nodes.
static int aocmessage_get_unit_entry (const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
static void append_channel_vars (struct ast_str **pbuf, struct ast_channel *chan)
static int append_event (const char *str, int category)
 events are appended to a queue from where they can be dispatched to clients.
int ast_hook_send_action (struct manager_custom_hook *hook, const char *msg)
 access for hooks to send action messages to ami
static int ast_instring (const char *bigstr, const char *smallstr, const char delim)
int ast_manager_register2 (const char *action, int auth, int(*func)(struct mansession *s, const struct message *m), struct ast_module *module, const char *synopsis, const char *description)
 register a new command with manager, including online help. This is the preferred way to register a manager command
void ast_manager_register_hook (struct manager_custom_hook *hook)
 Add a custom hook to be called when an event is fired.
static int ast_manager_register_struct (struct manager_action *act)
int ast_manager_unregister (const char *action)
 support functions to register/unregister AMI action handlers,
void ast_manager_unregister_hook (struct manager_custom_hook *hook)
 Delete a custom hook to be called when an event is fired.
static int ast_xml_doc_item_cmp_fn (const void *a, const void *b)
void astman_append (struct mansession *s, const char *fmt,...)
static void astman_append_json (struct mansession *s, const char *str)
int astman_datastore_add (struct mansession *s, struct ast_datastore *datastore)
 Add a datastore to a session.
struct ast_datastoreastman_datastore_find (struct mansession *s, const struct ast_datastore_info *info, const char *uid)
 Find a datastore on a session.
int astman_datastore_remove (struct mansession *s, struct ast_datastore *datastore)
 Remove a datastore from a session.
const char * astman_get_header (const struct message *m, char *var)
 Return the first matching variable from an array.
struct ast_variableastman_get_variables (const struct message *m)
 Get a linked list of the Variable: headers.
int astman_is_authed (uint32_t ident)
 Determinie if a manager session ident is authenticated.
void astman_send_ack (struct mansession *s, const struct message *m, char *msg)
 Send ack in manager transaction.
void astman_send_error (struct mansession *s, const struct message *m, char *error)
 Send error in manager transaction.
void astman_send_error_va (struct mansession *s, const struct message *m, const char *fmt,...)
 Send error in manager transaction (with va_args support)
void astman_send_listack (struct mansession *s, const struct message *m, char *msg, char *listflag)
 Send ack in manager list transaction.
void astman_send_response (struct mansession *s, const struct message *m, char *resp, char *msg)
 Send response in manager transaction.
static void astman_send_response_full (struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
 send a response with an optional message, and terminate it with an empty line. m is used only to grab the 'ActionID' field.
static void astman_start_ack (struct mansession *s, const struct message *m)
int astman_verify_session_readpermissions (uint32_t ident, int perm)
 Verify a session's read permissions against a permission mask.
int astman_verify_session_writepermissions (uint32_t ident, int perm)
 Verify a session's write permissions against a permission mask.
static int auth_http_callback (struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, const struct ast_sockaddr *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_manager_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_mxml_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_rawman_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int authenticate (struct mansession *s, const struct message *m)
static const char * authority_to_str (int authority, struct ast_str **res)
 Convert authority code to a list of options. Note that the EVENT_FLAG_ALL authority will always be returned.
static int blackfilter_cmp_fn (void *obj, void *arg, void *data, int flags)
static struct mansession_sessionbuild_mansession (const struct ast_sockaddr *addr)
 Allocate manager session structure and add it to the list of sessions.
static int check_blacklist (const char *cmd)
int check_manager_enabled (void)
 Check if AMI is enabled.
static int check_manager_session_inuse (const char *name)
int check_webmanager_enabled (void)
 Check if AMI/HTTP is enabled.
static void destroy_fast_originate_helper (struct fast_originate_helper *doomed)
static int do_message (struct mansession *s)
static void event_filter_destructor (void *obj)
static void * fast_originate (void *data)
static struct mansession_sessionfind_session (uint32_t ident, int incinuse)
static struct mansession_sessionfind_session_by_nonce (const char *username, unsigned long nonce, int *stale)
static void free_channelvars (void)
static int function_amiclient (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 ${AMI_CLIENT()} Dialplan function - reads manager client data
static int function_capable_string_allowed_with_auths (const char *evaluating, int writepermlist)
 Checks to see if a string which can be used to evaluate functions should be rejected.
static int generic_http_callback (struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, const struct ast_sockaddr *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
static int get_input (struct mansession *s, char *output)
static struct ast_manager_userget_manager_by_name_locked (const char *name)
static int get_manager_sessions_cb (void *obj, void *arg, void *data, int flags)
 Get number of logged in sessions for a login name.
static int get_perm (const char *instr)
static struct eventqentgrab_last (void)
static char * handle_manager_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager reload.
static char * handle_manager_show_event (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_manager_show_events (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_manager_show_settings (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager show settings.
static char * handle_mandebug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void handle_parse_error (struct mansession *s, struct message *m, char *error)
static char * handle_showmanager (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmanagers (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmancmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmancmds (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list commands.
static char * handle_showmanconn (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list connected.
static char * handle_showmaneventq (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list eventq.
static enum error_type handle_updates (struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
 helper function for action_updateconfig
int init_manager (void)
 Called by Asterisk initialization.
static void json_escape (char *out, const char *in)
static void load_channelvars (struct ast_variable *var)
static struct ast_variableman_do_variable_value (struct ast_variable *head, const char *hdr_val)
static enum add_filter_result manager_add_filter (const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters)
 Add an event filter to a manager session.
static int manager_displayconnects (struct mansession_session *session)
 Get displayconnects config option.
static void manager_free_user (struct ast_manager_user *user)
static int manager_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int manager_modulecheck (struct mansession *s, const struct message *m)
 Manager function to check if module is loaded.
static int manager_moduleload (struct mansession *s, const struct message *m)
static void manager_set_defaults (void)
static void manager_shutdown (void)
static int manager_state_cb (char *context, char *exten, struct ast_state_cb_info *info, void *data)
static int mansession_cmp_fn (void *obj, void *arg, int flags)
static enum
ast_security_event_transport_type 
mansession_get_transport (const struct mansession *s)
static void mansession_lock (struct mansession *s)
 Lock the 'mansession' structure.
static void mansession_unlock (struct mansession *s)
 Unlock the 'mansession' structure.
static int match_filter (struct mansession *s, char *eventdata)
static int mxml_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int process_events (struct mansession *s)
static int process_message (struct mansession *s, const struct message *m)
 Process an AMI message, performing desired action. Return 0 on success, -1 on error that require the session to be destroyed.
static void process_output (struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
static void purge_events (void)
static void purge_old_stuff (void *data)
 cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most
static void purge_sessions (int n_max)
 remove at most n_max stale session from the list.
static int rawman_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
int reload_manager (void)
 Called by Asterisk module functions and the CLI command.
static void report_auth_success (const struct mansession *s)
static void report_failed_acl (const struct mansession *s, const char *username)
static void report_failed_challenge_response (const struct mansession *s, const char *response, const char *expected_response)
static void report_inval_password (const struct mansession *s, const char *username)
static void report_invalid_user (const struct mansession *s, const char *username)
static void report_req_bad_format (const struct mansession *s, const char *action)
static void report_req_not_allowed (const struct mansession *s, const char *action)
static void report_session_limit (const struct mansession *s)
static int send_string (struct mansession *s, char *string)
static void session_destroy (struct mansession_session *s)
static void session_destructor (void *obj)
static void * session_do (void *data)
 The body of the individual manager session. Call get_input() to read one line at a time (or be woken up on new events), collect the lines in a message until found an empty line, and execute the request. In any case, deliver events asynchronously through process_events() (called from here if no line is available, or at the end of process_message(). )
static int set_eventmask (struct mansession *s, const char *eventmask)
 Rather than braindead on,off this now can also accept a specific int mask value or a ',' delim list of mask strings (the same as manager.conf) -anthm.
static int strings_to_mask (const char *string)
static struct mansession_sessionunref_mansession (struct mansession_session *s)
 Unreference manager session object. If no more references, then go ahead and delete it.
static const char * user_authority_to_str (int authority, struct ast_str **res)
 Convert authority code to a list of options for a user. This will only display those authority codes that have an explicit match on authority.
static int variable_count_cmp_fn (void *obj, void *vstr, int flags)
static int variable_count_hash_fn (const void *vvc, const int flags)
static int whitefilter_cmp_fn (void *obj, void *arg, void *data, int flags)
static void xml_copy_escape (struct ast_str **out, const char *src, int mode)
static void xml_translate (struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
 Convert the input into XML or HTML. The input is supposed to be a sequence of lines of the form Name: value optionally followed by a blob of unformatted text. A blank line is a section separator. Basically, this is a mixture of the format of Manager Interface and CLI commands. The unformatted text is considered as a single value of a field named 'Opaque-data'.

Variables

static struct ast_event_subacl_change_event_subscription
static struct actions actions
static struct all_events all_events
static int allowmultiplelogin = 1
static struct ast_http_uri amanageruri
static struct ast_http_uri amanagerxmluri
static struct
ast_tcptls_session_args 
ami_desc
static struct ast_tls_config ami_tls_cfg
static struct
ast_tcptls_session_args 
amis_desc
static struct ast_http_uri arawmanuri
static struct ast_threadstorage astman_append_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_astman_append_buf , .custom_init = NULL , }
static int authlimit
static int authtimeout
static int block_sockets
static int broken_events_action = 0
static struct channelvars channelvars
static struct ast_cli_entry cli_manager []
struct {
   const char *   words [AST_MAX_CMD_LEN]
command_blacklist []
static const char *const contenttype []
static int displayconnects = 1
static char global_realm [MAXHOSTNAMELEN]
static int httptimeout = 60
static char * manager_channelvars
static int manager_debug = 0
static int manager_enabled = 0
static struct ast_threadstorage manager_event_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_manager_event_buf , .custom_init = NULL , }
static struct ast_threadstorage manager_event_funcbuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_manager_event_funcbuf , .custom_init = NULL , }
static struct manager_hooks manager_hooks
static struct ast_custom_function managerclient_function
 description of AMI_CLIENT dialplan function
static struct ast_http_uri manageruri
static struct ast_http_uri managerxmluri
static struct permalias perms []
static struct ast_http_uri rawmanuri
static int timestampevents
static int unauth_sessions = 0
static struct ast_threadstorage userevent_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_userevent_buf , .custom_init = NULL , }
static struct users users
static int webmanager_enabled = 0
static int webregged = 0

Detailed Description

The Asterisk Management Interface - AMI.

Author:
Mark Spencer <markster@digium.com>
ExtRef:
OpenSSL http://www.openssl.org - for AMI/SSL

At the moment this file contains a number of functions, namely:

  • data structures storing AMI state
  • AMI-related API functions, used by internal asterisk components
  • handlers for AMI-related CLI functions
  • handlers for AMI functions (available through the AMI socket)
  • the code for the main AMI listener thread and individual session threads
  • the http handlers invoked for AMI-over-HTTP by the threads in main/http.c

manager.conf

Definition in file manager.c.


Define Documentation

#define FORMAT   " %-25.25s %-15.55s\n"
#define FORMAT2   " %-25.25s %-15d\n"
#define HSMC_FORMAT   " %-15.15s %-15.15s %-55.55s\n"

Referenced by handle_showmancmds().

#define HSMCONN_FORMAT1   " %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"

Referenced by handle_showmanconn().

#define HSMCONN_FORMAT2   " %-15.15s %-55.55s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"

Referenced by handle_showmanconn().

#define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"

Referenced by generic_http_callback().

#define TEST_STRING   "<form action=\"manager\" method=\"post\">\n\ Action: <select name=\"action\">\n\ <option value=\"\">-----&gt;</option>\n\ <option value=\"login\">login</option>\n\ <option value=\"command\">Command</option>\n\ <option value=\"waitevent\">waitevent</option>\n\ <option value=\"listcommands\">listcommands</option>\n\ </select>\n\ or <input name=\"action\"><br/>\n\ CLI Command <input name=\"command\"><br>\n\ user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\ <input type=\"submit\">\n</form>\n"

Referenced by generic_http_callback().


Enumeration Type Documentation

Enumerator:
FORMAT_RAW 
FORMAT_HTML 
FORMAT_XML 

Definition at line 5995 of file manager.c.


Function Documentation

static int __init_manager ( int  reload,
int  by_external_config 
) [static]

Definition at line 7568 of file manager.c.

References __ast_custom_function_register(), ast_manager_user::a1_hash, ast_manager_user::acl, acl_change_event_subscribe(), acl_change_event_unsubscribe(), action_aocmessage(), action_atxfer(), action_challenge(), action_command(), action_coresettings(), action_coreshowchannels(), action_corestatus(), action_createconfig(), action_events(), action_extensionstate(), action_filter(), action_getconfig(), action_getconfigjson(), action_getvar(), action_hangup(), action_listcategories(), action_listcommands(), action_login(), action_logoff(), action_mailboxcount(), action_mailboxstatus(), action_originate(), action_ping(), action_presencestate(), action_redirect(), action_reload(), action_sendtext(), action_setvar(), action_status(), action_timeout(), action_updateconfig(), action_userevent(), action_waitevent(), ami_tls_cfg, ao2_container_alloc, ao2_global_obj_replace_unref, ao2_ref, ao2_t_callback, ao2_t_global_obj_replace_unref, ao2_t_ref, append_event(), ARRAY_LEN, ast_append_acl(), ast_calloc, ast_category_browse(), ast_cli_register_multiple(), ast_config_destroy(), ast_config_load2(), ast_copy_string(), ast_debug, ast_extension_state_add(), ast_free, ast_free_acl_list(), ast_http_uri_link(), ast_http_uri_unlink(), AST_LIST_INSERT_TAIL, ast_log(), ast_manager_register_xml_core, ast_md5_hash(), ast_parse_arg(), ast_register_atexit(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_sockaddr_copy(), ast_sockaddr_isnull(), ast_sockaddr_parse(), ast_sockaddr_port, ast_sockaddr_set_port, ast_sockaddr_stringify_addr(), ast_ssl_setup(), ast_strdup, ast_strlen_zero(), ast_tcptls_server_start(), ast_tcptls_server_stop(), ast_tls_read_conf(), ast_true(), ast_variable_browse(), ast_variable_new(), ast_variable_retrieve(), ast_variables_destroy(), ast_xmldoc_build_documentation(), ast_manager_user::blackfilters, block_sockets, ast_manager_user::chanvars, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_MANAGER_PORT, DEFAULT_MANAGER_TLS_PORT, displayconnects, ast_manager_user::displayconnects, ast_tls_config::enabled, EVENT_FLAG_AOC, EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, EVENT_FLAG_CONFIG, EVENT_FLAG_ORIGINATE, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, get_manager_by_name_locked(), get_perm(), global_realm, ast_manager_user::keep, ast_variable::lineno, load_channelvars(), ast_tcptls_session_args::local_address, LOG_NOTICE, LOG_WARNING, manager_add_filter(), manager_event, manager_free_user(), manager_modulecheck(), manager_moduleload(), manager_set_defaults(), manager_shutdown(), manager_state_cb(), mansession_cmp_fn(), ast_variable::name, ast_variable::next, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, PARSE_ADDR, PARSE_IN_RANGE, PARSE_PORT_IGNORE, PARSE_UINT32, ast_manager_user::readperm, ast_manager_user::secret, sessions, ast_tcptls_session_args::tls_cfg, ast_manager_user::username, value, ast_variable::value, var, ast_manager_user::whitefilters, ast_manager_user::writeperm, and ast_manager_user::writetimeout.

Referenced by acl_change_event_cb(), init_manager(), and reload_manager().

{
   struct ast_config *ucfg = NULL, *cfg = NULL;
   const char *val;
   char *cat = NULL;
   int newhttptimeout = 60;
   struct ast_manager_user *user = NULL;
   struct ast_variable *var;
   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;

   if (!reload) {
      struct ao2_container *sessions;
#ifdef AST_XML_DOCS
      struct ao2_container *temp_event_docs;
#endif

      ast_register_atexit(manager_shutdown);

      /* Register default actions */
      ast_manager_register_xml_core("Ping", 0, action_ping);
      ast_manager_register_xml_core("Events", 0, action_events);
      ast_manager_register_xml_core("Logoff", 0, action_logoff);
      ast_manager_register_xml_core("Login", 0, action_login);
      ast_manager_register_xml_core("Challenge", 0, action_challenge);
      ast_manager_register_xml_core("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
      ast_manager_register_xml_core("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
      ast_manager_register_xml_core("Setvar", EVENT_FLAG_CALL, action_setvar);
      ast_manager_register_xml_core("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
      ast_manager_register_xml_core("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
      ast_manager_register_xml_core("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
      ast_manager_register_xml_core("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
      ast_manager_register_xml_core("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
      ast_manager_register_xml_core("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
      ast_manager_register_xml_core("Redirect", EVENT_FLAG_CALL, action_redirect);
      ast_manager_register_xml_core("Atxfer", EVENT_FLAG_CALL, action_atxfer);
      ast_manager_register_xml_core("Originate", EVENT_FLAG_ORIGINATE, action_originate);
      ast_manager_register_xml_core("Command", EVENT_FLAG_COMMAND, action_command);
      ast_manager_register_xml_core("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
      ast_manager_register_xml_core("PresenceState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_presencestate);
      ast_manager_register_xml_core("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
      ast_manager_register_xml_core("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
      ast_manager_register_xml_core("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
      ast_manager_register_xml_core("ListCommands", 0, action_listcommands);
      ast_manager_register_xml_core("SendText", EVENT_FLAG_CALL, action_sendtext);
      ast_manager_register_xml_core("UserEvent", EVENT_FLAG_USER, action_userevent);
      ast_manager_register_xml_core("WaitEvent", 0, action_waitevent);
      ast_manager_register_xml_core("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
      ast_manager_register_xml_core("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
      ast_manager_register_xml_core("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
      ast_manager_register_xml_core("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
      ast_manager_register_xml_core("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
      ast_manager_register_xml_core("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
      ast_manager_register_xml_core("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
      ast_manager_register_xml_core("Filter", EVENT_FLAG_SYSTEM, action_filter);

      ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
      __ast_custom_function_register(&managerclient_function, NULL);
      ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);

      /* Append placeholder event so master_eventq never runs dry */
      if (append_event("Event: Placeholder\r\n\r\n", 0)) {
         return -1;
      }

#ifdef AST_XML_DOCS
      temp_event_docs = ast_xmldoc_build_documentation("managerEvent");
      if (temp_event_docs) {
         ao2_t_global_obj_replace_unref(event_docs, temp_event_docs, "Toss old event docs");
         ao2_t_ref(temp_event_docs, -1, "Remove creation ref - container holds only ref now");
      }
#endif

      /* If you have a NULL hash fn, you only need a single bucket */
      sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn);
      if (!sessions) {
         return -1;
      }
      ao2_global_obj_replace_unref(mgr_sessions, sessions);
      ao2_ref(sessions, -1);

      /* Initialize all settings before first configuration load. */
      manager_set_defaults();
   }

   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");
      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();
   }

   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, "block-sockets")) {
         block_sockets = 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);
      }
   }

   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);
   }

   if (manager_enabled) {
      ast_sockaddr_copy(&ami_desc.local_address, &ami_desc_local_address_tmp);
      ast_sockaddr_copy(&amis_desc.local_address, &amis_desc_local_address_tmp);
   }

   AST_RWLIST_WRLOCK(&users);

   /* First, get users from users.conf */
   ucfg = ast_config_load2("users.conf", "manager", config_flags);
   if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
      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->acl = NULL;
               user->keep = 1;
               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)) {
               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 value = atoi(user_writetimeout);
               if (value < 100) {
                  ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value);
               } else {
                  user->writetimeout = value;
               }
            }
         }
      }
      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")) {
         continue;
      }

      /* 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));

         user->acl = NULL;
         user->readperm = 0;
         user->writeperm = 0;
         /* Default displayconnect from [general] */
         user->displayconnects = displayconnects;
         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;
         }

         /* Insert into list */
         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);
      for (; var; var = var->next) {
         if (!strcasecmp(var->name, "secret")) {
            ast_free(user->secret);
            user->secret = ast_strdup(var->value);
         } 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") ) {
            user->readperm = get_perm(var->value);
         }  else if (!strcasecmp(var->name, "write") ) {
            user->writeperm = get_perm(var->value);
         }  else if (!strcasecmp(var->name, "displayconnects") ) {
            user->displayconnects = ast_true(var->value);
         } else if (!strcasecmp(var->name, "writetimeout")) {
            int value = atoi(var->value);
            if (value < 100) {
               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);
   }
   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 */
         user->keep = 0;

         /* 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);
      manager_free_user(user);
   }
   AST_RWLIST_TRAVERSE_SAFE_END;

   AST_RWLIST_UNLOCK(&users);

   if (webmanager_enabled && manager_enabled) {
      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);
         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);
         webregged = 0;
      }
   }

   if (newhttptimeout > 0) {
      httptimeout = newhttptimeout;
   }

   manager_event(EVENT_FLAG_SYSTEM, "Reload",
      "Module: Manager\r\n"
      "Status: %s\r\n"
      "Message: Manager reload Requested\r\n",
      manager_enabled ? "Enabled" : "Disabled");

   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);
   }

   return 0;
static int ast_xml_doc_item_cmp_fn ( const void *  a,
const void *  b 
) [static]

Definition at line 7231 of file manager.c.

Referenced by handle_manager_show_events().

{
   struct ast_xml_doc_item **item_a = (struct ast_xml_doc_item **)a;
   struct ast_xml_doc_item **item_b = (struct ast_xml_doc_item **)b;
   return strcmp((*item_a)->name, (*item_b)->name);
int astman_datastore_add ( struct mansession s,
struct ast_datastore datastore 
)

Add a datastore to a session.

Return values:
0success
non-zerofailure
Since:
1.6.1

Definition at line 8055 of file manager.c.

References AST_LIST_INSERT_HEAD, mansession_session::datastores, and mansession::session.

{
   AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);

   return 0;
struct ast_datastore* astman_datastore_find ( struct mansession s,
const struct ast_datastore_info info,
const char *  uid 
) [read]

Find a datastore on a session.

Return values:
pointerto the datastore if found
NULLif not found
Since:
1.6.1

Definition at line 8067 of file manager.c.

References AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, mansession_session::datastores, ast_datastore::info, mansession::session, and ast_datastore::uid.

{
   struct ast_datastore *datastore = NULL;

   if (info == NULL)
      return NULL;

   AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
      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;
int astman_datastore_remove ( struct mansession s,
struct ast_datastore datastore 
)

Remove a datastore from a session.

Return values:
0success
non-zerofailure
Since:
1.6.1

Definition at line 8062 of file manager.c.

References AST_LIST_REMOVE, mansession_session::datastores, and mansession::session.

{
   return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
int astman_is_authed ( uint32_t  ident)

Determinie if a manager session ident is authenticated.

Definition at line 6084 of file manager.c.

References ao2_unlock, mansession_session::authenticated, find_session(), and unref_mansession().

Referenced by http_post_callback(), and static_callback().

{
   int authed;
   struct mansession_session *session;

   if (!(session = find_session(ident, 0)))
      return 0;

   authed = (session->authenticated != 0);

   ao2_unlock(session);
   unref_mansession(session);

   return authed;
int astman_verify_session_readpermissions ( uint32_t  ident,
int  perm 
)

Verify a session's read permissions against a permission mask.

Parameters:
identsession identity
permpermission mask to verify
Return values:
1if the session has the permission mask capabilities
0otherwise

Definition at line 6100 of file manager.c.

References ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, mansession_session::managerid, mansession_session::readperm, sessions, and unref_mansession().

{
   int result = 0;
   struct mansession_session *session;
   struct ao2_container *sessions;
   struct ao2_iterator i;

   if (ident == 0) {
      return 0;
   }

   sessions = ao2_global_obj_ref(mgr_sessions);
   if (!sessions) {
      return 0;
   }
   i = ao2_iterator_init(sessions, 0);
   ao2_ref(sessions, -1);
   while ((session = ao2_iterator_next(&i))) {
      ao2_lock(session);
      if ((session->managerid == ident) && (session->readperm & perm)) {
         result = 1;
         ao2_unlock(session);
         unref_mansession(session);
         break;
      }
      ao2_unlock(session);
      unref_mansession(session);
   }
   ao2_iterator_destroy(&i);

   return result;
int astman_verify_session_writepermissions ( uint32_t  ident,
int  perm 
)

Verify a session's write permissions against a permission mask.

Parameters:
identsession identity
permpermission mask to verify
Return values:
1if the session has the permission mask capabilities, otherwise 0
0otherwise

Definition at line 6133 of file manager.c.

References ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, mansession_session::managerid, sessions, unref_mansession(), and mansession_session::writeperm.

Referenced by http_post_callback().

{
   int result = 0;
   struct mansession_session *session;
   struct ao2_container *sessions;
   struct ao2_iterator i;

   if (ident == 0) {
      return 0;
   }

   sessions = ao2_global_obj_ref(mgr_sessions);
   if (!sessions) {
      return 0;
   }
   i = ao2_iterator_init(sessions, 0);
   ao2_ref(sessions, -1);
   while ((session = ao2_iterator_next(&i))) {
      ao2_lock(session);
      if ((session->managerid == ident) && (session->writeperm & perm)) {
         result = 1;
         ao2_unlock(session);
         unref_mansession(session);
         break;
      }
      ao2_unlock(session);
      unref_mansession(session);
   }
   ao2_iterator_destroy(&i);

   return result;
static int auth_http_callback ( struct ast_tcptls_session_instance ser,
enum ast_http_method  method,
enum output_format  format,
const struct ast_sockaddr remote_address,
const char *  uri,
struct ast_variable get_params,
struct ast_variable headers 
) [static]

Definition at line 6656 of file manager.c.

References ast_manager_user::a1_hash, ast_manager_user::acl, mansession_session::addr, ao2_lock, ao2_unlock, ARRAY_LEN, ast_apply_acl(), ast_copy_string(), ast_debug, ast_free, ast_get_http_method(), ast_http_auth(), ast_http_error(), AST_HTTP_GET, ast_http_get_post_vars(), AST_HTTP_HEAD, AST_HTTP_POST, ast_http_send(), AST_LIST_HEAD_INIT_NOLOCK, ast_log(), ast_malloc, ast_md5_hash(), ast_mutex_destroy, ast_mutex_init, ast_parse_digest(), ast_random(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_sockaddr_stringify_addr(), ast_str_append(), ast_str_create(), ast_string_field_free_memory, ast_string_field_init, ast_strlen_zero(), ast_variables_destroy(), ast_verb, mansession_session::authenticated, build_mansession(), ast_http_digest::cnonce, mansession_session::datastores, ast_manager_user::displayconnects, errno, mansession_session::f, mansession::f, mansession_session::fd, mansession::fd, find_session_by_nonce(), FORMAT_HTML, FORMAT_XML, get_manager_by_name_locked(), get_params(), global_realm, grab_last(), message::hdrcount, message::headers, mansession_session::last_ev, mansession::lock, LOG_NOTICE, LOG_WARNING, mansession_session::managerid, ast_variable::name, ast_http_digest::nc, mansession_session::nc, mansession_session::needdestroy, ast_variable::next, ast_http_digest::nonce, mansession_session::noncetime, mansession_session::oldnonce, process_message(), process_output(), ast_http_digest::qop, mansession_session::readperm, ast_manager_user::readperm, ast_http_digest::response, mansession::session, session_destroy(), mansession_session::sessionstart, mansession_session::sessiontimeout, ast_http_digest::uri, ast_http_digest::username, mansession_session::username, ast_manager_user::username, ast_variable::value, mansession_session::writeperm, ast_manager_user::writeperm, mansession_session::writetimeout, and ast_manager_user::writetimeout.

Referenced by auth_manager_http_callback(), auth_mxml_http_callback(), and auth_rawman_http_callback().

{
   struct mansession_session *session = NULL;
   struct mansession s = { .session = NULL, .tcptls_session = ser };
   struct ast_variable *v, *params = get_params;
   char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
   struct ast_str *http_header = NULL, *out = NULL;
   size_t result_size = 512;
   struct message m = { 0 };
   unsigned int idx;
   size_t hdrlen;

   time_t time_now = time(NULL);
   unsigned long nonce = 0, nc;
   struct ast_http_digest d = { NULL, };
   struct ast_manager_user *user = NULL;
   int stale = 0;
   char resp_hash[256]="";
   /* Cache for user data */
   char u_username[80];
   int u_readperm;
   int u_writeperm;
   int u_writetimeout;
   int u_displayconnects;

   if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
      ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
      return -1;
   }

   /* Find "Authorization: " header */
   for (v = headers; v; v = v->next) {
      if (!strcasecmp(v->name, "Authorization")) {
         break;
      }
   }

   if (!v || ast_strlen_zero(v->value)) {
      goto out_401; /* Authorization Header not present - send auth request */
   }

   /* Digest found - parse */
   if (ast_string_field_init(&d, 128)) {
      ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
      return -1;
   }

   if (ast_parse_digest(v->value, &d, 0, 1)) {
      /* Error in Digest - send new one */
      nonce = 0;
      goto out_401;
   }
   if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
      ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
      nonce = 0;
      goto out_401;
   }

   AST_RWLIST_WRLOCK(&users);
   user = get_manager_by_name_locked(d.username);
   if(!user) {
      AST_RWLIST_UNLOCK(&users);
      ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
      nonce = 0;
      goto out_401;
   }

   /* --- We have User for this auth, now check ACL */
   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");
      return -1;
   }

   /* --- We have auth, so check it */

   /* compute the expected response to compare with what we received */
   {
      char a2[256];
      char a2_hash[256];
      char resp[256];

      /* XXX Now request method are hardcoded in A2 */
      snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
      ast_md5_hash(a2_hash, a2);

      if (d.qop) {
         /* RFC 2617 */
         snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
      }  else {
         /* RFC 2069 */
         snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
      }
      ast_md5_hash(resp_hash, resp);
   }

   if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
      /* Something was wrong, so give the client to try with a new challenge */
      AST_RWLIST_UNLOCK(&users);
      nonce = 0;
      goto out_401;
   }

   /*
    * User are pass Digest authentication.
    * Now, cache the user data and unlock user list.
    */
   ast_copy_string(u_username, user->username, sizeof(u_username));
   u_readperm = user->readperm;
   u_writeperm = user->writeperm;
   u_displayconnects = user->displayconnects;
   u_writetimeout = user->writetimeout;
   AST_RWLIST_UNLOCK(&users);

   if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
      /*
       * Create new session.
       * While it is not in the list we don't need any locking
       */
      if (!(session = build_mansession(remote_address))) {
         ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
         return -1;
      }
      ao2_lock(session);

      ast_copy_string(session->username, u_username, sizeof(session->username));
      session->managerid = nonce;
      session->last_ev = grab_last();
      AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);

      session->readperm = u_readperm;
      session->writeperm = u_writeperm;
      session->writetimeout = u_writetimeout;

      if (u_displayconnects) {
         ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
      }
      session->noncetime = session->sessionstart = time_now;
      session->authenticated = 1;
   } else if (stale) {
      /*
       * Session found, but nonce is stale.
       *
       * This could be because an old request (w/old nonce) arrived.
       *
       * This may be as the result of http proxy usage (separate delay or
       * multipath) or in a situation where a page was refreshed too quickly
       * (seen in Firefox).
       *
       * In this situation, we repeat the 401 auth with the current nonce
       * value.
       */
      nonce = session->managerid;
      ao2_unlock(session);
      stale = 1;
      goto out_401;
   } else {
      sscanf(d.nc, "%30lx", &nc);
      if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
         /*
          * Nonce time expired (> 2 minutes) or something wrong with nonce
          * counter.
          *
          * Create new nonce key and resend Digest auth request. Old nonce
          * is saved for stale checking...
          */
         session->nc = 0; /* Reset nonce counter */
         session->oldnonce = session->managerid;
         nonce = session->managerid = ast_random();
         session->noncetime = time_now;
         ao2_unlock(session);
         stale = 1;
         goto out_401;
      } else {
         session->nc = nc; /* All OK, save nonce counter */
      }
   }


   /* Reset session timeout. */
   session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
   ao2_unlock(session);

   ast_mutex_init(&s.lock);
   s.session = session;
   s.fd = mkstemp(template);  /* create a temporary file for command output */
   unlink(template);
   if (s.fd <= -1) {
      ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
      goto auth_callback_out;
   }
   s.f = fdopen(s.fd, "w+");
   if (!s.f) {
      ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
      ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
      close(s.fd);
      goto auth_callback_out;
   }

   if (method == AST_HTTP_POST) {
      params = ast_http_get_post_vars(ser, headers);
   }

   for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
      hdrlen = strlen(v->name) + strlen(v->value) + 3;
      m.headers[m.hdrcount] = ast_malloc(hdrlen);
      if (!m.headers[m.hdrcount]) {
         /* Allocation failure */
         continue;
      }
      snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
      ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
      ++m.hdrcount;
   }

   if (process_message(&s, &m)) {
      if (u_displayconnects) {
         ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
      }

      session->needdestroy = 1;
   }

   /* Free request headers. */
   for (idx = 0; idx < m.hdrcount; ++idx) {
      ast_free((void *) m.headers[idx]);
      m.headers[idx] = NULL;
   }

   if (s.f) {
      result_size = ftell(s.f); /* Calculate approx. size of result */
   }

   http_header = ast_str_create(80);
   out = ast_str_create(result_size * 2 + 512);

   if (http_header == NULL || out == NULL) {
      ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
      goto auth_callback_out;
   }

   ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]);

   if (format == FORMAT_XML) {
      ast_str_append(&out, 0, "<ajax-response>\n");
   } else if (format == FORMAT_HTML) {
      ast_str_append(&out, 0,
      "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
      "<html><head>\r\n"
      "<title>Asterisk&trade; Manager Interface</title>\r\n"
      "</head><body style=\"background-color: #ffffff;\">\r\n"
      "<form method=\"POST\">\r\n"
      "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
      "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
      "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
      "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
   }

   process_output(&s, &out, params, format);

   if (format == FORMAT_XML) {
      ast_str_append(&out, 0, "</ajax-response>\n");
   } else if (format == FORMAT_HTML) {
      ast_str_append(&out, 0, "</table></form></body></html>\r\n");
   }

   ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
   http_header = out = NULL;

auth_callback_out:
   ast_mutex_destroy(&s.lock);

   /* Clear resources and unlock manager session */
   if (method == AST_HTTP_POST && params) {
      ast_variables_destroy(params);
   }

   ast_free(http_header);
   ast_free(out);

   ao2_lock(session);
   if (session->f) {
      fclose(session->f);
   }
   session->f = NULL;
   session->fd = -1;
   ao2_unlock(session);

   if (session->needdestroy) {
      ast_debug(1, "Need destroy, doing it now!\n");
      session_destroy(session);
   }
   ast_string_field_free_memory(&d);
   return 0;

out_401:
   if (!nonce) {
      nonce = ast_random();
   }

   ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
   ast_string_field_free_memory(&d);
   return 0;
static int auth_manager_http_callback ( struct ast_tcptls_session_instance ser,
const struct ast_http_uri urih,
const char *  uri,
enum ast_http_method  method,
struct ast_variable get_params,
struct ast_variable headers 
) [static]

Definition at line 7026 of file manager.c.

References ast_sockaddr_copy(), auth_http_callback(), FORMAT_HTML, and ast_tcptls_session_instance::remote_address.

{
   int retval;
   struct ast_sockaddr ser_remote_address_tmp;

   ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
   retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
   ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
   return retval;
static int auth_mxml_http_callback ( struct ast_tcptls_session_instance ser,
const struct ast_http_uri urih,
const char *  uri,
enum ast_http_method  method,
struct ast_variable get_params,
struct ast_variable headers 
) [static]

Definition at line 7037 of file manager.c.

References ast_sockaddr_copy(), auth_http_callback(), FORMAT_XML, and ast_tcptls_session_instance::remote_address.

{
   int retval;
   struct ast_sockaddr ser_remote_address_tmp;

   ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
   retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
   ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
   return retval;
static int auth_rawman_http_callback ( struct ast_tcptls_session_instance ser,
const struct ast_http_uri urih,
const char *  uri,
enum ast_http_method  method,
struct ast_variable get_params,
struct ast_variable headers 
) [static]

Definition at line 7048 of file manager.c.

References ast_sockaddr_copy(), auth_http_callback(), FORMAT_RAW, and ast_tcptls_session_instance::remote_address.

{
   int retval;
   struct ast_sockaddr ser_remote_address_tmp;

   ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
   retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
   ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
   return retval;
static struct mansession_session* find_session ( uint32_t  ident,
int  incinuse 
) [static, read]

locate an http session in the list. The search key (ident) is the value of the mansession_id cookie (0 is not valid and means a session on the AMI socket).

Definition at line 6012 of file manager.c.

References ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_atomic_fetchadd_int(), mansession_session::inuse, mansession_session::managerid, mansession_session::needdestroy, sessions, and unref_mansession().

Referenced by astman_is_authed(), and generic_http_callback().

{
   struct ao2_container *sessions;
   struct mansession_session *session;
   struct ao2_iterator i;

   if (ident == 0) {
      return NULL;
   }

   sessions = ao2_global_obj_ref(mgr_sessions);
   if (!sessions) {
      return NULL;
   }
   i = ao2_iterator_init(sessions, 0);
   ao2_ref(sessions, -1);
   while ((session = ao2_iterator_next(&i))) {
      ao2_lock(session);
      if (session->managerid == ident && !session->needdestroy) {
         ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
         break;
      }
      ao2_unlock(session);
      unref_mansession(session);
   }
   ao2_iterator_destroy(&i);

   return session;
static struct mansession_session* find_session_by_nonce ( const char *  username,
unsigned long  nonce,
int *  stale 
) [static, read]

locate an http session in the list. The search keys (nonce) and (username) is value from received "Authorization" http header. As well as in find_session() function, the value of the nonce can't be zero. (0 meansi, that the session used for AMI socket connection). Flag (stale) is set, if client used valid, but old, nonce value.

Definition at line 6051 of file manager.c.

References ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, mansession_session::managerid, mansession_session::oldnonce, sessions, unref_mansession(), and mansession_session::username.

Referenced by auth_http_callback().

{
   struct mansession_session *session;
   struct ao2_container *sessions;
   struct ao2_iterator i;

   if (nonce == 0 || username == NULL || stale == NULL) {
      return NULL;
   }

   sessions = ao2_global_obj_ref(mgr_sessions);
   if (!sessions) {
      return NULL;
   }
   i = ao2_iterator_init(sessions, 0);
   ao2_ref(sessions, -1);
   while ((session = ao2_iterator_next(&i))) {
      ao2_lock(session);
      if (!strcasecmp(session->username, username) && session->managerid == nonce) {
         *stale = 0;
         break;
      } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
         *stale = 1;
         break;
      }
      ao2_unlock(session);
      unref_mansession(session);
   }
   ao2_iterator_destroy(&i);

   return session;
static int function_amiclient ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

${AMI_CLIENT()} Dialplan function - reads manager client data

Definition at line 7102 of file manager.c.

References ao2_callback_data, ao2_global_obj_ref, ao2_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_strip(), ast_strlen_zero(), get_manager_by_name_locked(), get_manager_sessions_cb(), LOG_ERROR, LOG_WARNING, and sessions.

{
   struct ast_manager_user *user = NULL;

   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(name);
      AST_APP_ARG(param);
   );


   if (ast_strlen_zero(data) ) {
      ast_log(LOG_WARNING, "AMI_CLIENT() requires two arguments: AMI_CLIENT(<name>[,<arg>])\n");
      return -1;
   }
   AST_STANDARD_APP_ARGS(args, data);
   args.name = ast_strip(args.name);
   args.param = ast_strip(args.param);

   AST_RWLIST_RDLOCK(&users);
   if (!(user = get_manager_by_name_locked(args.name))) {
      AST_RWLIST_UNLOCK(&users);
      ast_log(LOG_ERROR, "There's no manager user called : \"%s\"\n", args.name);
      return -1;
   }
   AST_RWLIST_UNLOCK(&users);

   if (!strcasecmp(args.param, "sessions")) {
      int no_sessions = 0;
      struct ao2_container *sessions;

      sessions = ao2_global_obj_ref(mgr_sessions);
      if (sessions) {
         ao2_callback_data(sessions, 0, get_manager_sessions_cb, /*login name*/ data, &no_sessions);
         ao2_ref(sessions, -1);
      }
      snprintf(buf, len, "%d", no_sessions);
   } else {
      ast_log(LOG_ERROR, "Invalid arguments provided to function AMI_CLIENT: %s\n", args.param);
      return -1;

   }

   return 0;
static int generic_http_callback ( struct ast_tcptls_session_instance ser,
enum ast_http_method  method,
enum output_format  format,
const struct ast_sockaddr remote_address,
const char *  uri,
struct ast_variable get_params,
struct ast_variable headers 
) [static]
Note:
There is approximately a 1 in 1.8E19 chance that the following calculation will produce 0, which is an invalid ID, but due to the properties of the rand() function (and the constantcy of s), that won't happen twice in a row.

Definition at line 6448 of file manager.c.

References mansession_session::addr, ao2_lock, ao2_unlock, ARRAY_LEN, ast_debug, ast_free, ast_http_error(), AST_HTTP_GET, ast_http_get_cookies(), ast_http_get_post_vars(), AST_HTTP_HEAD, AST_HTTP_POST, ast_http_send(), AST_LIST_HEAD_INIT_NOLOCK, ast_log(), ast_malloc, ast_mutex_destroy, ast_mutex_init, AST_PTHREADT_NULL, ast_random(), ast_sockaddr_stringify_addr(), ast_str_append(), ast_str_create(), ast_variables_destroy(), ast_verb, mansession_session::authenticated, build_mansession(), errno, mansession_session::f, mansession::f, mansession::fd, find_session(), FORMAT_HTML, FORMAT_XML, get_params(), grab_last(), message::hdrcount, message::headers, mansession_session::inuse, mansession::lock, LOG_WARNING, manager_displayconnects(), mansession_session::managerid, ast_variable::name, mansession_session::needdestroy, ast_variable::next, process_message(), process_output(), ROW_FMT, mansession_session::send_events, mansession::session, session_destroy(), mansession_session::sessiontimeout, TEST_STRING, mansession_session::username, ast_variable::value, and mansession_session::waiting_thread.

Referenced by manager_http_callback(), mxml_http_callback(), and rawman_http_callback().

{
   struct mansession s = { .session = NULL, .tcptls_session = ser };
   struct mansession_session *session = NULL;
   uint32_t ident = 0;
   int blastaway = 0;
   struct ast_variable *v, *cookies, *params = get_params;
   char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
   struct ast_str *http_header = NULL, *out = NULL;
   struct message m = { 0 };
   unsigned int idx;
   size_t hdrlen;

   if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
      ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
      return -1;
   }

   cookies = ast_http_get_cookies(headers);
   for (v = cookies; v; v = v->next) {
      if (!strcasecmp(v->name, "mansession_id")) {
         sscanf(v->value, "%30x", &ident);
         break;
      }
   }
   if (cookies) {
      ast_variables_destroy(cookies);
   }

   if (!(session = find_session(ident, 1))) {

      /**/
      /* Create new session.
       * While it is not in the list we don't need any locking
       */
      if (!(session = build_mansession(remote_address))) {
         ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
         return -1;
      }
      ao2_lock(session);
      session->send_events = 0;
      session->inuse = 1;
      /*!\note There is approximately a 1 in 1.8E19 chance that the following
       * calculation will produce 0, which is an invalid ID, but due to the
       * properties of the rand() function (and the constantcy of s), that
       * won't happen twice in a row.
       */
      while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
      session->last_ev = grab_last();
      AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
   }
   ao2_unlock(session);

   http_header = ast_str_create(128);
   out = ast_str_create(2048);

   ast_mutex_init(&s.lock);

   if (http_header == NULL || out == NULL) {
      ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
      goto generic_callback_out;
   }

   s.session = session;
   s.fd = mkstemp(template);  /* create a temporary file for command output */
   unlink(template);
   if (s.fd <= -1) {
      ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
      goto generic_callback_out;
   }
   s.f = fdopen(s.fd, "w+");
   if (!s.f) {
      ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
      ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
      close(s.fd);
      goto generic_callback_out;
   }

   if (method == AST_HTTP_POST) {
      params = ast_http_get_post_vars(ser, headers);
   }

   for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
      hdrlen = strlen(v->name) + strlen(v->value) + 3;
      m.headers[m.hdrcount] = ast_malloc(hdrlen);
      if (!m.headers[m.hdrcount]) {
         /* Allocation failure */
         continue;
      }
      snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
      ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
      ++m.hdrcount;
   }

   if (process_message(&s, &m)) {
      if (session->authenticated) {
         if (manager_displayconnects(session)) {
            ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
         }
      } else {
         if (displayconnects) {
            ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_sockaddr_stringify_addr(&session->addr));
         }
      }
      session->needdestroy = 1;
   }

   /* Free request headers. */
   for (idx = 0; idx < m.hdrcount; ++idx) {
      ast_free((void *) m.headers[idx]);
      m.headers[idx] = NULL;
   }

   ast_str_append(&http_header, 0,
      "Content-type: text/%s\r\n"
      "Cache-Control: no-cache;\r\n"
      "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
      "Pragma: SuppressEvents\r\n",
      contenttype[format],
      session->managerid, httptimeout);

   if (format == FORMAT_XML) {
      ast_str_append(&out, 0, "<ajax-response>\n");
   } else if (format == FORMAT_HTML) {
      /*
       * When handling AMI-over-HTTP in HTML format, we provide a simple form for
       * debugging purposes. This HTML code should not be here, we
       * should read from some config file...
       */

#define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
#define TEST_STRING \
   "<form action=\"manager\" method=\"post\">\n\
   Action: <select name=\"action\">\n\
      <option value=\"\">-----&gt;</option>\n\
      <option value=\"login\">login</option>\n\
      <option value=\"command\">Command</option>\n\
      <option value=\"waitevent\">waitevent</option>\n\
      <option value=\"listcommands\">listcommands</option>\n\
   </select>\n\
   or <input name=\"action\"><br/>\n\
   CLI Command <input name=\"command\"><br>\n\
   user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
   <input type=\"submit\">\n</form>\n"

      ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
      ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
      ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
      ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
   }

   process_output(&s, &out, params, format);

   if (format == FORMAT_XML) {
      ast_str_append(&out, 0, "</ajax-response>\n");
   } else if (format == FORMAT_HTML) {
      ast_str_append(&out, 0, "</table></body>\r\n");
   }

   ao2_lock(session);
   /* Reset HTTP timeout.  If we're not authenticated, keep it extremely short */
   session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);

   if (session->needdestroy) {
      if (session->inuse == 1) {
         ast_debug(1, "Need destroy, doing it now!\n");
         blastaway = 1;
      } else {
         ast_debug(1, "Need destroy, but can't do it yet!\n");
         if (session->waiting_thread != AST_PTHREADT_NULL) {
            pthread_kill(session->waiting_thread, SIGURG);
         }
         session->inuse--;
      }
   } else {
      session->inuse--;
   }
   ao2_unlock(session);

   ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
   http_header = out = NULL;

generic_callback_out:
   ast_mutex_destroy(&s.lock);

   /* Clear resource */

   if (method == AST_HTTP_POST && params) {
      ast_variables_destroy(params);
   }
   ast_free(http_header);
   ast_free(out);

   if (session && blastaway) {
      session_destroy(session);
   } else if (session && session->f) {
      fclose(session->f);
      session->f = NULL;
   }

   return 0;
static int get_manager_sessions_cb ( void *  obj,
void *  arg,
void *  data,
int  flags 
) [static]

Get number of logged in sessions for a login name.

Definition at line 7087 of file manager.c.

References mansession_session::username.

Referenced by function_amiclient().

{
   struct mansession_session *session = obj;
   const char *login = (char *)arg;
   int *no_sessions = data;

   if (strcasecmp(session->username, login) == 0) {
      (*no_sessions)++;
   }

   return 0;
static char* handle_manager_show_event ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7319 of file manager.c.

References ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_xml_doc_item::arguments, ast_cli_args::argv, ast_cli(), ast_free, ast_str_buffer(), ast_strdup, ast_strlen_zero(), ast_xmldoc_printable(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, COLOR_MAGENTA, ast_cli_entry::command, ast_xml_doc_item::description, events, ast_cli_args::fd, match(), ast_cli_args::n, ast_xml_doc_item::name, ast_xml_doc_item::next, OBJ_KEY, ast_xml_doc_item::seealso, ast_xml_doc_item::synopsis, synopsis, ast_xml_doc_item::syntax, term_color(), ast_cli_entry::usage, and ast_cli_args::word.

{
   RAII_VAR(struct ao2_container *, events, NULL, ao2_cleanup);
   struct ao2_iterator it_events;
   struct ast_xml_doc_item *item, *temp;
   int length;
   int which;
   char *match = NULL;
   char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];

   if (cmd == CLI_INIT) {
      e->command = "manager show event";
      e->usage =
         "Usage: manager show event <eventname>\n"
         "       Provides a detailed description a Manager interface event.\n";
      return NULL;
   }

   events = ao2_global_obj_ref(event_docs);
   if (!events) {
      ast_cli(a->fd, "No manager event documentation loaded\n");
      return CLI_SUCCESS;
   }

   if (cmd == CLI_GENERATE) {
      length = strlen(a->word);
      which = 0;
      it_events = ao2_iterator_init(events, 0);
      while ((item = ao2_iterator_next(&it_events))) {
         if (!strncasecmp(a->word, item->name, length) && ++which > a->n) {
            match = ast_strdup(item->name);
            ao2_ref(item, -1);
            break;
         }
         ao2_ref(item, -1);
      }
      ao2_iterator_destroy(&it_events);
      return match;
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   if (!(item = ao2_find(events, a->argv[3], OBJ_KEY))) {
      ast_cli(a->fd, "Could not find event '%s'\n", a->argv[3]);
      return CLI_SUCCESS;
   }

   term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
   term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
   term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
   term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
   term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);

   ast_cli(a->fd, "Event: %s\n", a->argv[3]);
   for (temp = item; temp; temp = temp->next) {
      if (!ast_strlen_zero(ast_str_buffer(temp->synopsis))) {
         char *synopsis = ast_xmldoc_printable(ast_str_buffer(temp->synopsis), 1);
         ast_cli(a->fd, "%s%s\n\n", synopsis_title, synopsis);
         ast_free(synopsis);
      }
      if (!ast_strlen_zero(ast_str_buffer(temp->syntax))) {
         char *syntax = ast_xmldoc_printable(ast_str_buffer(temp->syntax), 1);
         ast_cli(a->fd, "%s%s\n\n", syntax_title, syntax);
         ast_free(syntax);
      }
      if (!ast_strlen_zero(ast_str_buffer(temp->description))) {
         char *description = ast_xmldoc_printable(ast_str_buffer(temp->description), 1);
         ast_cli(a->fd, "%s%s\n\n", description_title, description);
         ast_free(description);
      }
      if (!ast_strlen_zero(ast_str_buffer(temp->arguments))) {
         char *arguments = ast_xmldoc_printable(ast_str_buffer(temp->arguments), 1);
         ast_cli(a->fd, "%s%s\n\n", arguments_title, arguments);
         ast_free(arguments);
      }
      if (!ast_strlen_zero(ast_str_buffer(temp->seealso))) {
         char *seealso = ast_xmldoc_printable(ast_str_buffer(temp->seealso), 1);
         ast_cli(a->fd, "%s%s\n\n", seealso_title, seealso);
         ast_free(seealso);
      }
   }

   ao2_ref(item, -1);
   return CLI_SUCCESS;
static char* handle_manager_show_events ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7238 of file manager.c.

References ao2_callback, ao2_container_count(), ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_cli_args::argc, ast_calloc, ast_cli(), ast_free, ast_log(), AST_LOG_ERROR, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), ast_xml_doc_item_cmp_fn(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, events, ast_cli_args::fd, OBJ_MULTIPLE, OBJ_NOLOCK, and ast_cli_entry::usage.

{
   struct ao2_container *events;
   struct ao2_iterator *it_events;
   struct ast_xml_doc_item *item;
   struct ast_xml_doc_item **items;
   struct ast_str *buffer;
   int i = 0, totalitems = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "manager show events";
      e->usage =
         "Usage: manager show events\n"
            "  Prints a listing of the available Asterisk manager interface events.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }
   if (a->argc != 3) {
      return CLI_SHOWUSAGE;
   }

   buffer = ast_str_create(128);
   if (!buffer) {
      return CLI_SUCCESS;
   }

   events = ao2_global_obj_ref(event_docs);
   if (!events) {
      ast_cli(a->fd, "No manager event documentation loaded\n");
      ast_free(buffer);
      return CLI_SUCCESS;
   }

   ao2_lock(events);
   if (!(it_events = ao2_callback(events, OBJ_MULTIPLE | OBJ_NOLOCK, NULL, NULL))) {
      ao2_unlock(events);
      ast_log(AST_LOG_ERROR, "Unable to create iterator for events container\n");
      ast_free(buffer);
      ao2_ref(events, -1);
      return CLI_SUCCESS;
   }
   if (!(items = ast_calloc(sizeof(struct ast_xml_doc_item *), ao2_container_count(events)))) {
      ao2_unlock(events);
      ast_log(AST_LOG_ERROR, "Unable to create temporary sorting array for events\n");
      ao2_iterator_destroy(it_events);
      ast_free(buffer);
      ao2_ref(events, -1);
      return CLI_SUCCESS;
   }
   ao2_unlock(events);

   while ((item = ao2_iterator_next(it_events))) {
      items[totalitems++] = item;
      ao2_ref(item, -1);
   }

   qsort(items, totalitems, sizeof(struct ast_xml_doc_item *), ast_xml_doc_item_cmp_fn);

   ast_cli(a->fd, "Events:\n");
   ast_cli(a->fd, "  --------------------  --------------------  --------------------  \n");
   for (i = 0; i < totalitems; i++) {
      ast_str_append(&buffer, 0, "  %-20.20s", items[i]->name);
      if ((i + 1) % 3 == 0) {
         ast_cli(a->fd, "%s\n", ast_str_buffer(buffer));
         ast_str_set(&buffer, 0, "%s", "");
      }
   }
   if ((i + 1) % 3 != 0) {
      ast_cli(a->fd, "%s\n", ast_str_buffer(buffer));
   }

   ao2_iterator_destroy(it_events);
   ast_free(items);
   ao2_ref(events, -1);
   ast_free(buffer);

   return CLI_SUCCESS;
static char* handle_manager_show_settings ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command manager show settings.

Definition at line 7189 of file manager.c.

References ami_tls_cfg, ast_cli_args::argc, ast_cli(), AST_CLI_YESNO, ast_sockaddr_stringify(), block_sockets, ast_tls_config::certfile, ast_tls_config::cipher, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_tls_config::enabled, ast_cli_args::fd, FORMAT, FORMAT2, ast_tcptls_session_args::local_address, ast_tls_config::pvtfile, S_OR, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "manager show settings";
      e->usage =
         "Usage: manager show settings\n"
         "       Provides detailed list of the configuration of the Manager.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }
#define FORMAT "  %-25.25s  %-15.55s\n"
#define FORMAT2 "  %-25.25s  %-15d\n"
   if (a->argc != 3) {
      return CLI_SHOWUSAGE;
   }
   ast_cli(a->fd, "\nGlobal Settings:\n");
   ast_cli(a->fd, "----------------\n");
   ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
   ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
   ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
   ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
   ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
   ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
   ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
   ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
   ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
   ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
   ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
   ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
   ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
   ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
   ast_cli(a->fd, FORMAT, "Block sockets:", AST_CLI_YESNO(block_sockets));
#undef FORMAT
#undef FORMAT2

   return CLI_SUCCESS;
int init_manager ( void  )

Called by Asterisk initialization.

Definition at line 8045 of file manager.c.

References __init_manager().

Referenced by main().

{
   return __init_manager(0, 0);
static void load_channelvars ( struct ast_variable var) [static]

Definition at line 7433 of file manager.c.

References ast_calloc, ast_free, AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, free_channelvars(), manager_channel_variable::isfunc, manager_channel_variable::name, manager_channel_variable::next, and ast_variable::value.

Referenced by __init_manager().

{
   struct manager_channel_variable *mcv;
   char *remaining = ast_strdupa(var->value);
   char *next;

   ast_free(manager_channelvars);
   manager_channelvars = ast_strdup(var->value);

   /*
    * XXX TODO: To allow dialplan functions to have more than one
    * parameter requires eliminating the '|' as a separator so we
    * could use AST_STANDARD_APP_ARGS() to separate items.
    */
   free_channelvars();
   AST_RWLIST_WRLOCK(&channelvars);
   while ((next = strsep(&remaining, ",|"))) {
      if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
         break;
      }
      strcpy(mcv->name, next); /* SAFE */
      if (strchr(next, '(')) {
         mcv->isfunc = 1;
      }
      AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
   }
   AST_RWLIST_UNLOCK(&channelvars);
static void manager_free_user ( struct ast_manager_user user) [static]

Definition at line 7463 of file manager.c.

References ast_manager_user::a1_hash, ast_manager_user::acl, ao2_t_ref, ast_free, ast_free_acl_list(), ast_variables_destroy(), ast_manager_user::blackfilters, ast_manager_user::chanvars, ast_manager_user::secret, and ast_manager_user::whitefilters.

Referenced by __init_manager(), and manager_shutdown().

{
   ast_free(user->a1_hash);
   ast_free(user->secret);
   if (user->whitefilters) {
      ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
   }
   if (user->blackfilters) {
      ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
   }
   user->acl = ast_free_acl_list(user->acl);
   ast_variables_destroy(user->chanvars);
   ast_free(user);
static int manager_http_callback ( struct ast_tcptls_session_instance ser,
const struct ast_http_uri urih,
const char *  uri,
enum ast_http_method  method,
struct ast_variable get_params,
struct ast_variable headers 
) [static]

Definition at line 6967 of file manager.c.

References ast_sockaddr_copy(), FORMAT_HTML, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

{
   int retval;
   struct ast_sockaddr ser_remote_address_tmp;

   ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
   retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
   ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
   return retval;
static void manager_shutdown ( void  ) [static]

Definition at line 7479 of file manager.c.

References ami_tls_cfg, ao2_global_obj_release, ao2_t_global_obj_release, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_free, AST_LIST_REMOVE_HEAD, ast_manager_unregister(), ast_tcptls_server_stop(), ast_tls_config::certfile, ast_tls_config::cipher, manager_free_user(), ast_tls_config::pvtfile, and user.

Referenced by __init_manager().

{
   struct ast_manager_user *user;

   ast_manager_unregister("Ping");
   ast_manager_unregister("Events");
   ast_manager_unregister("Logoff");
   ast_manager_unregister("Login");
   ast_manager_unregister("Challenge");
   ast_manager_unregister("Hangup");
   ast_manager_unregister("Status");
   ast_manager_unregister("Setvar");
   ast_manager_unregister("Getvar");
   ast_manager_unregister("GetConfig");
   ast_manager_unregister("GetConfigJSON");
   ast_manager_unregister("UpdateConfig");
   ast_manager_unregister("CreateConfig");
   ast_manager_unregister("ListCategories");
   ast_manager_unregister("Redirect");
   ast_manager_unregister("Atxfer");
   ast_manager_unregister("Originate");
   ast_manager_unregister("Command");
   ast_manager_unregister("ExtensionState");
   ast_manager_unregister("PresenceState");
   ast_manager_unregister("AbsoluteTimeout");
   ast_manager_unregister("MailboxStatus");
   ast_manager_unregister("MailboxCount");
   ast_manager_unregister("ListCommands");
   ast_manager_unregister("SendText");
   ast_manager_unregister("UserEvent");
   ast_manager_unregister("WaitEvent");
   ast_manager_unregister("CoreSettings");
   ast_manager_unregister("CoreStatus");
   ast_manager_unregister("Reload");
   ast_manager_unregister("CoreShowChannels");
   ast_manager_unregister("ModuleLoad");
   ast_manager_unregister("ModuleCheck");
   ast_manager_unregister("AOCMessage");
   ast_manager_unregister("Filter");
   ast_custom_function_unregister(&managerclient_function);
   ast_cli_unregister_multiple(cli_manager, ARRAY_LEN(cli_manager));

#ifdef AST_XML_DOCS
   ao2_t_global_obj_release(event_docs, "Dispose of event_docs");
#endif

   ast_tcptls_server_stop(&ami_desc);
   ast_tcptls_server_stop(&amis_desc);

   ast_free(ami_tls_cfg.certfile);
   ami_tls_cfg.certfile = NULL;
   ast_free(ami_tls_cfg.pvtfile);
   ami_tls_cfg.pvtfile = NULL;
   ast_free(ami_tls_cfg.cipher);
   ami_tls_cfg.cipher = NULL;

   ao2_global_obj_release(mgr_sessions);

   while ((user = AST_LIST_REMOVE_HEAD(&users, list))) {
      manager_free_user(user);
   }
static int mxml_http_callback ( struct ast_tcptls_session_instance ser,
const struct ast_http_uri urih,
const char *  uri,
enum ast_http_method  method,
struct ast_variable get_params,
struct ast_variable headers 
) [static]

Definition at line 6978 of file manager.c.

References ast_sockaddr_copy(), FORMAT_XML, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

{
   int retval;
   struct ast_sockaddr ser_remote_address_tmp;

   ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
   retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
   ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
   return retval;
static void process_output ( struct mansession s,
struct ast_str **  out,
struct ast_variable params,
enum output_format  format 
) [static]

Definition at line 6396 of file manager.c.

References ast_log(), ast_str_append(), errno, mansession::f, mansession::fd, FORMAT_HTML, FORMAT_XML, LOG_ERROR, LOG_WARNING, and xml_translate().

Referenced by auth_http_callback(), and generic_http_callback().

{
   char *buf;
   size_t l;

   if (!s->f)
      return;

   /* Ensure buffer is NULL-terminated */
   fprintf(s->f, "%c", 0);
   fflush(s->f);

   if ((l = ftell(s->f)) > 0) {
      if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) {
         ast_log(LOG_WARNING, "mmap failed.  Manager output was not processed\n");
      } else {
         if (format == FORMAT_XML || format == FORMAT_HTML) {
            xml_translate(out, buf, params, format);
         } else {
            ast_str_append(out, 0, "%s", buf);
         }
         munmap(buf, l);
      }
   } else if (format == FORMAT_XML || format == FORMAT_HTML) {
      xml_translate(out, "", params, format);
   }

   if (s->f) {
      /*
       * Issuing shutdown() is necessary here to avoid a race
       * condition where the last data written may not appear
       * in the the TCP stream.  See ASTERISK-23548
      */
      if (s->fd != -1) {
         shutdown(s->fd, SHUT_RDWR);
      }
      if (fclose(s->f)) {
         ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
      }
      s->f = NULL;
      s->fd = -1;
   } else if (s->fd != -1) {
      shutdown(s->fd, SHUT_RDWR);
      if (close(s->fd)) {
         ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
      }
      s->fd = -1;
   } else {
      ast_log(LOG_ERROR, "process output attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n");
   }
static void purge_old_stuff ( void *  data) [static]

cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most

Definition at line 7160 of file manager.c.

References purge_events(), and purge_sessions().

static int rawman_http_callback ( struct ast_tcptls_session_instance ser,
const struct ast_http_uri urih,
const char *  uri,
enum ast_http_method  method,
struct ast_variable get_params,
struct ast_variable headers 
) [static]

Definition at line 6989 of file manager.c.

References ast_sockaddr_copy(), FORMAT_RAW, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

{
   int retval;
   struct ast_sockaddr ser_remote_address_tmp;

   ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
   retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
   ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
   return retval;
int reload_manager ( void  )

Called by Asterisk module functions and the CLI command.

Definition at line 8050 of file manager.c.

References __init_manager().

Referenced by handle_manager_reload().

{
   return __init_manager(1, 0);
static int variable_count_cmp_fn ( void *  obj,
void *  vstr,
int  flags 
) [static]

Definition at line 6240 of file manager.c.

References CMP_MATCH, CMP_STOP, str, and variable_count::varname.

Referenced by xml_translate().

{
   /* Due to the simplicity of struct variable_count, it makes no difference
    * if you pass in objects or strings, the same operation applies. This is
    * due to the fact that the hash occurs on the first element, which means
    * the address of both the struct and the string are exactly the same. */
   struct variable_count *vc = obj;
   char *str = vstr;
   return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
static int variable_count_hash_fn ( const void *  vvc,
const int  flags 
) [static]

Definition at line 6233 of file manager.c.

References ast_str_hash(), and variable_count::varname.

Referenced by xml_translate().

{
   const struct variable_count *vc = vvc;

   return ast_str_hash(vc->varname);
static void xml_copy_escape ( struct ast_str **  out,
const char *  src,
int  mode 
) [static]

Definition at line 6171 of file manager.c.

References ast_str_append(), and ast_frame::src.

Referenced by xml_translate().

{
   /* store in a local buffer to avoid calling ast_str_append too often */
   char buf[256];
   char *dst = buf;
   int space = sizeof(buf);
   /* repeat until done and nothing to flush */
   for ( ; *src || dst != buf ; src++) {
      if (*src == '\0' || space < 10) {   /* flush */
         *dst++ = '\0';
         ast_str_append(out, 0, "%s", buf);
         dst = buf;
         space = sizeof(buf);
         if (*src == '\0') {
            break;
         }
      }

      if ( (mode & 2) && !isalnum(*src)) {
         *dst++ = '_';
         space--;
         continue;
      }
      switch (*src) {
      case '<':
         strcpy(dst, "&lt;");
         dst += 4;
         space -= 4;
         break;
      case '>':
         strcpy(dst, "&gt;");
         dst += 4;
         space -= 4;
         break;
      case '\"':
         strcpy(dst, "&quot;");
         dst += 6;
         space -= 6;
         break;
      case '\'':
         strcpy(dst, "&apos;");
         dst += 6;
         space -= 6;
         break;
      case '&':
         strcpy(dst, "&amp;");
         dst += 5;
         space -= 5;
         break;

      default:
         *dst++ = mode ? tolower(*src) : *src;
         space--;
      }
   }
static void xml_translate ( struct ast_str **  out,
char *  in,
struct ast_variable get_vars,
enum output_format  format 
) [static]

Convert the input into XML or HTML. The input is supposed to be a sequence of lines of the form Name: value optionally followed by a blob of unformatted text. A blank line is a section separator. Basically, this is a mixture of the format of Manager Interface and CLI commands. The unformatted text is considered as a single value of a field named 'Opaque-data'.

At the moment the output format is the following (but it may change depending on future requirements so don't count too much on it when writing applications):

General: the unformatted text is used as a value of XML output: to be completed

 *   Each section is within <response type="object" id="xxx">
 *   where xxx is taken from ajaxdest variable or defaults to unknown
 *   Each row is reported as an attribute Name="value" of an XML
 *   entity named from the variable ajaxobjtype, default to "generic"
 * 

HTML output: each Name-value pair is output as a single row of a two-column table. Sections (blank lines in the input) are separated by a


Definition at line 6279 of file manager.c.

References ao2_alloc, ao2_container_alloc, ao2_find, ao2_link, ao2_ref, ast_debug, ast_skip_blanks(), ast_str_append(), ast_strlen_zero(), ast_trim_blanks(), variable_count::count, FORMAT_XML, ast_variable::name, ast_variable::next, ast_variable::value, var, variable_count_cmp_fn(), variable_count_hash_fn(), variable_count::varname, and xml_copy_escape().

Referenced by process_output().

{
   struct ast_variable *v;
   const char *dest = NULL;
   char *var, *val;
   const char *objtype = NULL;
   int in_data = 0;  /* parsing data */
   int inobj = 0;
   int xml = (format == FORMAT_XML);
   struct variable_count *vc = NULL;
   struct ao2_container *vco = NULL;

   if (xml) {
      /* dest and objtype need only for XML format */
      for (v = get_vars; v; v = v->next) {
         if (!strcasecmp(v->name, "ajaxdest")) {
            dest = v->value;
         } else if (!strcasecmp(v->name, "ajaxobjtype")) {
            objtype = v->value;
         }
      }
      if (ast_strlen_zero(dest)) {
         dest = "unknown";
      }
      if (ast_strlen_zero(objtype)) {
         objtype = "generic";
      }
   }

   /* we want to stop when we find an empty line */
   while (in && *in) {
      val = strsep(&in, "\r\n"); /* mark start and end of line */
      if (in && *in == '\n') {   /* remove trailing \n if any */
         in++;
      }
      ast_trim_blanks(val);
      ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
      if (ast_strlen_zero(val)) {
         /* empty line */
         if (in_data) {
            /* close data in Opaque mode */
            ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
            in_data = 0;
         }

         if (inobj) {
            /* close block */
            ast_str_append(out, 0, xml ? " /></response>\n" :
               "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
            inobj = 0;
            ao2_ref(vco, -1);
            vco = NULL;
         }
         continue;
      }

      if (!inobj) {
         /* start new block */
         if (xml) {
            ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
         }
         vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
         inobj = 1;
      }

      if (in_data) {
         /* Process data field in Opaque mode. This is a
          * followup, so we re-add line feeds. */
         ast_str_append(out, 0, xml ? "\n" : "<br>\n");
         xml_copy_escape(out, val, 0);   /* data field */
         continue;
      }

      /* We expect "Name: value" line here */
      var = strsep(&val, ":");
      if (val) {
         /* found the field name */
         val = ast_skip_blanks(val);
         ast_trim_blanks(var);
      } else {
         /* field name not found, switch to opaque mode */
         val = var;
         var = "Opaque-data";
         in_data = 1;
      }


      ast_str_append(out, 0, xml ? " " : "<tr><td>");
      if ((vc = ao2_find(vco, var, 0))) {
         vc->count++;
      } else {
         /* Create a new entry for this one */
         vc = ao2_alloc(sizeof(*vc), NULL);
         vc->varname = var;
         vc->count = 1;
         ao2_link(vco, vc);
      }

      xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
      if (vc->count > 1) {
         ast_str_append(out, 0, "-%d", vc->count);
      }
      ao2_ref(vc, -1);
      ast_str_append(out, 0, xml ? "='" : "</td><td>");
      xml_copy_escape(out, val, 0); /* data field */
      if (!in_data || !*in) {
         ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
      }
   }

   if (inobj) {
      ast_str_append(out, 0, xml ? " /></response>\n" :
         "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
      ao2_ref(vco, -1);
   }

Variable Documentation

struct ast_http_uri amanageruri [static]

Definition at line 7068 of file manager.c.

struct ast_http_uri amanagerxmluri [static]

Definition at line 7077 of file manager.c.

Definition at line 7167 of file manager.c.

Definition at line 7178 of file manager.c.

struct ast_http_uri arawmanuri [static]

Definition at line 7059 of file manager.c.

struct ast_cli_entry cli_manager[] [static]

Definition at line 7409 of file manager.c.

const char* const contenttype[] [static]
Initial value:
 {
   [FORMAT_RAW] = "plain",
   [FORMAT_HTML] = "html",
   [FORMAT_XML] =  "xml",
}

Definition at line 6001 of file manager.c.

Initial value:
 {
   .name = "AMI_CLIENT",
   .read = function_amiclient,
   .read_max = 12,
}

description of AMI_CLIENT dialplan function

Definition at line 7149 of file manager.c.

struct ast_http_uri manageruri [static]

Definition at line 7008 of file manager.c.

struct ast_http_uri managerxmluri [static]

Definition at line 7016 of file manager.c.

struct ast_http_uri rawmanuri [static]

Definition at line 7000 of file manager.c.

int webregged = 0 [static]

Definition at line 7155 of file manager.c.

const char* words[AST_MAX_CMD_LEN]

Definition at line 1042 of file manager.c.

Referenced by check_blacklist().