#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"
#include "asterisk/stringfields.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) |
Return a matching header value. | |
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 void | action_destroy (void *obj) |
static int | action_events (struct mansession *s, const struct message *m) |
static int | action_extensionstate (struct mansession *s, const struct message *m) |
static struct manager_action * | action_find (const char *name) |
static int | action_getconfig (struct mansession *s, const struct message *m) |
static int | action_getconfigjson (struct mansession *s, const struct message *m) |
static int | action_getvar (struct mansession *s, const struct message *m) |
static int | action_hangup (struct mansession *s, const struct message *m) |
static int | action_listcategories (struct mansession *s, const struct message *m) |
static int | action_listcommands (struct mansession *s, const struct message *m) |
static int | action_login (struct mansession *s, const struct message *m) |
static int | action_logoff (struct mansession *s, const struct message *m) |
static int | action_mailboxcount (struct mansession *s, const struct message *m) |
static int | action_mailboxstatus (struct mansession *s, const struct message *m) |
static int | action_originate (struct mansession *s, const struct message *m) |
static int | action_ping (struct mansession *s, const struct message *m) |
static int | action_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,...) |
static void | astman_append_json (struct mansession *s, const char *str) |
int | astman_datastore_add (struct mansession *s, struct ast_datastore *datastore) |
Add a datastore to a session. | |
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 (void) |
Check if AMI is enabled. | |
static int | check_manager_session_inuse (const char *name) |
int | check_webmanager_enabled (void) |
Check if AMI/HTTP is enabled. | |
static 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 void | load_channelvars (struct ast_variable *var) |
static struct ast_variable * | man_do_variable_value (struct ast_variable *head, const char *hdr_val) |
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 | process_output (struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format) |
static void | purge_events (void) |
static void | purge_old_stuff (void *data) |
cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most | |
static void | purge_sessions (int n_max) |
remove at most n_max stale session from the list. | |
static int | rawman_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) |
int | reload_manager (void) |
Called by Asterisk module functions and the CLI command. | |
static void | report_auth_success (const struct mansession *s) |
static void | report_failed_acl (const struct mansession *s, const char *username) |
static void | report_failed_challenge_response (const struct mansession *s, const char *response, const char *expected_response) |
static void | report_inval_password (const struct mansession *s, const char *username) |
static void | report_invalid_user (const struct mansession *s, const char *username) |
static void | report_req_bad_format (const struct mansession *s, const char *action) |
static void | report_req_not_allowed (const struct mansession *s, const char *action) |
static void | report_session_limit (const struct mansession *s) |
static int | send_string (struct mansession *s, char *string) |
static void | session_destroy (struct mansession_session *s) |
static void | session_destructor (void *obj) |
static void * | session_do (void *data) |
The body of the individual manager session. Call get_input() to read one line at a time (or be woken up on new events), collect the lines in a message until found an empty line, and execute the request. In any case, deliver events asynchronously through process_events() (called from here if no line is available, or at the end of process_message(). ). | |
static int | set_eventmask (struct mansession *s, const char *eventmask) |
Rather than braindead on,off this now can also accept a specific int mask value or a ',' delim list of mask strings (the same as manager.conf) -anthm. | |
static int | strings_to_mask (const char *string) |
static struct mansession_session * | unref_mansession (struct mansession_session *s) |
Unreference manager session object. If no more references, then go ahead and delete it. | |
static 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_MANAGERDEBUG = 0 |
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 = 0 |
static int | manager_enabled = 0 |
static struct ast_threadstorage | manager_event_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_manager_event_buf , .custom_init = NULL , } |
static struct ast_threadstorage | manager_event_funcbuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_manager_event_funcbuf , .custom_init = NULL , } |
static struct 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 5286 of file manager.c.
05286 { 05287 FORMAT_RAW, 05288 FORMAT_HTML, 05289 FORMAT_XML, 05290 };
static int __init_manager | ( | int | reload | ) | [static] |
Definition at line 6464 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_MANAGERDEBUG, 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_debug, 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().
06465 { 06466 struct ast_config *ucfg = NULL, *cfg = NULL; 06467 const char *val; 06468 char *cat = NULL; 06469 int newhttptimeout = DEFAULT_HTTPTIMEOUT; 06470 struct ast_manager_user *user = NULL; 06471 struct ast_variable *var; 06472 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06473 char a1[256]; 06474 char a1_hash[256]; 06475 struct sockaddr_in ami_desc_local_address_tmp = { 0, }; 06476 struct sockaddr_in amis_desc_local_address_tmp = { 0, }; 06477 06478 if (!registered) { 06479 /* Register default actions */ 06480 ast_manager_register_xml("Ping", 0, action_ping); 06481 ast_manager_register_xml("Events", 0, action_events); 06482 ast_manager_register_xml("Logoff", 0, action_logoff); 06483 ast_manager_register_xml("Login", 0, action_login); 06484 ast_manager_register_xml("Challenge", 0, action_challenge); 06485 ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup); 06486 ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status); 06487 ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar); 06488 ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar); 06489 ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig); 06490 ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson); 06491 ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig); 06492 ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig); 06493 ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories); 06494 ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect); 06495 ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer); 06496 ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate); 06497 ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command); 06498 ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate); 06499 ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout); 06500 ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus); 06501 ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount); 06502 ast_manager_register_xml("ListCommands", 0, action_listcommands); 06503 ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext); 06504 ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent); 06505 ast_manager_register_xml("WaitEvent", 0, action_waitevent); 06506 ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings); 06507 ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus); 06508 ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload); 06509 ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels); 06510 ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload); 06511 ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck); 06512 ast_manager_register_xml("AOCMessage", EVENT_FLAG_AOC, action_aocmessage); 06513 06514 ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager)); 06515 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL); 06516 registered = 1; 06517 /* Append placeholder event so master_eventq never runs dry */ 06518 append_event("Event: Placeholder\r\n\r\n", 0); 06519 } 06520 if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) { 06521 return 0; 06522 } 06523 06524 manager_enabled = DEFAULT_ENABLED; 06525 webmanager_enabled = DEFAULT_WEBENABLED; 06526 manager_debug = DEFAULT_MANAGERDEBUG; 06527 displayconnects = DEFAULT_DISPLAYCONNECTS; 06528 broken_events_action = DEFAULT_BROKENEVENTSACTION; 06529 block_sockets = DEFAULT_BLOCKSOCKETS; 06530 timestampevents = DEFAULT_TIMESTAMPEVENTS; 06531 httptimeout = DEFAULT_HTTPTIMEOUT; 06532 authtimeout = DEFAULT_AUTHTIMEOUT; 06533 authlimit = DEFAULT_AUTHLIMIT; 06534 06535 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { 06536 ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled.\n"); 06537 return 0; 06538 } 06539 06540 /* default values */ 06541 ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm)); 06542 memset(&ami_desc.local_address, 0, sizeof(struct sockaddr_in)); 06543 memset(&amis_desc.local_address, 0, sizeof(amis_desc.local_address)); 06544 amis_desc_local_address_tmp.sin_port = htons(5039); 06545 ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT); 06546 06547 ami_tls_cfg.enabled = 0; 06548 if (ami_tls_cfg.certfile) { 06549 ast_free(ami_tls_cfg.certfile); 06550 } 06551 ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE); 06552 if (ami_tls_cfg.pvtfile) { 06553 ast_free(ami_tls_cfg.pvtfile); 06554 } 06555 ami_tls_cfg.pvtfile = ast_strdup(""); 06556 if (ami_tls_cfg.cipher) { 06557 ast_free(ami_tls_cfg.cipher); 06558 } 06559 ami_tls_cfg.cipher = ast_strdup(""); 06560 06561 free_channelvars(); 06562 06563 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 06564 val = var->value; 06565 06566 if (!ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) { 06567 continue; 06568 } 06569 06570 if (!strcasecmp(var->name, "enabled")) { 06571 manager_enabled = ast_true(val); 06572 } else if (!strcasecmp(var->name, "block-sockets")) { 06573 block_sockets = ast_true(val); 06574 } else if (!strcasecmp(var->name, "webenabled")) { 06575 webmanager_enabled = ast_true(val); 06576 } else if (!strcasecmp(var->name, "port")) { 06577 ami_desc_local_address_tmp.sin_port = htons(atoi(val)); 06578 } else if (!strcasecmp(var->name, "bindaddr")) { 06579 if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) { 06580 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val); 06581 memset(&ami_desc_local_address_tmp.sin_addr, 0, 06582 sizeof(ami_desc_local_address_tmp.sin_addr)); 06583 } 06584 } else if (!strcasecmp(var->name, "brokeneventsaction")) { 06585 broken_events_action = ast_true(val); 06586 } else if (!strcasecmp(var->name, "allowmultiplelogin")) { 06587 allowmultiplelogin = ast_true(val); 06588 } else if (!strcasecmp(var->name, "displayconnects")) { 06589 displayconnects = ast_true(val); 06590 } else if (!strcasecmp(var->name, "timestampevents")) { 06591 timestampevents = ast_true(val); 06592 } else if (!strcasecmp(var->name, "debug")) { 06593 manager_debug = ast_true(val); 06594 } else if (!strcasecmp(var->name, "httptimeout")) { 06595 newhttptimeout = atoi(val); 06596 } else if (!strcasecmp(var->name, "authtimeout")) { 06597 int timeout = atoi(var->value); 06598 06599 if (timeout < 1) { 06600 ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value); 06601 } else { 06602 authtimeout = timeout; 06603 } 06604 } else if (!strcasecmp(var->name, "authlimit")) { 06605 int limit = atoi(var->value); 06606 06607 if (limit < 1) { 06608 ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value); 06609 } else { 06610 authlimit = limit; 06611 } 06612 } else if (!strcasecmp(var->name, "channelvars")) { 06613 load_channelvars(var); 06614 } else { 06615 ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n", 06616 var->name, val); 06617 } 06618 } 06619 06620 ami_desc_local_address_tmp.sin_family = AF_INET; 06621 amis_desc_local_address_tmp.sin_family = AF_INET; 06622 06623 /* if the amis address has not been set, default is the same as non secure ami */ 06624 if (!amis_desc_local_address_tmp.sin_addr.s_addr) { 06625 amis_desc_local_address_tmp.sin_addr = 06626 ami_desc_local_address_tmp.sin_addr; 06627 } 06628 06629 if (manager_enabled) { 06630 ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp); 06631 ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp); 06632 } 06633 06634 AST_RWLIST_WRLOCK(&users); 06635 06636 /* First, get users from users.conf */ 06637 ucfg = ast_config_load2("users.conf", "manager", config_flags); 06638 if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) { 06639 const char *hasmanager; 06640 int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager")); 06641 06642 while ((cat = ast_category_browse(ucfg, cat))) { 06643 if (!strcasecmp(cat, "general")) { 06644 continue; 06645 } 06646 06647 hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager"); 06648 if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) { 06649 const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret"); 06650 const char *user_read = ast_variable_retrieve(ucfg, cat, "read"); 06651 const char *user_write = ast_variable_retrieve(ucfg, cat, "write"); 06652 const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects"); 06653 const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout"); 06654 06655 /* Look for an existing entry, 06656 * if none found - create one and add it to the list 06657 */ 06658 if (!(user = get_manager_by_name_locked(cat))) { 06659 if (!(user = ast_calloc(1, sizeof(*user)))) { 06660 break; 06661 } 06662 06663 /* Copy name over */ 06664 ast_copy_string(user->username, cat, sizeof(user->username)); 06665 /* Insert into list */ 06666 AST_LIST_INSERT_TAIL(&users, user, list); 06667 user->ha = NULL; 06668 user->keep = 1; 06669 user->readperm = -1; 06670 user->writeperm = -1; 06671 /* Default displayconnect from [general] */ 06672 user->displayconnects = displayconnects; 06673 user->writetimeout = 100; 06674 } 06675 06676 if (!user_secret) { 06677 user_secret = ast_variable_retrieve(ucfg, "general", "secret"); 06678 } 06679 if (!user_read) { 06680 user_read = ast_variable_retrieve(ucfg, "general", "read"); 06681 } 06682 if (!user_write) { 06683 user_write = ast_variable_retrieve(ucfg, "general", "write"); 06684 } 06685 if (!user_displayconnects) { 06686 user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects"); 06687 } 06688 if (!user_writetimeout) { 06689 user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout"); 06690 } 06691 06692 if (!ast_strlen_zero(user_secret)) { 06693 if (user->secret) { 06694 ast_free(user->secret); 06695 } 06696 user->secret = ast_strdup(user_secret); 06697 } 06698 06699 if (user_read) { 06700 user->readperm = get_perm(user_read); 06701 } 06702 if (user_write) { 06703 user->writeperm = get_perm(user_write); 06704 } 06705 if (user_displayconnects) { 06706 user->displayconnects = ast_true(user_displayconnects); 06707 } 06708 if (user_writetimeout) { 06709 int value = atoi(user_writetimeout); 06710 if (value < 100) { 06711 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at users.conf line %d\n", var->value, var->lineno); 06712 } else { 06713 user->writetimeout = value; 06714 } 06715 } 06716 } 06717 } 06718 ast_config_destroy(ucfg); 06719 } 06720 06721 /* cat is NULL here in any case */ 06722 06723 while ((cat = ast_category_browse(cfg, cat))) { 06724 struct ast_ha *oldha; 06725 06726 if (!strcasecmp(cat, "general")) { 06727 continue; 06728 } 06729 06730 /* Look for an existing entry, if none found - create one and add it to the list */ 06731 if (!(user = get_manager_by_name_locked(cat))) { 06732 if (!(user = ast_calloc(1, sizeof(*user)))) { 06733 break; 06734 } 06735 /* Copy name over */ 06736 ast_copy_string(user->username, cat, sizeof(user->username)); 06737 06738 user->ha = NULL; 06739 user->readperm = 0; 06740 user->writeperm = 0; 06741 /* Default displayconnect from [general] */ 06742 user->displayconnects = displayconnects; 06743 user->writetimeout = 100; 06744 user->whitefilters = ao2_container_alloc(1, NULL, NULL); 06745 user->blackfilters = ao2_container_alloc(1, NULL, NULL); 06746 06747 /* Insert into list */ 06748 AST_RWLIST_INSERT_TAIL(&users, user, list); 06749 } else { 06750 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters"); 06751 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters"); 06752 } 06753 06754 /* Make sure we keep this user and don't destroy it during cleanup */ 06755 user->keep = 1; 06756 oldha = user->ha; 06757 user->ha = NULL; 06758 06759 var = ast_variable_browse(cfg, cat); 06760 for (; var; var = var->next) { 06761 if (!strcasecmp(var->name, "secret")) { 06762 if (user->secret) { 06763 ast_free(user->secret); 06764 } 06765 user->secret = ast_strdup(var->value); 06766 } else if (!strcasecmp(var->name, "deny") || 06767 !strcasecmp(var->name, "permit")) { 06768 user->ha = ast_append_ha(var->name, var->value, user->ha, NULL); 06769 } else if (!strcasecmp(var->name, "read") ) { 06770 user->readperm = get_perm(var->value); 06771 } else if (!strcasecmp(var->name, "write") ) { 06772 user->writeperm = get_perm(var->value); 06773 } else if (!strcasecmp(var->name, "displayconnects") ) { 06774 user->displayconnects = ast_true(var->value); 06775 } else if (!strcasecmp(var->name, "writetimeout")) { 06776 int value = atoi(var->value); 06777 if (value < 100) { 06778 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno); 06779 } else { 06780 user->writetimeout = value; 06781 } 06782 } else if (!strcasecmp(var->name, "eventfilter")) { 06783 const char *value = var->value; 06784 regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation"); 06785 if (new_filter) { 06786 int is_blackfilter; 06787 if (value[0] == '!') { 06788 is_blackfilter = 1; 06789 value++; 06790 } else { 06791 is_blackfilter = 0; 06792 } 06793 if (regcomp(new_filter, value, 0)) { 06794 ao2_t_ref(new_filter, -1, "failed to make regx"); 06795 } else { 06796 if (is_blackfilter) { 06797 ao2_t_link(user->blackfilters, new_filter, "link new filter into black user container"); 06798 } else { 06799 ao2_t_link(user->whitefilters, new_filter, "link new filter into white user container"); 06800 } 06801 } 06802 } 06803 } else { 06804 ast_debug(1, "%s is an unknown option.\n", var->name); 06805 } 06806 } 06807 ast_free_ha(oldha); 06808 } 06809 ast_config_destroy(cfg); 06810 06811 /* Perform cleanup - essentially prune out old users that no longer exist */ 06812 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) { 06813 if (user->keep) { /* valid record. clear flag for the next round */ 06814 user->keep = 0; 06815 06816 /* Calculate A1 for Digest auth */ 06817 snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret); 06818 ast_md5_hash(a1_hash,a1); 06819 if (user->a1_hash) { 06820 ast_free(user->a1_hash); 06821 } 06822 user->a1_hash = ast_strdup(a1_hash); 06823 continue; 06824 } 06825 /* We do not need to keep this user so take them out of the list */ 06826 AST_RWLIST_REMOVE_CURRENT(list); 06827 ast_debug(4, "Pruning user '%s'\n", user->username); 06828 /* Free their memory now */ 06829 if (user->a1_hash) { 06830 ast_free(user->a1_hash); 06831 } 06832 if (user->secret) { 06833 ast_free(user->secret); 06834 } 06835 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters"); 06836 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters"); 06837 ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one"); 06838 ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one"); 06839 ast_free_ha(user->ha); 06840 ast_free(user); 06841 } 06842 AST_RWLIST_TRAVERSE_SAFE_END; 06843 06844 AST_RWLIST_UNLOCK(&users); 06845 06846 if (!reload) { 06847 /* If you have a NULL hash fn, you only need a single bucket */ 06848 sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn); 06849 } 06850 06851 if (webmanager_enabled && manager_enabled) { 06852 if (!webregged) { 06853 06854 ast_http_uri_link(&rawmanuri); 06855 ast_http_uri_link(&manageruri); 06856 ast_http_uri_link(&managerxmluri); 06857 06858 ast_http_uri_link(&arawmanuri); 06859 ast_http_uri_link(&amanageruri); 06860 ast_http_uri_link(&amanagerxmluri); 06861 webregged = 1; 06862 } 06863 } else { 06864 if (webregged) { 06865 ast_http_uri_unlink(&rawmanuri); 06866 ast_http_uri_unlink(&manageruri); 06867 ast_http_uri_unlink(&managerxmluri); 06868 06869 ast_http_uri_unlink(&arawmanuri); 06870 ast_http_uri_unlink(&amanageruri); 06871 ast_http_uri_unlink(&amanagerxmluri); 06872 webregged = 0; 06873 } 06874 } 06875 06876 if (newhttptimeout > 0) { 06877 httptimeout = newhttptimeout; 06878 } 06879 06880 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled"); 06881 06882 ast_tcptls_server_start(&ami_desc); 06883 if (ast_ssl_setup(amis_desc.tls_cfg)) { 06884 ast_tcptls_server_start(&amis_desc); 06885 } 06886 return 0; 06887 }
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 6910 of file manager.c.
References AST_LIST_INSERT_HEAD, mansession_session::datastores, manager_channel_variable::entry, and mansession::session.
06911 { 06912 AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry); 06913 06914 return 0; 06915 }
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 6922 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.
06923 { 06924 struct ast_datastore *datastore = NULL; 06925 06926 if (info == NULL) 06927 return NULL; 06928 06929 AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) { 06930 if (datastore->info != info) { 06931 continue; 06932 } 06933 06934 if (uid == NULL) { 06935 /* matched by type only */ 06936 break; 06937 } 06938 06939 if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) { 06940 /* Matched by type AND uid */ 06941 break; 06942 } 06943 } 06944 AST_LIST_TRAVERSE_SAFE_END; 06945 06946 return datastore; 06947 }
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 6917 of file manager.c.
References AST_LIST_REMOVE, mansession_session::datastores, manager_channel_variable::entry, and mansession::session.
06918 { 06919 return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1; 06920 }
int astman_is_authed | ( | uint32_t | ident | ) |
Determinie if a manager session ident is authenticated.
Definition at line 5362 of file manager.c.
References ao2_unlock, mansession_session::authenticated, find_session(), and unref_mansession().
Referenced by http_post_callback(), and static_callback().
05363 { 05364 int authed; 05365 struct mansession_session *session; 05366 05367 if (!(session = find_session(ident, 0))) 05368 return 0; 05369 05370 authed = (session->authenticated != 0); 05371 05372 ao2_unlock(session); 05373 unref_mansession(session); 05374 05375 return authed; 05376 }
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 5378 of file manager.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().
05379 { 05380 int result = 0; 05381 struct mansession_session *session; 05382 struct ao2_iterator i; 05383 05384 if (ident == 0) { 05385 return 0; 05386 } 05387 05388 i = ao2_iterator_init(sessions, 0); 05389 while ((session = ao2_iterator_next(&i))) { 05390 ao2_lock(session); 05391 if ((session->managerid == ident) && (session->readperm & perm)) { 05392 result = 1; 05393 ao2_unlock(session); 05394 unref_mansession(session); 05395 break; 05396 } 05397 ao2_unlock(session); 05398 unref_mansession(session); 05399 } 05400 ao2_iterator_destroy(&i); 05401 return result; 05402 }
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 5404 of file manager.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().
05405 { 05406 int result = 0; 05407 struct mansession_session *session; 05408 struct ao2_iterator i; 05409 05410 if (ident == 0) { 05411 return 0; 05412 } 05413 05414 i = ao2_iterator_init(sessions, 0); 05415 while ((session = ao2_iterator_next(&i))) { 05416 ao2_lock(session); 05417 if ((session->managerid == ident) && (session->writeperm & perm)) { 05418 result = 1; 05419 ao2_unlock(session); 05420 unref_mansession(session); 05421 break; 05422 } 05423 ao2_unlock(session); 05424 unref_mansession(session); 05425 } 05426 ao2_iterator_destroy(&i); 05427 return result; 05428 }
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 5908 of file manager.c.
References ast_http_error(), AST_HTTP_GET, AST_HTTP_HEAD, AST_HTTP_POST, get_params(), ast_variable::name, ast_variable::next, and mansession::session.
Referenced by auth_manager_http_callback(), auth_mxml_http_callback(), and auth_rawman_http_callback().
05914 { 05915 struct mansession_session *session = NULL; 05916 struct mansession s = { .session = NULL, .tcptls_session = ser }; 05917 struct ast_variable *v, *params = get_params; 05918 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */ 05919 struct ast_str *http_header = NULL, *out = NULL; 05920 size_t result_size = 512; 05921 struct message m = { 0 }; 05922 unsigned int idx; 05923 size_t hdrlen; 05924 05925 time_t time_now = time(NULL); 05926 unsigned long nonce = 0, nc; 05927 struct ast_http_digest d = { NULL, }; 05928 struct ast_manager_user *user = NULL; 05929 int stale = 0; 05930 char resp_hash[256]=""; 05931 /* Cache for user data */ 05932 char u_username[80]; 05933 int u_readperm; 05934 int u_writeperm; 05935 int u_writetimeout; 05936 int u_displayconnects; 05937 struct ast_sockaddr addr; 05938 05939 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) { 05940 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 05941 return -1; 05942 } 05943 05944 /* Find "Authorization: " header */ 05945 for (v = headers; v; v = v->next) { 05946 if (!strcasecmp(v->name, "Authorization")) { 05947 break; 05948 } 05949 } 05950 05951 if (!v || ast_strlen_zero(v->value)) { 05952 goto out_401; /* Authorization Header not present - send auth request */ 05953 } 05954 05955 /* Digest found - parse */ 05956 if (ast_string_field_init(&d, 128)) { 05957 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 05958 return -1; 05959 } 05960 05961 if (ast_parse_digest(v->value, &d, 0, 1)) { 05962 /* Error in Digest - send new one */ 05963 nonce = 0; 05964 goto out_401; 05965 } 05966 if (sscanf(d.nonce, "%30lx", &nonce) != 1) { 05967 ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce); 05968 nonce = 0; 05969 goto out_401; 05970 } 05971 05972 AST_RWLIST_WRLOCK(&users); 05973 user = get_manager_by_name_locked(d.username); 05974 if(!user) { 05975 AST_RWLIST_UNLOCK(&users); 05976 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username); 05977 nonce = 0; 05978 goto out_401; 05979 } 05980 05981 ast_sockaddr_from_sin(&addr, remote_address); 05982 /* --- We have User for this auth, now check ACL */ 05983 if (user->ha && !ast_apply_ha(user->ha, &addr)) { 05984 AST_RWLIST_UNLOCK(&users); 05985 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username); 05986 ast_http_error(ser, 403, "Permission denied", "Permission denied\n"); 05987 return -1; 05988 } 05989 05990 /* --- We have auth, so check it */ 05991 05992 /* compute the expected response to compare with what we received */ 05993 { 05994 char a2[256]; 05995 char a2_hash[256]; 05996 char resp[256]; 05997 05998 /* XXX Now request method are hardcoded in A2 */ 05999 snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri); 06000 ast_md5_hash(a2_hash, a2); 06001 06002 if (d.qop) { 06003 /* RFC 2617 */ 06004 snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash); 06005 } else { 06006 /* RFC 2069 */ 06007 snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash); 06008 } 06009 ast_md5_hash(resp_hash, resp); 06010 } 06011 06012 if (!d.nonce || strncasecmp(d.response, resp_hash, strlen(resp_hash))) { 06013 /* Something was wrong, so give the client to try with a new challenge */ 06014 AST_RWLIST_UNLOCK(&users); 06015 nonce = 0; 06016 goto out_401; 06017 } 06018 06019 /* 06020 * User are pass Digest authentication. 06021 * Now, cache the user data and unlock user list. 06022 */ 06023 ast_copy_string(u_username, user->username, sizeof(u_username)); 06024 u_readperm = user->readperm; 06025 u_writeperm = user->writeperm; 06026 u_displayconnects = user->displayconnects; 06027 u_writetimeout = user->writetimeout; 06028 AST_RWLIST_UNLOCK(&users); 06029 06030 if (!(session = find_session_by_nonce(d.username, nonce, &stale))) { 06031 /* 06032 * Create new session. 06033 * While it is not in the list we don't need any locking 06034 */ 06035 if (!(session = build_mansession(*remote_address))) { 06036 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 06037 return -1; 06038 } 06039 ao2_lock(session); 06040 06041 ast_copy_string(session->username, u_username, sizeof(session->username)); 06042 session->managerid = nonce; 06043 session->last_ev = grab_last(); 06044 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores); 06045 06046 session->readperm = u_readperm; 06047 session->writeperm = u_writeperm; 06048 session->writetimeout = u_writetimeout; 06049 06050 if (u_displayconnects) { 06051 ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 06052 } 06053 session->noncetime = session->sessionstart = time_now; 06054 session->authenticated = 1; 06055 } else if (stale) { 06056 /* 06057 * Session found, but nonce is stale. 06058 * 06059 * This could be because an old request (w/old nonce) arrived. 06060 * 06061 * This may be as the result of http proxy usage (separate delay or 06062 * multipath) or in a situation where a page was refreshed too quickly 06063 * (seen in Firefox). 06064 * 06065 * In this situation, we repeat the 401 auth with the current nonce 06066 * value. 06067 */ 06068 nonce = session->managerid; 06069 ao2_unlock(session); 06070 stale = 1; 06071 goto out_401; 06072 } else { 06073 sscanf(d.nc, "%30lx", &nc); 06074 if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) { 06075 /* 06076 * Nonce time expired (> 2 minutes) or something wrong with nonce 06077 * counter. 06078 * 06079 * Create new nonce key and resend Digest auth request. Old nonce 06080 * is saved for stale checking... 06081 */ 06082 session->nc = 0; /* Reset nonce counter */ 06083 session->oldnonce = session->managerid; 06084 nonce = session->managerid = ast_random(); 06085 session->noncetime = time_now; 06086 ao2_unlock(session); 06087 stale = 1; 06088 goto out_401; 06089 } else { 06090 session->nc = nc; /* All OK, save nonce counter */ 06091 } 06092 } 06093 06094 06095 /* Reset session timeout. */ 06096 session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5); 06097 ao2_unlock(session); 06098 06099 ast_mutex_init(&s.lock); 06100 s.session = session; 06101 s.fd = mkstemp(template); /* create a temporary file for command output */ 06102 unlink(template); 06103 if (s.fd <= -1) { 06104 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n"); 06105 goto auth_callback_out; 06106 } 06107 s.f = fdopen(s.fd, "w+"); 06108 if (!s.f) { 06109 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno)); 06110 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n"); 06111 close(s.fd); 06112 goto auth_callback_out; 06113 } 06114 06115 if (method == AST_HTTP_POST) { 06116 params = ast_http_get_post_vars(ser, headers); 06117 } 06118 06119 for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) { 06120 hdrlen = strlen(v->name) + strlen(v->value) + 3; 06121 m.headers[m.hdrcount] = ast_malloc(hdrlen); 06122 if (!m.headers[m.hdrcount]) { 06123 /* Allocation failure */ 06124 continue; 06125 } 06126 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value); 06127 ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]); 06128 ++m.hdrcount; 06129 } 06130 06131 if (process_message(&s, &m)) { 06132 if (u_displayconnects) { 06133 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 06134 } 06135 06136 session->needdestroy = 1; 06137 } 06138 06139 /* Free request headers. */ 06140 for (idx = 0; idx < m.hdrcount; ++idx) { 06141 ast_free((void *) m.headers[idx]); 06142 m.headers[idx] = NULL; 06143 } 06144 06145 if (s.f) { 06146 result_size = ftell(s.f); /* Calculate approx. size of result */ 06147 } 06148 06149 http_header = ast_str_create(80); 06150 out = ast_str_create(result_size * 2 + 512); 06151 06152 if (http_header == NULL || out == NULL) { 06153 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n"); 06154 goto auth_callback_out; 06155 } 06156 06157 ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]); 06158 06159 if (format == FORMAT_XML) { 06160 ast_str_append(&out, 0, "<ajax-response>\n"); 06161 } else if (format == FORMAT_HTML) { 06162 ast_str_append(&out, 0, 06163 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 06164 "<html><head>\r\n" 06165 "<title>Asterisk™ Manager Interface</title>\r\n" 06166 "</head><body style=\"background-color: #ffffff;\">\r\n" 06167 "<form method=\"POST\">\r\n" 06168 "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n" 06169 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n" 06170 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>" 06171 "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n"); 06172 } 06173 06174 process_output(&s, &out, params, format); 06175 06176 if (format == FORMAT_XML) { 06177 ast_str_append(&out, 0, "</ajax-response>\n"); 06178 } else if (format == FORMAT_HTML) { 06179 ast_str_append(&out, 0, "</table></form></body></html>\r\n"); 06180 } 06181 06182 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0); 06183 http_header = out = NULL; 06184 06185 auth_callback_out: 06186 ast_mutex_destroy(&s.lock); 06187 06188 /* Clear resources and unlock manager session */ 06189 if (method == AST_HTTP_POST && params) { 06190 ast_variables_destroy(params); 06191 } 06192 06193 ast_free(http_header); 06194 ast_free(out); 06195 06196 ao2_lock(session); 06197 if (session->f) { 06198 fclose(session->f); 06199 } 06200 session->f = NULL; 06201 session->fd = -1; 06202 ao2_unlock(session); 06203 06204 if (session->needdestroy) { 06205 ast_debug(1, "Need destroy, doing it now!\n"); 06206 session_destroy(session); 06207 } 06208 ast_string_field_free_memory(&d); 06209 return 0; 06210 06211 out_401: 06212 if (!nonce) { 06213 nonce = ast_random(); 06214 } 06215 06216 ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL); 06217 ast_string_field_free_memory(&d); 06218 return 0; 06219 }
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 6280 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.
06281 { 06282 int retval; 06283 struct sockaddr_in ser_remote_address_tmp; 06284 06285 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06286 retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers); 06287 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06288 return retval; 06289 }
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 6291 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.
06292 { 06293 int retval; 06294 struct sockaddr_in ser_remote_address_tmp; 06295 06296 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06297 retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers); 06298 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06299 return retval; 06300 }
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 6302 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.
06303 { 06304 int retval; 06305 struct sockaddr_in ser_remote_address_tmp; 06306 06307 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06308 retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers); 06309 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06310 return retval; 06311 }
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 5303 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().
05304 { 05305 struct mansession_session *session; 05306 struct ao2_iterator i; 05307 05308 if (ident == 0) { 05309 return NULL; 05310 } 05311 05312 i = ao2_iterator_init(sessions, 0); 05313 while ((session = ao2_iterator_next(&i))) { 05314 ao2_lock(session); 05315 if (session->managerid == ident && !session->needdestroy) { 05316 ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0); 05317 break; 05318 } 05319 ao2_unlock(session); 05320 unref_mansession(session); 05321 } 05322 ao2_iterator_destroy(&i); 05323 05324 return session; 05325 }
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 5336 of file manager.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().
05337 { 05338 struct mansession_session *session; 05339 struct ao2_iterator i; 05340 05341 if (nonce == 0 || username == NULL || stale == NULL) { 05342 return NULL; 05343 } 05344 05345 i = ao2_iterator_init(sessions, 0); 05346 while ((session = ao2_iterator_next(&i))) { 05347 ao2_lock(session); 05348 if (!strcasecmp(session->username, username) && session->managerid == nonce) { 05349 *stale = 0; 05350 break; 05351 } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) { 05352 *stale = 1; 05353 break; 05354 } 05355 ao2_unlock(session); 05356 unref_mansession(session); 05357 } 05358 ao2_iterator_destroy(&i); 05359 return session; 05360 }
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 5693 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().
05699 { 05700 struct mansession s = { .session = NULL, .tcptls_session = ser }; 05701 struct mansession_session *session = NULL; 05702 uint32_t ident = 0; 05703 int blastaway = 0; 05704 struct ast_variable *v, *cookies, *params = get_params; 05705 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */ 05706 struct ast_str *http_header = NULL, *out = NULL; 05707 struct message m = { 0 }; 05708 unsigned int idx; 05709 size_t hdrlen; 05710 05711 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) { 05712 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 05713 return -1; 05714 } 05715 05716 cookies = ast_http_get_cookies(headers); 05717 for (v = cookies; v; v = v->next) { 05718 if (!strcasecmp(v->name, "mansession_id")) { 05719 sscanf(v->value, "%30x", &ident); 05720 break; 05721 } 05722 } 05723 if (cookies) { 05724 ast_variables_destroy(cookies); 05725 } 05726 05727 if (!(session = find_session(ident, 1))) { 05728 05729 /**/ 05730 /* Create new session. 05731 * While it is not in the list we don't need any locking 05732 */ 05733 if (!(session = build_mansession(*remote_address))) { 05734 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 05735 return -1; 05736 } 05737 ao2_lock(session); 05738 session->sin = *remote_address; 05739 session->fd = -1; 05740 session->waiting_thread = AST_PTHREADT_NULL; 05741 session->send_events = 0; 05742 session->inuse = 1; 05743 /*!\note There is approximately a 1 in 1.8E19 chance that the following 05744 * calculation will produce 0, which is an invalid ID, but due to the 05745 * properties of the rand() function (and the constantcy of s), that 05746 * won't happen twice in a row. 05747 */ 05748 while ((session->managerid = ast_random() ^ (unsigned long) session) == 0); 05749 session->last_ev = grab_last(); 05750 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores); 05751 } 05752 ao2_unlock(session); 05753 05754 http_header = ast_str_create(128); 05755 out = ast_str_create(2048); 05756 05757 ast_mutex_init(&s.lock); 05758 05759 if (http_header == NULL || out == NULL) { 05760 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n"); 05761 goto generic_callback_out; 05762 } 05763 05764 s.session = session; 05765 s.fd = mkstemp(template); /* create a temporary file for command output */ 05766 unlink(template); 05767 if (s.fd <= -1) { 05768 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n"); 05769 goto generic_callback_out; 05770 } 05771 s.f = fdopen(s.fd, "w+"); 05772 if (!s.f) { 05773 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno)); 05774 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n"); 05775 close(s.fd); 05776 goto generic_callback_out; 05777 } 05778 05779 if (method == AST_HTTP_POST) { 05780 params = ast_http_get_post_vars(ser, headers); 05781 } 05782 05783 for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) { 05784 hdrlen = strlen(v->name) + strlen(v->value) + 3; 05785 m.headers[m.hdrcount] = ast_malloc(hdrlen); 05786 if (!m.headers[m.hdrcount]) { 05787 /* Allocation failure */ 05788 continue; 05789 } 05790 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value); 05791 ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]); 05792 ++m.hdrcount; 05793 } 05794 05795 if (process_message(&s, &m)) { 05796 if (session->authenticated) { 05797 if (manager_displayconnects(session)) { 05798 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 05799 } 05800 } else { 05801 if (displayconnects) { 05802 ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr)); 05803 } 05804 } 05805 session->needdestroy = 1; 05806 } 05807 05808 /* Free request headers. */ 05809 for (idx = 0; idx < m.hdrcount; ++idx) { 05810 ast_free((void *) m.headers[idx]); 05811 m.headers[idx] = NULL; 05812 } 05813 05814 ast_str_append(&http_header, 0, 05815 "Content-type: text/%s\r\n" 05816 "Cache-Control: no-cache;\r\n" 05817 "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n" 05818 "Pragma: SuppressEvents\r\n", 05819 contenttype[format], 05820 session->managerid, httptimeout); 05821 05822 if (format == FORMAT_XML) { 05823 ast_str_append(&out, 0, "<ajax-response>\n"); 05824 } else if (format == FORMAT_HTML) { 05825 /* 05826 * When handling AMI-over-HTTP in HTML format, we provide a simple form for 05827 * debugging purposes. This HTML code should not be here, we 05828 * should read from some config file... 05829 */ 05830 05831 #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n" 05832 #define TEST_STRING \ 05833 "<form action=\"manager\" method=\"post\">\n\ 05834 Action: <select name=\"action\">\n\ 05835 <option value=\"\">-----></option>\n\ 05836 <option value=\"login\">login</option>\n\ 05837 <option value=\"command\">Command</option>\n\ 05838 <option value=\"waitevent\">waitevent</option>\n\ 05839 <option value=\"listcommands\">listcommands</option>\n\ 05840 </select>\n\ 05841 or <input name=\"action\"><br/>\n\ 05842 CLI Command <input name=\"command\"><br>\n\ 05843 user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\ 05844 <input type=\"submit\">\n</form>\n" 05845 05846 ast_str_append(&out, 0, "<title>Asterisk™ Manager Interface</title>"); 05847 ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n"); 05848 ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>"); 05849 ast_str_append(&out, 0, ROW_FMT, TEST_STRING); 05850 } 05851 05852 process_output(&s, &out, params, format); 05853 05854 if (format == FORMAT_XML) { 05855 ast_str_append(&out, 0, "</ajax-response>\n"); 05856 } else if (format == FORMAT_HTML) { 05857 ast_str_append(&out, 0, "</table></body>\r\n"); 05858 } 05859 05860 ao2_lock(session); 05861 /* Reset HTTP timeout. If we're not authenticated, keep it extremely short */ 05862 session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5); 05863 05864 if (session->needdestroy) { 05865 if (session->inuse == 1) { 05866 ast_debug(1, "Need destroy, doing it now!\n"); 05867 blastaway = 1; 05868 } else { 05869 ast_debug(1, "Need destroy, but can't do it yet!\n"); 05870 if (session->waiting_thread != AST_PTHREADT_NULL) { 05871 pthread_kill(session->waiting_thread, SIGURG); 05872 } 05873 session->inuse--; 05874 } 05875 } else { 05876 session->inuse--; 05877 } 05878 ao2_unlock(session); 05879 05880 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0); 05881 http_header = out = NULL; 05882 05883 generic_callback_out: 05884 ast_mutex_destroy(&s.lock); 05885 05886 /* Clear resource */ 05887 05888 if (method == AST_HTTP_POST && params) { 05889 ast_variables_destroy(params); 05890 } 05891 if (http_header) { 05892 ast_free(http_header); 05893 } 05894 if (out) { 05895 ast_free(out); 05896 } 05897 05898 if (session && blastaway) { 05899 session_destroy(session); 05900 } else if (session && session->f) { 05901 fclose(session->f); 05902 session->f = NULL; 05903 } 05904 05905 return 0; 05906 }
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 6375 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.
06376 { 06377 switch (cmd) { 06378 case CLI_INIT: 06379 e->command = "manager show settings"; 06380 e->usage = 06381 "Usage: manager show settings\n" 06382 " Provides detailed list of the configuration of the Manager.\n"; 06383 return NULL; 06384 case CLI_GENERATE: 06385 return NULL; 06386 } 06387 #define FORMAT " %-25.25s %-15.15s\n" 06388 #define FORMAT2 " %-25.25s %-15d\n" 06389 if (a->argc != 3) { 06390 return CLI_SHOWUSAGE; 06391 } 06392 ast_cli(a->fd, "\nGlobal Settings:\n"); 06393 ast_cli(a->fd, "----------------\n"); 06394 ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled)); 06395 ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled)); 06396 ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled"); 06397 ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout); 06398 ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled)); 06399 ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled"); 06400 ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile); 06401 ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile); 06402 ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher); 06403 ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin)); 06404 ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects)); 06405 ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents)); 06406 ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, "")); 06407 ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug)); 06408 ast_cli(a->fd, FORMAT, "Block sockets:", AST_CLI_YESNO(block_sockets)); 06409 #undef FORMAT 06410 #undef FORMAT2 06411 06412 return CLI_SUCCESS; 06413 }
int init_manager | ( | void | ) |
Called by Asterisk initialization.
Definition at line 6900 of file manager.c.
References __init_manager().
Referenced by main().
06901 { 06902 return __init_manager(0); 06903 }
static void load_channelvars | ( | struct ast_variable * | var | ) | [static] |
Definition at line 6435 of file manager.c.
References ast_calloc, ast_free, AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_strdupa, manager_channel_variable::entry, free_channelvars(), manager_channelvars, manager_channel_variable::next, strsep(), and var.
06436 { 06437 struct manager_channel_variable *mcv; 06438 char *remaining = ast_strdupa(var->value); 06439 char *next; 06440 06441 ast_free(manager_channelvars); 06442 manager_channelvars = ast_strdup(var->value); 06443 06444 /* 06445 * XXX TODO: To allow dialplan functions to have more than one 06446 * parameter requires eliminating the '|' as a separator so we 06447 * could use AST_STANDARD_APP_ARGS() to separate items. 06448 */ 06449 free_channelvars(); 06450 AST_RWLIST_WRLOCK(&channelvars); 06451 while ((next = strsep(&remaining, ",|"))) { 06452 if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) { 06453 break; 06454 } 06455 strcpy(mcv->name, next); /* SAFE */ 06456 if (strchr(next, '(')) { 06457 mcv->isfunc = 1; 06458 } 06459 AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry); 06460 } 06461 AST_RWLIST_UNLOCK(&channelvars); 06462 }
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 6221 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.
06222 { 06223 int retval; 06224 struct sockaddr_in ser_remote_address_tmp; 06225 06226 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06227 retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers); 06228 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06229 return retval; 06230 }
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 6232 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.
06233 { 06234 int retval; 06235 struct sockaddr_in ser_remote_address_tmp; 06236 06237 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06238 retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers); 06239 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06240 return retval; 06241 }
static void process_output | ( | struct mansession * | s, | |
struct ast_str ** | out, | |||
struct ast_variable * | params, | |||
enum output_format | format | |||
) | [static] |
Definition at line 5660 of file manager.c.
References ast_log(), ast_str_append(), mansession::f, mansession::fd, FORMAT_HTML, FORMAT_XML, LOG_WARNING, and xml_translate().
05661 { 05662 char *buf; 05663 size_t l; 05664 05665 if (!s->f) 05666 return; 05667 05668 /* Ensure buffer is NULL-terminated */ 05669 fprintf(s->f, "%c", 0); 05670 fflush(s->f); 05671 05672 if ((l = ftell(s->f))) { 05673 if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) { 05674 ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n"); 05675 } else { 05676 if (format == FORMAT_XML || format == FORMAT_HTML) { 05677 xml_translate(out, buf, params, format); 05678 } else { 05679 ast_str_append(out, 0, "%s", buf); 05680 } 05681 munmap(buf, l); 05682 } 05683 } else if (format == FORMAT_XML || format == FORMAT_HTML) { 05684 xml_translate(out, "", params, format); 05685 } 05686 05687 fclose(s->f); 05688 s->f = NULL; 05689 close(s->fd); 05690 s->fd = -1; 05691 }
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 6346 of file manager.c.
References purge_events(), and purge_sessions().
06347 { 06348 purge_sessions(1); 06349 purge_events(); 06350 }
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 6243 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.
06244 { 06245 int retval; 06246 struct sockaddr_in ser_remote_address_tmp; 06247 06248 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06249 retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers); 06250 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06251 return retval; 06252 }
int reload_manager | ( | void | ) |
Called by Asterisk module functions and the CLI command.
Definition at line 6905 of file manager.c.
References __init_manager().
Referenced by handle_manager_reload().
06906 { 06907 return __init_manager(1); 06908 }
static int variable_count_cmp_fn | ( | void * | obj, | |
void * | vstr, | |||
int | flags | |||
) | [static] |
Definition at line 5504 of file manager.c.
References CMP_MATCH, CMP_STOP, str, and variable_count::varname.
05505 { 05506 /* Due to the simplicity of struct variable_count, it makes no difference 05507 * if you pass in objects or strings, the same operation applies. This is 05508 * due to the fact that the hash occurs on the first element, which means 05509 * the address of both the struct and the string are exactly the same. */ 05510 struct variable_count *vc = obj; 05511 char *str = vstr; 05512 return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0; 05513 }
static int variable_count_hash_fn | ( | const void * | vvc, | |
const int | flags | |||
) | [static] |
Definition at line 5497 of file manager.c.
References ast_str_hash(), and variable_count::varname.
05498 { 05499 const struct variable_count *vc = vvc; 05500 05501 return ast_str_hash(vc->varname); 05502 }
static void xml_copy_escape | ( | struct ast_str ** | out, | |
const char * | src, | |||
int | mode | |||
) | [static] |
Definition at line 5435 of file manager.c.
References ast_str_append().
05436 { 05437 /* store in a local buffer to avoid calling ast_str_append too often */ 05438 char buf[256]; 05439 char *dst = buf; 05440 int space = sizeof(buf); 05441 /* repeat until done and nothing to flush */ 05442 for ( ; *src || dst != buf ; src++) { 05443 if (*src == '\0' || space < 10) { /* flush */ 05444 *dst++ = '\0'; 05445 ast_str_append(out, 0, "%s", buf); 05446 dst = buf; 05447 space = sizeof(buf); 05448 if (*src == '\0') { 05449 break; 05450 } 05451 } 05452 05453 if ( (mode & 2) && !isalnum(*src)) { 05454 *dst++ = '_'; 05455 space--; 05456 continue; 05457 } 05458 switch (*src) { 05459 case '<': 05460 strcpy(dst, "<"); 05461 dst += 4; 05462 space -= 4; 05463 break; 05464 case '>': 05465 strcpy(dst, ">"); 05466 dst += 4; 05467 space -= 4; 05468 break; 05469 case '\"': 05470 strcpy(dst, """); 05471 dst += 6; 05472 space -= 6; 05473 break; 05474 case '\'': 05475 strcpy(dst, "'"); 05476 dst += 6; 05477 space -= 6; 05478 break; 05479 case '&': 05480 strcpy(dst, "&"); 05481 dst += 5; 05482 space -= 5; 05483 break; 05484 05485 default: 05486 *dst++ = mode ? tolower(*src) : *src; 05487 space--; 05488 } 05489 } 05490 }
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 5543 of file manager.c.
References FORMAT_XML, ast_variable::name, ast_variable::next, ast_variable::value, and var.
Referenced by process_output().
05544 { 05545 struct ast_variable *v; 05546 const char *dest = NULL; 05547 char *var, *val; 05548 const char *objtype = NULL; 05549 int in_data = 0; /* parsing data */ 05550 int inobj = 0; 05551 int xml = (format == FORMAT_XML); 05552 struct variable_count *vc = NULL; 05553 struct ao2_container *vco = NULL; 05554 05555 if (xml) { 05556 /* dest and objtype need only for XML format */ 05557 for (v = get_vars; v; v = v->next) { 05558 if (!strcasecmp(v->name, "ajaxdest")) { 05559 dest = v->value; 05560 } else if (!strcasecmp(v->name, "ajaxobjtype")) { 05561 objtype = v->value; 05562 } 05563 } 05564 if (ast_strlen_zero(dest)) { 05565 dest = "unknown"; 05566 } 05567 if (ast_strlen_zero(objtype)) { 05568 objtype = "generic"; 05569 } 05570 } 05571 05572 /* we want to stop when we find an empty line */ 05573 while (in && *in) { 05574 val = strsep(&in, "\r\n"); /* mark start and end of line */ 05575 if (in && *in == '\n') { /* remove trailing \n if any */ 05576 in++; 05577 } 05578 ast_trim_blanks(val); 05579 ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val); 05580 if (ast_strlen_zero(val)) { 05581 /* empty line */ 05582 if (in_data) { 05583 /* close data in Opaque mode */ 05584 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n"); 05585 in_data = 0; 05586 } 05587 05588 if (inobj) { 05589 /* close block */ 05590 ast_str_append(out, 0, xml ? " /></response>\n" : 05591 "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 05592 inobj = 0; 05593 ao2_ref(vco, -1); 05594 vco = NULL; 05595 } 05596 continue; 05597 } 05598 05599 if (!inobj) { 05600 /* start new block */ 05601 if (xml) { 05602 ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype); 05603 } 05604 vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn); 05605 inobj = 1; 05606 } 05607 05608 if (in_data) { 05609 /* Process data field in Opaque mode. This is a 05610 * followup, so we re-add line feeds. */ 05611 ast_str_append(out, 0, xml ? "\n" : "<br>\n"); 05612 xml_copy_escape(out, val, 0); /* data field */ 05613 continue; 05614 } 05615 05616 /* We expect "Name: value" line here */ 05617 var = strsep(&val, ":"); 05618 if (val) { 05619 /* found the field name */ 05620 val = ast_skip_blanks(val); 05621 ast_trim_blanks(var); 05622 } else { 05623 /* field name not found, switch to opaque mode */ 05624 val = var; 05625 var = "Opaque-data"; 05626 in_data = 1; 05627 } 05628 05629 05630 ast_str_append(out, 0, xml ? " " : "<tr><td>"); 05631 if ((vc = ao2_find(vco, var, 0))) { 05632 vc->count++; 05633 } else { 05634 /* Create a new entry for this one */ 05635 vc = ao2_alloc(sizeof(*vc), NULL); 05636 vc->varname = var; 05637 vc->count = 1; 05638 ao2_link(vco, vc); 05639 } 05640 05641 xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */ 05642 if (vc->count > 1) { 05643 ast_str_append(out, 0, "-%d", vc->count); 05644 } 05645 ao2_ref(vc, -1); 05646 ast_str_append(out, 0, xml ? "='" : "</td><td>"); 05647 xml_copy_escape(out, val, 0); /* data field */ 05648 if (!in_data || !*in) { 05649 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n"); 05650 } 05651 } 05652 05653 if (inobj) { 05654 ast_str_append(out, 0, xml ? " /></response>\n" : 05655 "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 05656 ao2_ref(vco, -1); 05657 } 05658 }
struct ast_http_uri amanageruri [static] |
struct ast_http_uri amanagerxmluri [static] |
struct ast_tcptls_session_args ami_desc [static] |
Definition at line 6353 of file manager.c.
Referenced by __init_manager(), and handle_manager_show_settings().
struct ast_tls_config ami_tls_cfg [static] |
Definition at line 6352 of file manager.c.
Referenced by __init_manager(), and handle_manager_show_settings().
struct ast_tcptls_session_args amis_desc [static] |
Definition at line 6364 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] |