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"
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=\"\">-----></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_action * | action_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 eventqent * | advance_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_datastore * | astman_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_variable * | astman_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_session * | build_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_session * | find_session (uint32_t ident, int incinuse) |
| static struct mansession_session * | find_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_user * | get_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 eventqent * | grab_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_variable * | man_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_session * | unref_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_sub * | acl_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 |
The Asterisk Management Interface - AMI.
At the moment this file contains a number of functions, namely:
Definition in file manager.c.
| #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=\"\">-----></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().
| enum output_format |
| 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.
| 0 | success |
| non-zero | failure |
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.
| pointer | to the datastore if found |
| NULL | if not found |
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.
| 0 | success |
| non-zero | failure |
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.
| ident | session identity |
| perm | permission mask to verify |
| 1 | if the session has the permission mask capabilities |
| 0 | otherwise |
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.
| ident | session identity |
| perm | permission mask to verify |
| 1 | if the session has the permission mask capabilities, otherwise 0 |
| 0 | otherwise |
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™ 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] |
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=\"\">-----></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™ 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_set_defaults | ( | void | ) | [static] |
Definition at line 7542 of file manager.c.
References ami_tls_cfg, AST_CERTFILE, ast_config_AST_SYSTEM_NAME, ast_copy_string(), ast_free, ast_sockaddr_setnull(), ast_strdup, ast_tls_config::certfile, ast_tls_config::cipher, DEFAULT_REALM, ast_tls_config::enabled, free_channelvars(), global_realm, ast_tcptls_session_args::local_address, ast_tls_config::pvtfile, and S_OR.
Referenced by __init_manager().
{
manager_enabled = 0;
displayconnects = 1;
broken_events_action = 0;
authtimeout = 30;
authlimit = 50;
manager_debug = 0; /* Debug disabled by default */
/* default values */
ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM),
sizeof(global_realm));
ast_sockaddr_setnull(&ami_desc.local_address);
ast_sockaddr_setnull(&amis_desc.local_address);
ami_tls_cfg.enabled = 0;
ast_free(ami_tls_cfg.certfile);
ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
ast_free(ami_tls_cfg.pvtfile);
ami_tls_cfg.pvtfile = ast_strdup("");
ast_free(ami_tls_cfg.cipher);
ami_tls_cfg.cipher = ast_strdup("");
free_channelvars();
| 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().
{
purge_sessions(1);
purge_events();
| 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, "<");
dst += 4;
space -= 4;
break;
case '>':
strcpy(dst, ">");
dst += 4;
space -= 4;
break;
case '\"':
strcpy(dst, """);
dst += 6;
space -= 6;
break;
case '\'':
strcpy(dst, "'");
dst += 6;
space -= 6;
break;
case '&':
strcpy(dst, "&");
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);
}
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] |
Definition at line 7166 of file manager.c.
Referenced by __init_manager(), handle_manager_show_settings(), manager_set_defaults(), and manager_shutdown().
struct ast_tcptls_session_args amis_desc [static] |
struct ast_http_uri arawmanuri [static] |
struct ast_cli_entry cli_manager[] [static] |
const char* const contenttype[] [static] |
{
[FORMAT_RAW] = "plain",
[FORMAT_HTML] = "html",
[FORMAT_XML] = "xml",
}
struct ast_custom_function managerclient_function [static] |
{
.name = "AMI_CLIENT",
.read = function_amiclient,
.read_max = 12,
}
description of AMI_CLIENT dialplan function
struct ast_http_uri manageruri [static] |
struct ast_http_uri managerxmluri [static] |
struct ast_http_uri rawmanuri [static] |
| const char* words[AST_MAX_CMD_LEN] |
Definition at line 1042 of file manager.c.
Referenced by check_blacklist().