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