#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/aoc.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 |
struct | mansession_session |
struct | mansession_session::mansession_datastores |
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 | |
#define | DEFAULT_REALM "asterisk" |
#define | FORMAT " %-25.25s %-15.15s\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 %-15.15s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n" |
#define | HSMCONN_FORMAT2 " %-15.15s %-15.15s %-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) |
send a response with an optional message, and terminate it with an empty line. m is used only to grab the 'ActionID' field. | |
#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 | 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 | 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) |
static void | __init_astman_append_buf (void) |
thread local buffer for astman_append | |
static int | __init_manager (int reload) |
static void | __init_manager_event_buf (void) |
static void | __init_manager_event_funcbuf (void) |
static void | __init_userevent_buf (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 int | action_events (struct mansession *s, const struct message *m) |
static int | action_extensionstate (struct mansession *s, const struct message *m) |
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_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 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) |
int | ast_hook_send_action (struct manager_custom_hook *hook, const char *msg) |
Registered hooks can call this function to invoke actions and they will receive responses through registered callback. | |
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), const char *synopsis, const char *description) |
Register a manager command with the manager interface. | |
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 (char *action) |
Unregister a registered manager command. | |
void | ast_manager_unregister_hook (struct manager_custom_hook *hook) |
Delete a custom hook to be called when an event is fired. | |
void | astman_append (struct mansession *s, const char *fmt,...) |
int | astman_datastore_add (struct mansession *s, struct ast_datastore *datastore) |
Add a datastore to a session. | |
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) |
Get header from mananger transaction. | |
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_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) |
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, struct sockaddr_in *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. | |
static int | blackfilter_cmp_fn (void *obj, void *arg, void *data, int flags) |
static struct mansession_session * | build_mansession (struct sockaddr_in sin) |
Allocate manager session structure and add it to the list of sessions. | |
static int | check_blacklist (const char *cmd) |
int | check_manager_enabled () |
Check if AMI is enabled. | |
static int | check_manager_session_inuse (const char *name) |
int | check_webmanager_enabled () |
Check if AMI/HTTP is enabled. | |
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 | generic_http_callback (struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, struct sockaddr_in *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_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_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 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) |
int | init_manager (void) |
Called by Asterisk initialization. | |
static void | json_escape (char *out, const char *in) |
static int | manager_displayconnects (struct mansession_session *session) |
Get displayconnects config option. | |
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) |
static int | manager_moduleload (struct mansession *s, const struct message *m) |
static int | manager_state_cb (char *context, char *exten, int state, void *data) |
static int | mansession_cmp_fn (void *obj, void *arg, int flags) |
static struct sockaddr_in * | mansession_encode_sin_local (const struct mansession *s, struct sockaddr_in *sin_local) |
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) |
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 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 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 |
static struct ast_cli_entry | cli_manager [] |
struct { | |
const char * words [AST_MAX_CMD_LEN] | |
} | command_blacklist [] |
static const char *const | contenttype [] |
static const int | DEFAULT_AUTHLIMIT = 50 |
static const int | DEFAULT_AUTHTIMEOUT = 30 |
static const int | DEFAULT_BLOCKSOCKETS = 0 |
static const int | DEFAULT_BROKENEVENTSACTION = 0 |
static const int | DEFAULT_DISPLAYCONNECTS = 1 |
static const int | DEFAULT_ENABLED = 0 |
static const int | DEFAULT_HTTPTIMEOUT = 60 |
static const int | DEFAULT_TIMESTAMPEVENTS = 0 |
static const int | DEFAULT_WEBENABLED = 0 |
static int | displayconnects |
static char | global_realm [MAXHOSTNAMELEN] |
static int | httptimeout |
static char * | manager_channelvars |
static int | manager_debug |
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 ast_http_uri | manageruri |
static struct ast_http_uri | managerxmluri |
static struct permalias | perms [] |
static struct ast_http_uri | rawmanuri |
static int | registered = 0 |
static struct ao2_container * | sessions = NULL |
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 int | webmanager_enabled = 0 |
static int | webregged = 0 |
Definition in file manager.c.
#define FORMAT " %-25.25s %-15.15s\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 %-15.15s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n" |
Referenced by handle_showmanconn().
#define HSMCONN_FORMAT2 " %-15.15s %-15.15s %-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" |
#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" |
enum output_format |
END Doxygen group
Definition at line 5058 of file manager.c.
05058 { 05059 FORMAT_RAW, 05060 FORMAT_HTML, 05061 FORMAT_XML, 05062 };
static int __init_manager | ( | int | reload | ) | [static] |
Definition at line 6184 of file manager.c.
References action_aocmessage(), action_atxfer(), action_challenge(), action_command(), action_coresettings(), action_coreshowchannels(), action_corestatus(), action_createconfig(), action_events(), action_extensionstate(), 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_redirect(), action_reload(), action_sendtext(), action_setvar(), action_status(), action_timeout(), action_updateconfig(), action_userevent(), action_waitevent(), ami_desc, ami_tls_cfg, amis_desc, append_event(), ARRAY_LEN, AST_CERTFILE, ast_cli_register_multiple(), ast_config_AST_SYSTEM_NAME, ast_config_load2(), ast_copy_string(), ast_extension_state_add(), ast_free, ast_log(), ast_manager_register_xml, ast_strdup, ast_tls_read_conf(), ast_true(), ast_variable_browse(), authlimit, authtimeout, block_sockets, broken_events_action, ast_tls_config::certfile, ast_tls_config::cipher, cli_manager, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_AUTHLIMIT, DEFAULT_AUTHTIMEOUT, DEFAULT_BLOCKSOCKETS, DEFAULT_BROKENEVENTSACTION, DEFAULT_DISPLAYCONNECTS, DEFAULT_ENABLED, DEFAULT_HTTPTIMEOUT, DEFAULT_MANAGER_PORT, DEFAULT_REALM, DEFAULT_TIMESTAMPEVENTS, DEFAULT_WEBENABLED, 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, free_channelvars(), global_realm, httptimeout, ast_tcptls_session_args::local_address, LOG_NOTICE, manager_enabled, manager_modulecheck(), manager_moduleload(), manager_state_cb(), ast_tls_config::pvtfile, S_OR, timestampevents, var, and webmanager_enabled.
Referenced by init_manager(), and reload_manager().
06185 { 06186 struct ast_config *ucfg = NULL, *cfg = NULL; 06187 const char *val; 06188 char *cat = NULL; 06189 int newhttptimeout = DEFAULT_HTTPTIMEOUT; 06190 struct ast_manager_user *user = NULL; 06191 struct ast_variable *var; 06192 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06193 char a1[256]; 06194 char a1_hash[256]; 06195 struct sockaddr_in ami_desc_local_address_tmp = { 0, }; 06196 struct sockaddr_in amis_desc_local_address_tmp = { 0, }; 06197 06198 if (!registered) { 06199 /* Register default actions */ 06200 ast_manager_register_xml("Ping", 0, action_ping); 06201 ast_manager_register_xml("Events", 0, action_events); 06202 ast_manager_register_xml("Logoff", 0, action_logoff); 06203 ast_manager_register_xml("Login", 0, action_login); 06204 ast_manager_register_xml("Challenge", 0, action_challenge); 06205 ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup); 06206 ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status); 06207 ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar); 06208 ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar); 06209 ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig); 06210 ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson); 06211 ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig); 06212 ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig); 06213 ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories); 06214 ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect); 06215 ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer); 06216 ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate); 06217 ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command); 06218 ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate); 06219 ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout); 06220 ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus); 06221 ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount); 06222 ast_manager_register_xml("ListCommands", 0, action_listcommands); 06223 ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext); 06224 ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent); 06225 ast_manager_register_xml("WaitEvent", 0, action_waitevent); 06226 ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings); 06227 ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus); 06228 ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload); 06229 ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels); 06230 ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload); 06231 ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck); 06232 ast_manager_register_xml("AOCMessage", EVENT_FLAG_AOC, action_aocmessage); 06233 06234 ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager)); 06235 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL); 06236 registered = 1; 06237 /* Append placeholder event so master_eventq never runs dry */ 06238 append_event("Event: Placeholder\r\n\r\n", 0); 06239 } 06240 if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) { 06241 return 0; 06242 } 06243 06244 manager_enabled = DEFAULT_ENABLED; 06245 webmanager_enabled = DEFAULT_WEBENABLED; 06246 displayconnects = DEFAULT_DISPLAYCONNECTS; 06247 broken_events_action = DEFAULT_BROKENEVENTSACTION; 06248 block_sockets = DEFAULT_BLOCKSOCKETS; 06249 timestampevents = DEFAULT_TIMESTAMPEVENTS; 06250 httptimeout = DEFAULT_HTTPTIMEOUT; 06251 authtimeout = DEFAULT_AUTHTIMEOUT; 06252 authlimit = DEFAULT_AUTHLIMIT; 06253 06254 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { 06255 ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled.\n"); 06256 return 0; 06257 } 06258 06259 /* default values */ 06260 ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm)); 06261 memset(&ami_desc.local_address, 0, sizeof(struct sockaddr_in)); 06262 memset(&amis_desc.local_address, 0, sizeof(amis_desc.local_address)); 06263 amis_desc_local_address_tmp.sin_port = htons(5039); 06264 ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT); 06265 06266 ami_tls_cfg.enabled = 0; 06267 if (ami_tls_cfg.certfile) { 06268 ast_free(ami_tls_cfg.certfile); 06269 } 06270 ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE); 06271 if (ami_tls_cfg.pvtfile) { 06272 ast_free(ami_tls_cfg.pvtfile); 06273 } 06274 ami_tls_cfg.pvtfile = ast_strdup(""); 06275 if (ami_tls_cfg.cipher) { 06276 ast_free(ami_tls_cfg.cipher); 06277 } 06278 ami_tls_cfg.cipher = ast_strdup(""); 06279 06280 free_channelvars(); 06281 06282 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 06283 val = var->value; 06284 06285 if (!ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) { 06286 continue; 06287 } 06288 06289 if (!strcasecmp(var->name, "enabled")) { 06290 manager_enabled = ast_true(val); 06291 } else if (!strcasecmp(var->name, "block-sockets")) { 06292 block_sockets = ast_true(val); 06293 } else if (!strcasecmp(var->name, "webenabled")) { 06294 webmanager_enabled = ast_true(val); 06295 } else if (!strcasecmp(var->name, "port")) { 06296 ami_desc_local_address_tmp.sin_port = htons(atoi(val)); 06297 } else if (!strcasecmp(var->name, "bindaddr")) { 06298 if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) { 06299 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val); 06300 memset(&ami_desc_local_address_tmp.sin_addr, 0, 06301 sizeof(ami_desc_local_address_tmp.sin_addr)); 06302 } 06303 } else if (!strcasecmp(var->name, "brokeneventsaction")) { 06304 broken_events_action = ast_true(val); 06305 } else if (!strcasecmp(var->name, "allowmultiplelogin")) { 06306 allowmultiplelogin = ast_true(val); 06307 } else if (!strcasecmp(var->name, "displayconnects")) { 06308 displayconnects = ast_true(val); 06309 } else if (!strcasecmp(var->name, "timestampevents")) { 06310 timestampevents = ast_true(val); 06311 } else if (!strcasecmp(var->name, "debug")) { 06312 manager_debug = ast_true(val); 06313 } else if (!strcasecmp(var->name, "httptimeout")) { 06314 newhttptimeout = atoi(val); 06315 } else if (!strcasecmp(var->name, "authtimeout")) { 06316 int timeout = atoi(var->value); 06317 06318 if (timeout < 1) { 06319 ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value); 06320 } else { 06321 authtimeout = timeout; 06322 } 06323 } else if (!strcasecmp(var->name, "authlimit")) { 06324 int limit = atoi(var->value); 06325 06326 if (limit < 1) { 06327 ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value); 06328 } else { 06329 authlimit = limit; 06330 } 06331 } else if (!strcasecmp(var->name, "channelvars")) { 06332 struct manager_channel_variable *mcv; 06333 char *remaining = ast_strdupa(val), *next; 06334 ast_free(manager_channelvars); 06335 manager_channelvars = ast_strdup(val); 06336 AST_RWLIST_WRLOCK(&channelvars); 06337 while ((next = strsep(&remaining, ",|"))) { 06338 if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) { 06339 break; 06340 } 06341 strcpy(mcv->name, next); /* SAFE */ 06342 if (strchr(next, '(')) { 06343 mcv->isfunc = 1; 06344 } 06345 AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry); 06346 } 06347 AST_RWLIST_UNLOCK(&channelvars); 06348 } else { 06349 ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n", 06350 var->name, val); 06351 } 06352 } 06353 06354 ami_desc_local_address_tmp.sin_family = AF_INET; 06355 amis_desc_local_address_tmp.sin_family = AF_INET; 06356 06357 /* if the amis address has not been set, default is the same as non secure ami */ 06358 if (!amis_desc_local_address_tmp.sin_addr.s_addr) { 06359 amis_desc_local_address_tmp.sin_addr = 06360 ami_desc_local_address_tmp.sin_addr; 06361 } 06362 06363 if (manager_enabled) { 06364 ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp); 06365 ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp); 06366 } 06367 06368 AST_RWLIST_WRLOCK(&users); 06369 06370 /* First, get users from users.conf */ 06371 ucfg = ast_config_load2("users.conf", "manager", config_flags); 06372 if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) { 06373 const char *hasmanager; 06374 int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager")); 06375 06376 while ((cat = ast_category_browse(ucfg, cat))) { 06377 if (!strcasecmp(cat, "general")) { 06378 continue; 06379 } 06380 06381 hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager"); 06382 if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) { 06383 const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret"); 06384 const char *user_read = ast_variable_retrieve(ucfg, cat, "read"); 06385 const char *user_write = ast_variable_retrieve(ucfg, cat, "write"); 06386 const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects"); 06387 const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout"); 06388 06389 /* Look for an existing entry, 06390 * if none found - create one and add it to the list 06391 */ 06392 if (!(user = get_manager_by_name_locked(cat))) { 06393 if (!(user = ast_calloc(1, sizeof(*user)))) { 06394 break; 06395 } 06396 06397 /* Copy name over */ 06398 ast_copy_string(user->username, cat, sizeof(user->username)); 06399 /* Insert into list */ 06400 AST_LIST_INSERT_TAIL(&users, user, list); 06401 user->ha = NULL; 06402 user->keep = 1; 06403 user->readperm = -1; 06404 user->writeperm = -1; 06405 /* Default displayconnect from [general] */ 06406 user->displayconnects = displayconnects; 06407 user->writetimeout = 100; 06408 } 06409 06410 if (!user_secret) { 06411 user_secret = ast_variable_retrieve(ucfg, "general", "secret"); 06412 } 06413 if (!user_read) { 06414 user_read = ast_variable_retrieve(ucfg, "general", "read"); 06415 } 06416 if (!user_write) { 06417 user_write = ast_variable_retrieve(ucfg, "general", "write"); 06418 } 06419 if (!user_displayconnects) { 06420 user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects"); 06421 } 06422 if (!user_writetimeout) { 06423 user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout"); 06424 } 06425 06426 if (!ast_strlen_zero(user_secret)) { 06427 if (user->secret) { 06428 ast_free(user->secret); 06429 } 06430 user->secret = ast_strdup(user_secret); 06431 } 06432 06433 if (user_read) { 06434 user->readperm = get_perm(user_read); 06435 } 06436 if (user_write) { 06437 user->writeperm = get_perm(user_write); 06438 } 06439 if (user_displayconnects) { 06440 user->displayconnects = ast_true(user_displayconnects); 06441 } 06442 if (user_writetimeout) { 06443 int value = atoi(user_writetimeout); 06444 if (value < 100) { 06445 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at users.conf line %d\n", var->value, var->lineno); 06446 } else { 06447 user->writetimeout = value; 06448 } 06449 } 06450 } 06451 } 06452 ast_config_destroy(ucfg); 06453 } 06454 06455 /* cat is NULL here in any case */ 06456 06457 while ((cat = ast_category_browse(cfg, cat))) { 06458 struct ast_ha *oldha; 06459 06460 if (!strcasecmp(cat, "general")) { 06461 continue; 06462 } 06463 06464 /* Look for an existing entry, if none found - create one and add it to the list */ 06465 if (!(user = get_manager_by_name_locked(cat))) { 06466 if (!(user = ast_calloc(1, sizeof(*user)))) { 06467 break; 06468 } 06469 /* Copy name over */ 06470 ast_copy_string(user->username, cat, sizeof(user->username)); 06471 06472 user->ha = NULL; 06473 user->readperm = 0; 06474 user->writeperm = 0; 06475 /* Default displayconnect from [general] */ 06476 user->displayconnects = displayconnects; 06477 user->writetimeout = 100; 06478 user->whitefilters = ao2_container_alloc(1, NULL, NULL); 06479 user->blackfilters = ao2_container_alloc(1, NULL, NULL); 06480 06481 /* Insert into list */ 06482 AST_RWLIST_INSERT_TAIL(&users, user, list); 06483 } else { 06484 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters"); 06485 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters"); 06486 } 06487 06488 /* Make sure we keep this user and don't destroy it during cleanup */ 06489 user->keep = 1; 06490 oldha = user->ha; 06491 user->ha = NULL; 06492 06493 var = ast_variable_browse(cfg, cat); 06494 for (; var; var = var->next) { 06495 if (!strcasecmp(var->name, "secret")) { 06496 if (user->secret) { 06497 ast_free(user->secret); 06498 } 06499 user->secret = ast_strdup(var->value); 06500 } else if (!strcasecmp(var->name, "deny") || 06501 !strcasecmp(var->name, "permit")) { 06502 user->ha = ast_append_ha(var->name, var->value, user->ha, NULL); 06503 } else if (!strcasecmp(var->name, "read") ) { 06504 user->readperm = get_perm(var->value); 06505 } else if (!strcasecmp(var->name, "write") ) { 06506 user->writeperm = get_perm(var->value); 06507 } else if (!strcasecmp(var->name, "displayconnects") ) { 06508 user->displayconnects = ast_true(var->value); 06509 } else if (!strcasecmp(var->name, "writetimeout")) { 06510 int value = atoi(var->value); 06511 if (value < 100) { 06512 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno); 06513 } else { 06514 user->writetimeout = value; 06515 } 06516 } else if (!strcasecmp(var->name, "eventfilter")) { 06517 const char *value = var->value; 06518 regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation"); 06519 if (new_filter) { 06520 int is_blackfilter; 06521 if (value[0] == '!') { 06522 is_blackfilter = 1; 06523 value++; 06524 } else { 06525 is_blackfilter = 0; 06526 } 06527 if (regcomp(new_filter, value, 0)) { 06528 ao2_t_ref(new_filter, -1, "failed to make regx"); 06529 } else { 06530 if (is_blackfilter) { 06531 ao2_t_link(user->blackfilters, new_filter, "link new filter into black user container"); 06532 } else { 06533 ao2_t_link(user->whitefilters, new_filter, "link new filter into white user container"); 06534 } 06535 } 06536 } 06537 } else { 06538 ast_debug(1, "%s is an unknown option.\n", var->name); 06539 } 06540 } 06541 ast_free_ha(oldha); 06542 } 06543 ast_config_destroy(cfg); 06544 06545 /* Perform cleanup - essentially prune out old users that no longer exist */ 06546 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) { 06547 if (user->keep) { /* valid record. clear flag for the next round */ 06548 user->keep = 0; 06549 06550 /* Calculate A1 for Digest auth */ 06551 snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret); 06552 ast_md5_hash(a1_hash,a1); 06553 if (user->a1_hash) { 06554 ast_free(user->a1_hash); 06555 } 06556 user->a1_hash = ast_strdup(a1_hash); 06557 continue; 06558 } 06559 /* We do not need to keep this user so take them out of the list */ 06560 AST_RWLIST_REMOVE_CURRENT(list); 06561 ast_debug(4, "Pruning user '%s'\n", user->username); 06562 /* Free their memory now */ 06563 if (user->a1_hash) { 06564 ast_free(user->a1_hash); 06565 } 06566 if (user->secret) { 06567 ast_free(user->secret); 06568 } 06569 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters"); 06570 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters"); 06571 ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one"); 06572 ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one"); 06573 ast_free_ha(user->ha); 06574 ast_free(user); 06575 } 06576 AST_RWLIST_TRAVERSE_SAFE_END; 06577 06578 AST_RWLIST_UNLOCK(&users); 06579 06580 if (!reload) { 06581 /* If you have a NULL hash fn, you only need a single bucket */ 06582 sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn); 06583 } 06584 06585 if (webmanager_enabled && manager_enabled) { 06586 if (!webregged) { 06587 06588 ast_http_uri_link(&rawmanuri); 06589 ast_http_uri_link(&manageruri); 06590 ast_http_uri_link(&managerxmluri); 06591 06592 ast_http_uri_link(&arawmanuri); 06593 ast_http_uri_link(&amanageruri); 06594 ast_http_uri_link(&amanagerxmluri); 06595 webregged = 1; 06596 } 06597 } else { 06598 if (webregged) { 06599 ast_http_uri_unlink(&rawmanuri); 06600 ast_http_uri_unlink(&manageruri); 06601 ast_http_uri_unlink(&managerxmluri); 06602 06603 ast_http_uri_unlink(&arawmanuri); 06604 ast_http_uri_unlink(&amanageruri); 06605 ast_http_uri_unlink(&amanagerxmluri); 06606 webregged = 0; 06607 } 06608 } 06609 06610 if (newhttptimeout > 0) { 06611 httptimeout = newhttptimeout; 06612 } 06613 06614 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled"); 06615 06616 ast_tcptls_server_start(&ami_desc); 06617 if (ast_ssl_setup(amis_desc.tls_cfg)) { 06618 ast_tcptls_server_start(&amis_desc); 06619 } 06620 return 0; 06621 }
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 6644 of file manager.c.
References AST_LIST_INSERT_HEAD, mansession_session::datastores, manager_channel_variable::entry, and mansession::session.
06645 { 06646 AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry); 06647 06648 return 0; 06649 }
struct ast_datastore* astman_datastore_find | ( | struct mansession * | s, | |
const struct ast_datastore_info * | info, | |||
const char * | uid | |||
) |
Find a datastore on a session.
pointer | to the datastore if found | |
NULL | if not found |
Definition at line 6656 of file manager.c.
References AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, mansession_session::datastores, ast_datastore::entry, ast_datastore::info, mansession::session, and ast_datastore::uid.
06657 { 06658 struct ast_datastore *datastore = NULL; 06659 06660 if (info == NULL) 06661 return NULL; 06662 06663 AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) { 06664 if (datastore->info != info) { 06665 continue; 06666 } 06667 06668 if (uid == NULL) { 06669 /* matched by type only */ 06670 break; 06671 } 06672 06673 if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) { 06674 /* Matched by type AND uid */ 06675 break; 06676 } 06677 } 06678 AST_LIST_TRAVERSE_SAFE_END; 06679 06680 return datastore; 06681 }
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 6651 of file manager.c.
References AST_LIST_REMOVE, mansession_session::datastores, manager_channel_variable::entry, and mansession::session.
06652 { 06653 return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1; 06654 }
int astman_is_authed | ( | uint32_t | ident | ) |
Determinie if a manager session ident is authenticated.
Definition at line 5134 of file manager.c.
References ao2_unlock, mansession_session::authenticated, find_session(), and unref_mansession().
Referenced by http_post_callback(), and static_callback().
05135 { 05136 int authed; 05137 struct mansession_session *session; 05138 05139 if (!(session = find_session(ident, 0))) 05140 return 0; 05141 05142 authed = (session->authenticated != 0); 05143 05144 ao2_unlock(session); 05145 unref_mansession(session); 05146 05147 return authed; 05148 }
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 5150 of file manager.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().
05151 { 05152 int result = 0; 05153 struct mansession_session *session; 05154 struct ao2_iterator i; 05155 05156 if (ident == 0) { 05157 return 0; 05158 } 05159 05160 i = ao2_iterator_init(sessions, 0); 05161 while ((session = ao2_iterator_next(&i))) { 05162 ao2_lock(session); 05163 if ((session->managerid == ident) && (session->readperm & perm)) { 05164 result = 1; 05165 ao2_unlock(session); 05166 unref_mansession(session); 05167 break; 05168 } 05169 ao2_unlock(session); 05170 unref_mansession(session); 05171 } 05172 ao2_iterator_destroy(&i); 05173 return result; 05174 }
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 5176 of file manager.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().
05177 { 05178 int result = 0; 05179 struct mansession_session *session; 05180 struct ao2_iterator i; 05181 05182 if (ident == 0) { 05183 return 0; 05184 } 05185 05186 i = ao2_iterator_init(sessions, 0); 05187 while ((session = ao2_iterator_next(&i))) { 05188 ao2_lock(session); 05189 if ((session->managerid == ident) && (session->writeperm & perm)) { 05190 result = 1; 05191 ao2_unlock(session); 05192 unref_mansession(session); 05193 break; 05194 } 05195 ao2_unlock(session); 05196 unref_mansession(session); 05197 } 05198 ao2_iterator_destroy(&i); 05199 return result; 05200 }
static int auth_http_callback | ( | struct ast_tcptls_session_instance * | ser, | |
enum ast_http_method | method, | |||
enum output_format | format, | |||
struct sockaddr_in * | remote_address, | |||
const char * | uri, | |||
struct ast_variable * | get_params, | |||
struct ast_variable * | headers | |||
) | [static] |
Definition at line 5656 of file manager.c.
References ast_http_error(), AST_HTTP_GET, AST_HTTP_HEAD, AST_HTTP_POST, get_params(), ast_variable::name, and ast_variable::next.
Referenced by auth_manager_http_callback(), auth_mxml_http_callback(), and auth_rawman_http_callback().
05662 { 05663 struct mansession_session *session = NULL; 05664 struct mansession s = { NULL, }; 05665 struct ast_variable *v, *params = get_params; 05666 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */ 05667 struct ast_str *http_header = NULL, *out = NULL; 05668 size_t result_size = 512; 05669 struct message m = { 0 }; 05670 unsigned int x; 05671 size_t hdrlen; 05672 05673 time_t time_now = time(NULL); 05674 unsigned long nonce = 0, nc; 05675 struct ast_http_digest d = { NULL, }; 05676 struct ast_manager_user *user = NULL; 05677 int stale = 0; 05678 char resp_hash[256]=""; 05679 /* Cache for user data */ 05680 char u_username[80]; 05681 int u_readperm; 05682 int u_writeperm; 05683 int u_writetimeout; 05684 int u_displayconnects; 05685 struct ast_sockaddr addr; 05686 05687 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) { 05688 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 05689 return -1; 05690 } 05691 05692 /* Find "Authorization: " header */ 05693 for (v = headers; v; v = v->next) { 05694 if (!strcasecmp(v->name, "Authorization")) { 05695 break; 05696 } 05697 } 05698 05699 if (!v || ast_strlen_zero(v->value)) { 05700 goto out_401; /* Authorization Header not present - send auth request */ 05701 } 05702 05703 /* Digest found - parse */ 05704 if (ast_string_field_init(&d, 128)) { 05705 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 05706 return -1; 05707 } 05708 05709 if (ast_parse_digest(v->value, &d, 0, 1)) { 05710 /* Error in Digest - send new one */ 05711 nonce = 0; 05712 goto out_401; 05713 } 05714 if (sscanf(d.nonce, "%30lx", &nonce) != 1) { 05715 ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce); 05716 nonce = 0; 05717 goto out_401; 05718 } 05719 05720 AST_RWLIST_WRLOCK(&users); 05721 user = get_manager_by_name_locked(d.username); 05722 if(!user) { 05723 AST_RWLIST_UNLOCK(&users); 05724 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username); 05725 nonce = 0; 05726 goto out_401; 05727 } 05728 05729 ast_sockaddr_from_sin(&addr, remote_address); 05730 /* --- We have User for this auth, now check ACL */ 05731 if (user->ha && !ast_apply_ha(user->ha, &addr)) { 05732 AST_RWLIST_UNLOCK(&users); 05733 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username); 05734 ast_http_error(ser, 403, "Permission denied", "Permission denied\n"); 05735 return -1; 05736 } 05737 05738 /* --- We have auth, so check it */ 05739 05740 /* compute the expected response to compare with what we received */ 05741 { 05742 char a2[256]; 05743 char a2_hash[256]; 05744 char resp[256]; 05745 05746 /* XXX Now request method are hardcoded in A2 */ 05747 snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri); 05748 ast_md5_hash(a2_hash, a2); 05749 05750 if (d.qop) { 05751 /* RFC 2617 */ 05752 snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash); 05753 } else { 05754 /* RFC 2069 */ 05755 snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash); 05756 } 05757 ast_md5_hash(resp_hash, resp); 05758 } 05759 05760 if (!d.nonce || strncasecmp(d.response, resp_hash, strlen(resp_hash))) { 05761 /* Something was wrong, so give the client to try with a new challenge */ 05762 AST_RWLIST_UNLOCK(&users); 05763 nonce = 0; 05764 goto out_401; 05765 } 05766 05767 /* 05768 * User are pass Digest authentication. 05769 * Now, cache the user data and unlock user list. 05770 */ 05771 ast_copy_string(u_username, user->username, sizeof(u_username)); 05772 u_readperm = user->readperm; 05773 u_writeperm = user->writeperm; 05774 u_displayconnects = user->displayconnects; 05775 u_writetimeout = user->writetimeout; 05776 AST_RWLIST_UNLOCK(&users); 05777 05778 if (!(session = find_session_by_nonce(d.username, nonce, &stale))) { 05779 /* 05780 * Create new session. 05781 * While it is not in the list we don't need any locking 05782 */ 05783 if (!(session = build_mansession(*remote_address))) { 05784 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 05785 return -1; 05786 } 05787 ao2_lock(session); 05788 05789 ast_copy_string(session->username, u_username, sizeof(session->username)); 05790 session->managerid = nonce; 05791 session->last_ev = grab_last(); 05792 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores); 05793 05794 session->readperm = u_readperm; 05795 session->writeperm = u_writeperm; 05796 session->writetimeout = u_writetimeout; 05797 05798 if (u_displayconnects) { 05799 ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 05800 } 05801 session->noncetime = session->sessionstart = time_now; 05802 session->authenticated = 1; 05803 } else if (stale) { 05804 /* 05805 * Session found, but nonce is stale. 05806 * 05807 * This could be because an old request (w/old nonce) arrived. 05808 * 05809 * This may be as the result of http proxy usage (separate delay or 05810 * multipath) or in a situation where a page was refreshed too quickly 05811 * (seen in Firefox). 05812 * 05813 * In this situation, we repeat the 401 auth with the current nonce 05814 * value. 05815 */ 05816 nonce = session->managerid; 05817 ao2_unlock(session); 05818 stale = 1; 05819 goto out_401; 05820 } else { 05821 sscanf(d.nc, "%30lx", &nc); 05822 if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) { 05823 /* 05824 * Nonce time expired (> 2 minutes) or something wrong with nonce 05825 * counter. 05826 * 05827 * Create new nonce key and resend Digest auth request. Old nonce 05828 * is saved for stale checking... 05829 */ 05830 session->nc = 0; /* Reset nonce counter */ 05831 session->oldnonce = session->managerid; 05832 nonce = session->managerid = ast_random(); 05833 session->noncetime = time_now; 05834 ao2_unlock(session); 05835 stale = 1; 05836 goto out_401; 05837 } else { 05838 session->nc = nc; /* All OK, save nonce counter */ 05839 } 05840 } 05841 05842 05843 /* Reset session timeout. */ 05844 session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5); 05845 ao2_unlock(session); 05846 05847 ast_mutex_init(&s.lock); 05848 s.session = session; 05849 s.fd = mkstemp(template); /* create a temporary file for command output */ 05850 unlink(template); 05851 if (s.fd <= -1) { 05852 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n"); 05853 goto auth_callback_out; 05854 } 05855 s.f = fdopen(s.fd, "w+"); 05856 if (!s.f) { 05857 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno)); 05858 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n"); 05859 close(s.fd); 05860 goto auth_callback_out; 05861 } 05862 05863 if (method == AST_HTTP_POST) { 05864 params = ast_http_get_post_vars(ser, headers); 05865 } 05866 05867 for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) { 05868 hdrlen = strlen(v->name) + strlen(v->value) + 3; 05869 m.headers[m.hdrcount] = alloca(hdrlen); 05870 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value); 05871 ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]); 05872 m.hdrcount = x + 1; 05873 } 05874 05875 if (process_message(&s, &m)) { 05876 if (u_displayconnects) { 05877 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 05878 } 05879 05880 session->needdestroy = 1; 05881 } 05882 05883 if (s.f) { 05884 result_size = ftell(s.f); /* Calculate approx. size of result */ 05885 } 05886 05887 http_header = ast_str_create(80); 05888 out = ast_str_create(result_size * 2 + 512); 05889 05890 if (http_header == NULL || out == NULL) { 05891 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n"); 05892 goto auth_callback_out; 05893 } 05894 05895 ast_str_append(&http_header, 0, "Content-type: text/%s", contenttype[format]); 05896 05897 if (format == FORMAT_XML) { 05898 ast_str_append(&out, 0, "<ajax-response>\n"); 05899 } else if (format == FORMAT_HTML) { 05900 ast_str_append(&out, 0, 05901 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 05902 "<html><head>\r\n" 05903 "<title>Asterisk™ Manager Interface</title>\r\n" 05904 "</head><body style=\"background-color: #ffffff;\">\r\n" 05905 "<form method=\"POST\">\r\n" 05906 "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n" 05907 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n" 05908 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>" 05909 "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n"); 05910 } 05911 05912 if (s.f != NULL) { /* have temporary output */ 05913 char *buf; 05914 size_t l = ftell(s.f); 05915 05916 if (l) { 05917 if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s.fd, 0))) { 05918 if (format == FORMAT_XML || format == FORMAT_HTML) { 05919 xml_translate(&out, buf, params, format); 05920 } else { 05921 ast_str_append(&out, 0, "%s", buf); 05922 } 05923 munmap(buf, l); 05924 } 05925 } else if (format == FORMAT_XML || format == FORMAT_HTML) { 05926 xml_translate(&out, "", params, format); 05927 } 05928 fclose(s.f); 05929 s.f = NULL; 05930 s.fd = -1; 05931 } 05932 05933 if (format == FORMAT_XML) { 05934 ast_str_append(&out, 0, "</ajax-response>\n"); 05935 } else if (format == FORMAT_HTML) { 05936 ast_str_append(&out, 0, "</table></form></body></html>\r\n"); 05937 } 05938 05939 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0); 05940 http_header = out = NULL; 05941 05942 auth_callback_out: 05943 ast_mutex_destroy(&s.lock); 05944 05945 /* Clear resources and unlock manager session */ 05946 if (method == AST_HTTP_POST && params) { 05947 ast_variables_destroy(params); 05948 } 05949 05950 ast_free(http_header); 05951 ast_free(out); 05952 05953 ao2_lock(session); 05954 if (session->f) { 05955 fclose(session->f); 05956 } 05957 session->f = NULL; 05958 session->fd = -1; 05959 ao2_unlock(session); 05960 05961 if (session->needdestroy) { 05962 ast_debug(1, "Need destroy, doing it now!\n"); 05963 session_destroy(session); 05964 } 05965 ast_string_field_free_memory(&d); 05966 return 0; 05967 05968 out_401: 05969 if (!nonce) { 05970 nonce = ast_random(); 05971 } 05972 05973 ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL); 05974 ast_string_field_free_memory(&d); 05975 return 0; 05976 }
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 6037 of file manager.c.
References ast_sockaddr_from_sin, ast_sockaddr_to_sin, auth_http_callback(), FORMAT_HTML, get_params(), and ast_tcptls_session_instance::remote_address.
06038 { 06039 int retval; 06040 struct sockaddr_in ser_remote_address_tmp; 06041 06042 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06043 retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers); 06044 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06045 return retval; 06046 }
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 6048 of file manager.c.
References ast_sockaddr_from_sin, ast_sockaddr_to_sin, auth_http_callback(), FORMAT_XML, get_params(), and ast_tcptls_session_instance::remote_address.
06049 { 06050 int retval; 06051 struct sockaddr_in ser_remote_address_tmp; 06052 06053 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06054 retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers); 06055 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06056 return retval; 06057 }
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 6059 of file manager.c.
References ast_sockaddr_from_sin, ast_sockaddr_to_sin, auth_http_callback(), FORMAT_RAW, get_params(), and ast_tcptls_session_instance::remote_address.
06060 { 06061 int retval; 06062 struct sockaddr_in ser_remote_address_tmp; 06063 06064 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06065 retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers); 06066 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06067 return retval; 06068 }
static struct mansession_session* find_session | ( | uint32_t | ident, | |
int | incinuse | |||
) | [static] |
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 5075 of file manager.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, ast_atomic_fetchadd_int(), and unref_mansession().
Referenced by astman_is_authed().
05076 { 05077 struct mansession_session *session; 05078 struct ao2_iterator i; 05079 05080 if (ident == 0) { 05081 return NULL; 05082 } 05083 05084 i = ao2_iterator_init(sessions, 0); 05085 while ((session = ao2_iterator_next(&i))) { 05086 ao2_lock(session); 05087 if (session->managerid == ident && !session->needdestroy) { 05088 ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0); 05089 break; 05090 } 05091 ao2_unlock(session); 05092 unref_mansession(session); 05093 } 05094 ao2_iterator_destroy(&i); 05095 05096 return session; 05097 }
static struct mansession_session* find_session_by_nonce | ( | const char * | username, | |
unsigned long | nonce, | |||
int * | stale | |||
) | [static] |
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 5108 of file manager.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().
05109 { 05110 struct mansession_session *session; 05111 struct ao2_iterator i; 05112 05113 if (nonce == 0 || username == NULL || stale == NULL) { 05114 return NULL; 05115 } 05116 05117 i = ao2_iterator_init(sessions, 0); 05118 while ((session = ao2_iterator_next(&i))) { 05119 ao2_lock(session); 05120 if (!strcasecmp(session->username, username) && session->managerid == nonce) { 05121 *stale = 0; 05122 break; 05123 } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) { 05124 *stale = 1; 05125 break; 05126 } 05127 ao2_unlock(session); 05128 unref_mansession(session); 05129 } 05130 ao2_iterator_destroy(&i); 05131 return session; 05132 }
static int generic_http_callback | ( | struct ast_tcptls_session_instance * | ser, | |
enum ast_http_method | method, | |||
enum output_format | format, | |||
struct sockaddr_in * | remote_address, | |||
const char * | uri, | |||
struct ast_variable * | get_params, | |||
struct ast_variable * | headers | |||
) | [static] |
Definition at line 5429 of file manager.c.
References ast_http_error(), AST_HTTP_GET, ast_http_get_cookies(), AST_HTTP_HEAD, AST_HTTP_POST, get_params(), ast_variable::name, ast_variable::next, mansession::session, and ast_variable::value.
Referenced by manager_http_callback(), mxml_http_callback(), and rawman_http_callback().
05435 { 05436 struct mansession s = { .session = NULL, .tcptls_session = ser }; 05437 struct mansession_session *session = NULL; 05438 uint32_t ident = 0; 05439 int blastaway = 0; 05440 struct ast_variable *v, *cookies, *params = get_params; 05441 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */ 05442 struct ast_str *http_header = NULL, *out = NULL; 05443 struct message m = { 0 }; 05444 unsigned int x; 05445 size_t hdrlen; 05446 05447 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) { 05448 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 05449 return -1; 05450 } 05451 05452 cookies = ast_http_get_cookies(headers); 05453 for (v = cookies; v; v = v->next) { 05454 if (!strcasecmp(v->name, "mansession_id")) { 05455 sscanf(v->value, "%30x", &ident); 05456 break; 05457 } 05458 } 05459 if (cookies) { 05460 ast_variables_destroy(cookies); 05461 } 05462 05463 if (!(session = find_session(ident, 1))) { 05464 05465 /**/ 05466 /* Create new session. 05467 * While it is not in the list we don't need any locking 05468 */ 05469 if (!(session = build_mansession(*remote_address))) { 05470 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 05471 return -1; 05472 } 05473 ao2_lock(session); 05474 session->sin = *remote_address; 05475 session->fd = -1; 05476 session->waiting_thread = AST_PTHREADT_NULL; 05477 session->send_events = 0; 05478 session->inuse = 1; 05479 /*!\note There is approximately a 1 in 1.8E19 chance that the following 05480 * calculation will produce 0, which is an invalid ID, but due to the 05481 * properties of the rand() function (and the constantcy of s), that 05482 * won't happen twice in a row. 05483 */ 05484 while ((session->managerid = ast_random() ^ (unsigned long) session) == 0); 05485 session->last_ev = grab_last(); 05486 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores); 05487 } 05488 ao2_unlock(session); 05489 05490 http_header = ast_str_create(128); 05491 out = ast_str_create(2048); 05492 05493 ast_mutex_init(&s.lock); 05494 05495 if (http_header == NULL || out == NULL) { 05496 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n"); 05497 goto generic_callback_out; 05498 } 05499 05500 s.session = session; 05501 s.fd = mkstemp(template); /* create a temporary file for command output */ 05502 unlink(template); 05503 if (s.fd <= -1) { 05504 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n"); 05505 goto generic_callback_out; 05506 } 05507 s.f = fdopen(s.fd, "w+"); 05508 if (!s.f) { 05509 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno)); 05510 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n"); 05511 close(s.fd); 05512 goto generic_callback_out; 05513 } 05514 05515 if (method == AST_HTTP_POST) { 05516 params = ast_http_get_post_vars(ser, headers); 05517 } 05518 05519 for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) { 05520 hdrlen = strlen(v->name) + strlen(v->value) + 3; 05521 m.headers[m.hdrcount] = alloca(hdrlen); 05522 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value); 05523 ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]); 05524 m.hdrcount = x + 1; 05525 } 05526 05527 if (process_message(&s, &m)) { 05528 if (session->authenticated) { 05529 if (manager_displayconnects(session)) { 05530 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 05531 } 05532 } else { 05533 if (displayconnects) { 05534 ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr)); 05535 } 05536 } 05537 session->needdestroy = 1; 05538 } 05539 05540 ast_str_append(&http_header, 0, 05541 "Content-type: text/%s\r\n" 05542 "Cache-Control: no-cache;\r\n" 05543 "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n" 05544 "Pragma: SuppressEvents\r\n", 05545 contenttype[format], 05546 session->managerid, httptimeout); 05547 05548 if (format == FORMAT_XML) { 05549 ast_str_append(&out, 0, "<ajax-response>\n"); 05550 } else if (format == FORMAT_HTML) { 05551 /* 05552 * When handling AMI-over-HTTP in HTML format, we provide a simple form for 05553 * debugging purposes. This HTML code should not be here, we 05554 * should read from some config file... 05555 */ 05556 05557 #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n" 05558 #define TEST_STRING \ 05559 "<form action=\"manager\" method=\"post\">\n\ 05560 Action: <select name=\"action\">\n\ 05561 <option value=\"\">-----></option>\n\ 05562 <option value=\"login\">login</option>\n\ 05563 <option value=\"command\">Command</option>\n\ 05564 <option value=\"waitevent\">waitevent</option>\n\ 05565 <option value=\"listcommands\">listcommands</option>\n\ 05566 </select>\n\ 05567 or <input name=\"action\"><br/>\n\ 05568 CLI Command <input name=\"command\"><br>\n\ 05569 user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\ 05570 <input type=\"submit\">\n</form>\n" 05571 05572 ast_str_append(&out, 0, "<title>Asterisk™ Manager Interface</title>"); 05573 ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n"); 05574 ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>"); 05575 ast_str_append(&out, 0, ROW_FMT, TEST_STRING); 05576 } 05577 05578 if (s.f != NULL) { /* have temporary output */ 05579 char *buf; 05580 size_t l; 05581 05582 if ((l = ftell(s.f))) { 05583 if (MAP_FAILED == (buf = mmap(NULL, l + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, s.fd, 0))) { 05584 ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n"); 05585 } else { 05586 buf[l] = '\0'; 05587 if (format == FORMAT_XML || format == FORMAT_HTML) { 05588 xml_translate(&out, buf, params, format); 05589 } else { 05590 ast_str_append(&out, 0, "%s", buf); 05591 } 05592 munmap(buf, l + 1); 05593 } 05594 } else if (format == FORMAT_XML || format == FORMAT_HTML) { 05595 xml_translate(&out, "", params, format); 05596 } 05597 fclose(s.f); 05598 s.f = NULL; 05599 s.fd = -1; 05600 } 05601 05602 if (format == FORMAT_XML) { 05603 ast_str_append(&out, 0, "</ajax-response>\n"); 05604 } else if (format == FORMAT_HTML) { 05605 ast_str_append(&out, 0, "</table></body>\r\n"); 05606 } 05607 05608 ao2_lock(session); 05609 /* Reset HTTP timeout. If we're not authenticated, keep it extremely short */ 05610 session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5); 05611 05612 if (session->needdestroy) { 05613 if (session->inuse == 1) { 05614 ast_debug(1, "Need destroy, doing it now!\n"); 05615 blastaway = 1; 05616 } else { 05617 ast_debug(1, "Need destroy, but can't do it yet!\n"); 05618 if (session->waiting_thread != AST_PTHREADT_NULL) { 05619 pthread_kill(session->waiting_thread, SIGURG); 05620 } 05621 session->inuse--; 05622 } 05623 } else { 05624 session->inuse--; 05625 } 05626 ao2_unlock(session); 05627 05628 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0); 05629 http_header = out = NULL; 05630 05631 generic_callback_out: 05632 ast_mutex_destroy(&s.lock); 05633 05634 /* Clear resource */ 05635 05636 if (method == AST_HTTP_POST && params) { 05637 ast_variables_destroy(params); 05638 } 05639 if (http_header) { 05640 ast_free(http_header); 05641 } 05642 if (out) { 05643 ast_free(out); 05644 } 05645 05646 if (session && blastaway) { 05647 session_destroy(session); 05648 } else if (session && session->f) { 05649 fclose(session->f); 05650 session->f = NULL; 05651 } 05652 05653 return 0; 05654 }
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 6132 of file manager.c.
References allowmultiplelogin, ami_desc, ami_tls_cfg, amis_desc, 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, displayconnects, ast_tls_config::enabled, ast_cli_args::fd, FORMAT, FORMAT2, httptimeout, ast_tcptls_session_args::local_address, manager_channelvars, manager_debug, manager_enabled, ast_tls_config::pvtfile, S_OR, timestampevents, ast_cli_entry::usage, and webmanager_enabled.
06133 { 06134 switch (cmd) { 06135 case CLI_INIT: 06136 e->command = "manager show settings"; 06137 e->usage = 06138 "Usage: manager show settings\n" 06139 " Provides detailed list of the configuration of the Manager.\n"; 06140 return NULL; 06141 case CLI_GENERATE: 06142 return NULL; 06143 } 06144 #define FORMAT " %-25.25s %-15.15s\n" 06145 #define FORMAT2 " %-25.25s %-15d\n" 06146 if (a->argc != 3) { 06147 return CLI_SHOWUSAGE; 06148 } 06149 ast_cli(a->fd, "\nGlobal Settings:\n"); 06150 ast_cli(a->fd, "----------------\n"); 06151 ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled)); 06152 ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled)); 06153 ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled"); 06154 ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout); 06155 ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled)); 06156 ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled"); 06157 ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile); 06158 ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile); 06159 ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher); 06160 ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin)); 06161 ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects)); 06162 ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents)); 06163 ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, "")); 06164 ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug)); 06165 ast_cli(a->fd, FORMAT, "Block sockets:", AST_CLI_YESNO(block_sockets)); 06166 #undef FORMAT 06167 #undef FORMAT2 06168 06169 return CLI_SUCCESS; 06170 }
int init_manager | ( | void | ) |
Called by Asterisk initialization.
Definition at line 6634 of file manager.c.
References __init_manager().
Referenced by main().
06635 { 06636 return __init_manager(0); 06637 }
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 5978 of file manager.c.
References ast_sockaddr_from_sin, ast_sockaddr_to_sin, FORMAT_HTML, generic_http_callback(), get_params(), and ast_tcptls_session_instance::remote_address.
05979 { 05980 int retval; 05981 struct sockaddr_in ser_remote_address_tmp; 05982 05983 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 05984 retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers); 05985 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 05986 return retval; 05987 }
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 5989 of file manager.c.
References ast_sockaddr_from_sin, ast_sockaddr_to_sin, FORMAT_XML, generic_http_callback(), get_params(), and ast_tcptls_session_instance::remote_address.
05990 { 05991 int retval; 05992 struct sockaddr_in ser_remote_address_tmp; 05993 05994 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 05995 retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers); 05996 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 05997 return retval; 05998 }
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 6103 of file manager.c.
References purge_events(), and purge_sessions().
06104 { 06105 purge_sessions(1); 06106 purge_events(); 06107 }
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 6000 of file manager.c.
References ast_sockaddr_from_sin, ast_sockaddr_to_sin, FORMAT_RAW, generic_http_callback(), get_params(), and ast_tcptls_session_instance::remote_address.
06001 { 06002 int retval; 06003 struct sockaddr_in ser_remote_address_tmp; 06004 06005 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06006 retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers); 06007 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06008 return retval; 06009 }
int reload_manager | ( | void | ) |
Called by Asterisk module functions and the CLI command.
Definition at line 6639 of file manager.c.
References __init_manager().
Referenced by handle_manager_reload().
06640 { 06641 return __init_manager(1); 06642 }
static int variable_count_cmp_fn | ( | void * | obj, | |
void * | vstr, | |||
int | flags | |||
) | [static] |
Definition at line 5276 of file manager.c.
References CMP_MATCH, CMP_STOP, str, and variable_count::varname.
05277 { 05278 /* Due to the simplicity of struct variable_count, it makes no difference 05279 * if you pass in objects or strings, the same operation applies. This is 05280 * due to the fact that the hash occurs on the first element, which means 05281 * the address of both the struct and the string are exactly the same. */ 05282 struct variable_count *vc = obj; 05283 char *str = vstr; 05284 return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0; 05285 }
static int variable_count_hash_fn | ( | const void * | vvc, | |
const int | flags | |||
) | [static] |
Definition at line 5269 of file manager.c.
References ast_str_hash(), and variable_count::varname.
05270 { 05271 const struct variable_count *vc = vvc; 05272 05273 return ast_str_hash(vc->varname); 05274 }
static void xml_copy_escape | ( | struct ast_str ** | out, | |
const char * | src, | |||
int | mode | |||
) | [static] |
Definition at line 5207 of file manager.c.
References ast_str_append().
05208 { 05209 /* store in a local buffer to avoid calling ast_str_append too often */ 05210 char buf[256]; 05211 char *dst = buf; 05212 int space = sizeof(buf); 05213 /* repeat until done and nothing to flush */ 05214 for ( ; *src || dst != buf ; src++) { 05215 if (*src == '\0' || space < 10) { /* flush */ 05216 *dst++ = '\0'; 05217 ast_str_append(out, 0, "%s", buf); 05218 dst = buf; 05219 space = sizeof(buf); 05220 if (*src == '\0') { 05221 break; 05222 } 05223 } 05224 05225 if ( (mode & 2) && !isalnum(*src)) { 05226 *dst++ = '_'; 05227 space--; 05228 continue; 05229 } 05230 switch (*src) { 05231 case '<': 05232 strcpy(dst, "<"); 05233 dst += 4; 05234 space -= 4; 05235 break; 05236 case '>': 05237 strcpy(dst, ">"); 05238 dst += 4; 05239 space -= 4; 05240 break; 05241 case '\"': 05242 strcpy(dst, """); 05243 dst += 6; 05244 space -= 6; 05245 break; 05246 case '\'': 05247 strcpy(dst, "'"); 05248 dst += 6; 05249 space -= 6; 05250 break; 05251 case '&': 05252 strcpy(dst, "&"); 05253 dst += 5; 05254 space -= 5; 05255 break; 05256 05257 default: 05258 *dst++ = mode ? tolower(*src) : *src; 05259 space--; 05260 } 05261 } 05262 }
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 5315 of file manager.c.
References FORMAT_XML, ast_variable::name, ast_variable::next, ast_variable::value, and var.
05316 { 05317 struct ast_variable *v; 05318 const char *dest = NULL; 05319 char *var, *val; 05320 const char *objtype = NULL; 05321 int in_data = 0; /* parsing data */ 05322 int inobj = 0; 05323 int xml = (format == FORMAT_XML); 05324 struct variable_count *vc = NULL; 05325 struct ao2_container *vco = NULL; 05326 05327 if (xml) { 05328 /* dest and objtype need only for XML format */ 05329 for (v = get_vars; v; v = v->next) { 05330 if (!strcasecmp(v->name, "ajaxdest")) { 05331 dest = v->value; 05332 } else if (!strcasecmp(v->name, "ajaxobjtype")) { 05333 objtype = v->value; 05334 } 05335 } 05336 if (ast_strlen_zero(dest)) { 05337 dest = "unknown"; 05338 } 05339 if (ast_strlen_zero(objtype)) { 05340 objtype = "generic"; 05341 } 05342 } 05343 05344 /* we want to stop when we find an empty line */ 05345 while (in && *in) { 05346 val = strsep(&in, "\r\n"); /* mark start and end of line */ 05347 if (in && *in == '\n') { /* remove trailing \n if any */ 05348 in++; 05349 } 05350 ast_trim_blanks(val); 05351 ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val); 05352 if (ast_strlen_zero(val)) { 05353 /* empty line */ 05354 if (in_data) { 05355 /* close data in Opaque mode */ 05356 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n"); 05357 in_data = 0; 05358 } 05359 05360 if (inobj) { 05361 /* close block */ 05362 ast_str_append(out, 0, xml ? " /></response>\n" : 05363 "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 05364 inobj = 0; 05365 ao2_ref(vco, -1); 05366 vco = NULL; 05367 } 05368 continue; 05369 } 05370 05371 if (!inobj) { 05372 /* start new block */ 05373 if (xml) { 05374 ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype); 05375 } 05376 vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn); 05377 inobj = 1; 05378 } 05379 05380 if (in_data) { 05381 /* Process data field in Opaque mode */ 05382 xml_copy_escape(out, val, 0); /* data field */ 05383 ast_str_append(out, 0, xml ? "\n" : "<br>\n"); 05384 continue; 05385 } 05386 05387 /* We expect "Name: value" line here */ 05388 var = strsep(&val, ":"); 05389 if (val) { 05390 /* found the field name */ 05391 val = ast_skip_blanks(val); 05392 ast_trim_blanks(var); 05393 } else { 05394 /* field name not found, switch to opaque mode */ 05395 val = var; 05396 var = "Opaque-data"; 05397 in_data = 1; 05398 } 05399 05400 05401 ast_str_append(out, 0, xml ? " " : "<tr><td>"); 05402 if ((vc = ao2_find(vco, var, 0))) { 05403 vc->count++; 05404 } else { 05405 /* Create a new entry for this one */ 05406 vc = ao2_alloc(sizeof(*vc), NULL); 05407 vc->varname = var; 05408 vc->count = 1; 05409 ao2_link(vco, vc); 05410 } 05411 05412 xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */ 05413 if (vc->count > 1) { 05414 ast_str_append(out, 0, "-%d", vc->count); 05415 } 05416 ao2_ref(vc, -1); 05417 ast_str_append(out, 0, xml ? "='" : "</td><td>"); 05418 xml_copy_escape(out, val, 0); /* data field */ 05419 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n"); 05420 } 05421 05422 if (inobj) { 05423 ast_str_append(out, 0, xml ? " /></response>\n" : 05424 "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 05425 ao2_ref(vco, -1); 05426 } 05427 }
struct ast_http_uri amanageruri [static] |
struct ast_http_uri amanagerxmluri [static] |
struct ast_tcptls_session_args ami_desc [static] |
Definition at line 6110 of file manager.c.
Referenced by __init_manager(), and handle_manager_show_settings().
struct ast_tls_config ami_tls_cfg [static] |
Definition at line 6109 of file manager.c.
Referenced by __init_manager(), and handle_manager_show_settings().
struct ast_tcptls_session_args amis_desc [static] |
Definition at line 6121 of file manager.c.
Referenced by __init_manager(), and handle_manager_show_settings().
struct ast_http_uri arawmanuri [static] |
struct ast_cli_entry cli_manager[] [static] |
const char* const contenttype[] [static] |
Initial value:
{ [FORMAT_RAW] = "plain", [FORMAT_HTML] = "html", [FORMAT_XML] = "xml", }
struct ast_http_uri manageruri [static] |
struct ast_http_uri managerxmluri [static] |
struct ast_http_uri rawmanuri [static] |
int registered = 0 [static] |
const char* words[AST_MAX_CMD_LEN] |