#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 void | destroy_fast_originate_helper (struct fast_originate_helper *doomed) |
static int | do_message (struct mansession *s) |
static void | event_filter_destructor (void *obj) |
static void * | fast_originate (void *data) |
static struct mansession_session * | find_session (uint32_t ident, int incinuse) |
static struct mansession_session * | find_session_by_nonce (const char *username, unsigned long nonce, int *stale) |
static void | free_channelvars (void) |
static int | function_capable_string_allowed_with_auths (const char *evaluating, int writepermlist) |
Checks to see if a string which can be used to evaluate functions should be rejected. | |
static int | generic_http_callback (struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, 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 5387 of file manager.c.
05387 { 05388 FORMAT_RAW, 05389 FORMAT_HTML, 05390 FORMAT_XML, 05391 };
static int __init_manager | ( | int | reload | ) | [static] |
Definition at line 6575 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_sockaddr_setnull(), 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_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().
06576 { 06577 struct ast_config *ucfg = NULL, *cfg = NULL; 06578 const char *val; 06579 char *cat = NULL; 06580 int newhttptimeout = DEFAULT_HTTPTIMEOUT; 06581 struct ast_manager_user *user = NULL; 06582 struct ast_variable *var; 06583 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06584 char a1[256]; 06585 char a1_hash[256]; 06586 struct sockaddr_in ami_desc_local_address_tmp = { 0, }; 06587 struct sockaddr_in amis_desc_local_address_tmp = { 0, }; 06588 int tls_was_enabled = 0; 06589 06590 if (!registered) { 06591 /* Register default actions */ 06592 ast_manager_register_xml("Ping", 0, action_ping); 06593 ast_manager_register_xml("Events", 0, action_events); 06594 ast_manager_register_xml("Logoff", 0, action_logoff); 06595 ast_manager_register_xml("Login", 0, action_login); 06596 ast_manager_register_xml("Challenge", 0, action_challenge); 06597 ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup); 06598 ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status); 06599 ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar); 06600 ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar); 06601 ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig); 06602 ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson); 06603 ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig); 06604 ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig); 06605 ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories); 06606 ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect); 06607 ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer); 06608 ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate); 06609 ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command); 06610 ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate); 06611 ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout); 06612 ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus); 06613 ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount); 06614 ast_manager_register_xml("ListCommands", 0, action_listcommands); 06615 ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext); 06616 ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent); 06617 ast_manager_register_xml("WaitEvent", 0, action_waitevent); 06618 ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings); 06619 ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus); 06620 ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload); 06621 ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels); 06622 ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload); 06623 ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck); 06624 ast_manager_register_xml("AOCMessage", EVENT_FLAG_AOC, action_aocmessage); 06625 06626 ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager)); 06627 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL); 06628 registered = 1; 06629 /* Append placeholder event so master_eventq never runs dry */ 06630 append_event("Event: Placeholder\r\n\r\n", 0); 06631 } 06632 if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) { 06633 return 0; 06634 } 06635 06636 manager_enabled = DEFAULT_ENABLED; 06637 webmanager_enabled = DEFAULT_WEBENABLED; 06638 manager_debug = DEFAULT_MANAGERDEBUG; 06639 displayconnects = DEFAULT_DISPLAYCONNECTS; 06640 broken_events_action = DEFAULT_BROKENEVENTSACTION; 06641 block_sockets = DEFAULT_BLOCKSOCKETS; 06642 timestampevents = DEFAULT_TIMESTAMPEVENTS; 06643 httptimeout = DEFAULT_HTTPTIMEOUT; 06644 authtimeout = DEFAULT_AUTHTIMEOUT; 06645 authlimit = DEFAULT_AUTHLIMIT; 06646 06647 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { 06648 ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled.\n"); 06649 return 0; 06650 } 06651 06652 /* default values */ 06653 ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm)); 06654 ast_sockaddr_setnull(&ami_desc.local_address); 06655 ast_sockaddr_setnull(&amis_desc.local_address); 06656 06657 ami_desc_local_address_tmp.sin_family = AF_INET; 06658 amis_desc_local_address_tmp.sin_family = AF_INET; 06659 06660 ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT); 06661 06662 tls_was_enabled = (reload && ami_tls_cfg.enabled); 06663 06664 ami_tls_cfg.enabled = 0; 06665 if (ami_tls_cfg.certfile) { 06666 ast_free(ami_tls_cfg.certfile); 06667 } 06668 ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE); 06669 if (ami_tls_cfg.pvtfile) { 06670 ast_free(ami_tls_cfg.pvtfile); 06671 } 06672 ami_tls_cfg.pvtfile = ast_strdup(""); 06673 if (ami_tls_cfg.cipher) { 06674 ast_free(ami_tls_cfg.cipher); 06675 } 06676 ami_tls_cfg.cipher = ast_strdup(""); 06677 06678 free_channelvars(); 06679 06680 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 06681 val = var->value; 06682 06683 if (!ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) { 06684 continue; 06685 } 06686 06687 if (!strcasecmp(var->name, "enabled")) { 06688 manager_enabled = ast_true(val); 06689 } else if (!strcasecmp(var->name, "block-sockets")) { 06690 block_sockets = ast_true(val); 06691 } else if (!strcasecmp(var->name, "webenabled")) { 06692 webmanager_enabled = ast_true(val); 06693 } else if (!strcasecmp(var->name, "port")) { 06694 ami_desc_local_address_tmp.sin_port = htons(atoi(val)); 06695 } else if (!strcasecmp(var->name, "bindaddr")) { 06696 if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) { 06697 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val); 06698 memset(&ami_desc_local_address_tmp.sin_addr, 0, 06699 sizeof(ami_desc_local_address_tmp.sin_addr)); 06700 } 06701 } else if (!strcasecmp(var->name, "brokeneventsaction")) { 06702 broken_events_action = ast_true(val); 06703 } else if (!strcasecmp(var->name, "allowmultiplelogin")) { 06704 allowmultiplelogin = ast_true(val); 06705 } else if (!strcasecmp(var->name, "displayconnects")) { 06706 displayconnects = ast_true(val); 06707 } else if (!strcasecmp(var->name, "timestampevents")) { 06708 timestampevents = ast_true(val); 06709 } else if (!strcasecmp(var->name, "debug")) { 06710 manager_debug = ast_true(val); 06711 } else if (!strcasecmp(var->name, "httptimeout")) { 06712 newhttptimeout = atoi(val); 06713 } else if (!strcasecmp(var->name, "authtimeout")) { 06714 int timeout = atoi(var->value); 06715 06716 if (timeout < 1) { 06717 ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value); 06718 } else { 06719 authtimeout = timeout; 06720 } 06721 } else if (!strcasecmp(var->name, "authlimit")) { 06722 int limit = atoi(var->value); 06723 06724 if (limit < 1) { 06725 ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value); 06726 } else { 06727 authlimit = limit; 06728 } 06729 } else if (!strcasecmp(var->name, "channelvars")) { 06730 load_channelvars(var); 06731 } else { 06732 ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n", 06733 var->name, val); 06734 } 06735 } 06736 06737 ast_sockaddr_to_sin(&amis_desc.local_address, &amis_desc_local_address_tmp); 06738 06739 /* if the amis address has not been set, default is the same as non secure ami */ 06740 if (!amis_desc_local_address_tmp.sin_addr.s_addr) { 06741 amis_desc_local_address_tmp.sin_addr = 06742 ami_desc_local_address_tmp.sin_addr; 06743 } 06744 06745 if (!amis_desc_local_address_tmp.sin_port) { 06746 amis_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_TLS_PORT); 06747 } 06748 06749 if (manager_enabled) { 06750 ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp); 06751 ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp); 06752 } 06753 06754 AST_RWLIST_WRLOCK(&users); 06755 06756 /* First, get users from users.conf */ 06757 ucfg = ast_config_load2("users.conf", "manager", config_flags); 06758 if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) { 06759 const char *hasmanager; 06760 int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager")); 06761 06762 while ((cat = ast_category_browse(ucfg, cat))) { 06763 if (!strcasecmp(cat, "general")) { 06764 continue; 06765 } 06766 06767 hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager"); 06768 if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) { 06769 const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret"); 06770 const char *user_read = ast_variable_retrieve(ucfg, cat, "read"); 06771 const char *user_write = ast_variable_retrieve(ucfg, cat, "write"); 06772 const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects"); 06773 const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout"); 06774 06775 /* Look for an existing entry, 06776 * if none found - create one and add it to the list 06777 */ 06778 if (!(user = get_manager_by_name_locked(cat))) { 06779 if (!(user = ast_calloc(1, sizeof(*user)))) { 06780 break; 06781 } 06782 06783 /* Copy name over */ 06784 ast_copy_string(user->username, cat, sizeof(user->username)); 06785 /* Insert into list */ 06786 AST_LIST_INSERT_TAIL(&users, user, list); 06787 user->ha = NULL; 06788 user->keep = 1; 06789 user->readperm = -1; 06790 user->writeperm = -1; 06791 /* Default displayconnect from [general] */ 06792 user->displayconnects = displayconnects; 06793 user->writetimeout = 100; 06794 } 06795 06796 if (!user_secret) { 06797 user_secret = ast_variable_retrieve(ucfg, "general", "secret"); 06798 } 06799 if (!user_read) { 06800 user_read = ast_variable_retrieve(ucfg, "general", "read"); 06801 } 06802 if (!user_write) { 06803 user_write = ast_variable_retrieve(ucfg, "general", "write"); 06804 } 06805 if (!user_displayconnects) { 06806 user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects"); 06807 } 06808 if (!user_writetimeout) { 06809 user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout"); 06810 } 06811 06812 if (!ast_strlen_zero(user_secret)) { 06813 if (user->secret) { 06814 ast_free(user->secret); 06815 } 06816 user->secret = ast_strdup(user_secret); 06817 } 06818 06819 if (user_read) { 06820 user->readperm = get_perm(user_read); 06821 } 06822 if (user_write) { 06823 user->writeperm = get_perm(user_write); 06824 } 06825 if (user_displayconnects) { 06826 user->displayconnects = ast_true(user_displayconnects); 06827 } 06828 if (user_writetimeout) { 06829 int value = atoi(user_writetimeout); 06830 if (value < 100) { 06831 ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value); 06832 } else { 06833 user->writetimeout = value; 06834 } 06835 } 06836 } 06837 } 06838 ast_config_destroy(ucfg); 06839 } 06840 06841 /* cat is NULL here in any case */ 06842 06843 while ((cat = ast_category_browse(cfg, cat))) { 06844 struct ast_ha *oldha; 06845 06846 if (!strcasecmp(cat, "general")) { 06847 continue; 06848 } 06849 06850 /* Look for an existing entry, if none found - create one and add it to the list */ 06851 if (!(user = get_manager_by_name_locked(cat))) { 06852 if (!(user = ast_calloc(1, sizeof(*user)))) { 06853 break; 06854 } 06855 /* Copy name over */ 06856 ast_copy_string(user->username, cat, sizeof(user->username)); 06857 06858 user->ha = NULL; 06859 user->readperm = 0; 06860 user->writeperm = 0; 06861 /* Default displayconnect from [general] */ 06862 user->displayconnects = displayconnects; 06863 user->writetimeout = 100; 06864 user->whitefilters = ao2_container_alloc(1, NULL, NULL); 06865 user->blackfilters = ao2_container_alloc(1, NULL, NULL); 06866 06867 /* Insert into list */ 06868 AST_RWLIST_INSERT_TAIL(&users, user, list); 06869 } else { 06870 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters"); 06871 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters"); 06872 } 06873 06874 /* Make sure we keep this user and don't destroy it during cleanup */ 06875 user->keep = 1; 06876 oldha = user->ha; 06877 user->ha = NULL; 06878 06879 var = ast_variable_browse(cfg, cat); 06880 for (; var; var = var->next) { 06881 if (!strcasecmp(var->name, "secret")) { 06882 if (user->secret) { 06883 ast_free(user->secret); 06884 } 06885 user->secret = ast_strdup(var->value); 06886 } else if (!strcasecmp(var->name, "deny") || 06887 !strcasecmp(var->name, "permit")) { 06888 user->ha = ast_append_ha(var->name, var->value, user->ha, NULL); 06889 } else if (!strcasecmp(var->name, "read") ) { 06890 user->readperm = get_perm(var->value); 06891 } else if (!strcasecmp(var->name, "write") ) { 06892 user->writeperm = get_perm(var->value); 06893 } else if (!strcasecmp(var->name, "displayconnects") ) { 06894 user->displayconnects = ast_true(var->value); 06895 } else if (!strcasecmp(var->name, "writetimeout")) { 06896 int value = atoi(var->value); 06897 if (value < 100) { 06898 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno); 06899 } else { 06900 user->writetimeout = value; 06901 } 06902 } else if (!strcasecmp(var->name, "eventfilter")) { 06903 const char *value = var->value; 06904 regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation"); 06905 if (new_filter) { 06906 int is_blackfilter; 06907 if (value[0] == '!') { 06908 is_blackfilter = 1; 06909 value++; 06910 } else { 06911 is_blackfilter = 0; 06912 } 06913 if (regcomp(new_filter, value, 0)) { 06914 ao2_t_ref(new_filter, -1, "failed to make regx"); 06915 } else { 06916 if (is_blackfilter) { 06917 ao2_t_link(user->blackfilters, new_filter, "link new filter into black user container"); 06918 } else { 06919 ao2_t_link(user->whitefilters, new_filter, "link new filter into white user container"); 06920 } 06921 } 06922 } 06923 } else { 06924 ast_debug(1, "%s is an unknown option.\n", var->name); 06925 } 06926 } 06927 ast_free_ha(oldha); 06928 } 06929 ast_config_destroy(cfg); 06930 06931 /* Perform cleanup - essentially prune out old users that no longer exist */ 06932 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) { 06933 if (user->keep) { /* valid record. clear flag for the next round */ 06934 user->keep = 0; 06935 06936 /* Calculate A1 for Digest auth */ 06937 snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret); 06938 ast_md5_hash(a1_hash,a1); 06939 if (user->a1_hash) { 06940 ast_free(user->a1_hash); 06941 } 06942 user->a1_hash = ast_strdup(a1_hash); 06943 continue; 06944 } 06945 /* We do not need to keep this user so take them out of the list */ 06946 AST_RWLIST_REMOVE_CURRENT(list); 06947 ast_debug(4, "Pruning user '%s'\n", user->username); 06948 /* Free their memory now */ 06949 if (user->a1_hash) { 06950 ast_free(user->a1_hash); 06951 } 06952 if (user->secret) { 06953 ast_free(user->secret); 06954 } 06955 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters"); 06956 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters"); 06957 ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one"); 06958 ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one"); 06959 ast_free_ha(user->ha); 06960 ast_free(user); 06961 } 06962 AST_RWLIST_TRAVERSE_SAFE_END; 06963 06964 AST_RWLIST_UNLOCK(&users); 06965 06966 if (!reload) { 06967 /* If you have a NULL hash fn, you only need a single bucket */ 06968 sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn); 06969 } 06970 06971 if (webmanager_enabled && manager_enabled) { 06972 if (!webregged) { 06973 06974 ast_http_uri_link(&rawmanuri); 06975 ast_http_uri_link(&manageruri); 06976 ast_http_uri_link(&managerxmluri); 06977 06978 ast_http_uri_link(&arawmanuri); 06979 ast_http_uri_link(&amanageruri); 06980 ast_http_uri_link(&amanagerxmluri); 06981 webregged = 1; 06982 } 06983 } else { 06984 if (webregged) { 06985 ast_http_uri_unlink(&rawmanuri); 06986 ast_http_uri_unlink(&manageruri); 06987 ast_http_uri_unlink(&managerxmluri); 06988 06989 ast_http_uri_unlink(&arawmanuri); 06990 ast_http_uri_unlink(&amanageruri); 06991 ast_http_uri_unlink(&amanagerxmluri); 06992 webregged = 0; 06993 } 06994 } 06995 06996 if (newhttptimeout > 0) { 06997 httptimeout = newhttptimeout; 06998 } 06999 07000 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled"); 07001 07002 ast_tcptls_server_start(&ami_desc); 07003 if (tls_was_enabled && !ami_tls_cfg.enabled) { 07004 ast_tcptls_server_stop(&amis_desc); 07005 } else if (ast_ssl_setup(amis_desc.tls_cfg)) { 07006 ast_tcptls_server_start(&amis_desc); 07007 } 07008 return 0; 07009 }
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 7032 of file manager.c.
References AST_LIST_INSERT_HEAD, mansession_session::datastores, manager_channel_variable::entry, and mansession::session.
07033 { 07034 AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry); 07035 07036 return 0; 07037 }
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 7044 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.
07045 { 07046 struct ast_datastore *datastore = NULL; 07047 07048 if (info == NULL) 07049 return NULL; 07050 07051 AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) { 07052 if (datastore->info != info) { 07053 continue; 07054 } 07055 07056 if (uid == NULL) { 07057 /* matched by type only */ 07058 break; 07059 } 07060 07061 if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) { 07062 /* Matched by type AND uid */ 07063 break; 07064 } 07065 } 07066 AST_LIST_TRAVERSE_SAFE_END; 07067 07068 return datastore; 07069 }
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 7039 of file manager.c.
References AST_LIST_REMOVE, mansession_session::datastores, manager_channel_variable::entry, and mansession::session.
07040 { 07041 return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1; 07042 }
int astman_is_authed | ( | uint32_t | ident | ) |
Determinie if a manager session ident is authenticated.
Definition at line 5463 of file manager.c.
References ao2_unlock, mansession_session::authenticated, find_session(), and unref_mansession().
Referenced by http_post_callback(), and static_callback().
05464 { 05465 int authed; 05466 struct mansession_session *session; 05467 05468 if (!(session = find_session(ident, 0))) 05469 return 0; 05470 05471 authed = (session->authenticated != 0); 05472 05473 ao2_unlock(session); 05474 unref_mansession(session); 05475 05476 return authed; 05477 }
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 5479 of file manager.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().
05480 { 05481 int result = 0; 05482 struct mansession_session *session; 05483 struct ao2_iterator i; 05484 05485 if (ident == 0) { 05486 return 0; 05487 } 05488 05489 i = ao2_iterator_init(sessions, 0); 05490 while ((session = ao2_iterator_next(&i))) { 05491 ao2_lock(session); 05492 if ((session->managerid == ident) && (session->readperm & perm)) { 05493 result = 1; 05494 ao2_unlock(session); 05495 unref_mansession(session); 05496 break; 05497 } 05498 ao2_unlock(session); 05499 unref_mansession(session); 05500 } 05501 ao2_iterator_destroy(&i); 05502 return result; 05503 }
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 5505 of file manager.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().
05506 { 05507 int result = 0; 05508 struct mansession_session *session; 05509 struct ao2_iterator i; 05510 05511 if (ident == 0) { 05512 return 0; 05513 } 05514 05515 i = ao2_iterator_init(sessions, 0); 05516 while ((session = ao2_iterator_next(&i))) { 05517 ao2_lock(session); 05518 if ((session->managerid == ident) && (session->writeperm & perm)) { 05519 result = 1; 05520 ao2_unlock(session); 05521 unref_mansession(session); 05522 break; 05523 } 05524 ao2_unlock(session); 05525 unref_mansession(session); 05526 } 05527 ao2_iterator_destroy(&i); 05528 return result; 05529 }
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 6019 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().
06025 { 06026 struct mansession_session *session = NULL; 06027 struct mansession s = { .session = NULL, .tcptls_session = ser }; 06028 struct ast_variable *v, *params = get_params; 06029 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */ 06030 struct ast_str *http_header = NULL, *out = NULL; 06031 size_t result_size = 512; 06032 struct message m = { 0 }; 06033 unsigned int idx; 06034 size_t hdrlen; 06035 06036 time_t time_now = time(NULL); 06037 unsigned long nonce = 0, nc; 06038 struct ast_http_digest d = { NULL, }; 06039 struct ast_manager_user *user = NULL; 06040 int stale = 0; 06041 char resp_hash[256]=""; 06042 /* Cache for user data */ 06043 char u_username[80]; 06044 int u_readperm; 06045 int u_writeperm; 06046 int u_writetimeout; 06047 int u_displayconnects; 06048 struct ast_sockaddr addr; 06049 06050 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) { 06051 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 06052 return -1; 06053 } 06054 06055 /* Find "Authorization: " header */ 06056 for (v = headers; v; v = v->next) { 06057 if (!strcasecmp(v->name, "Authorization")) { 06058 break; 06059 } 06060 } 06061 06062 if (!v || ast_strlen_zero(v->value)) { 06063 goto out_401; /* Authorization Header not present - send auth request */ 06064 } 06065 06066 /* Digest found - parse */ 06067 if (ast_string_field_init(&d, 128)) { 06068 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 06069 return -1; 06070 } 06071 06072 if (ast_parse_digest(v->value, &d, 0, 1)) { 06073 /* Error in Digest - send new one */ 06074 nonce = 0; 06075 goto out_401; 06076 } 06077 if (sscanf(d.nonce, "%30lx", &nonce) != 1) { 06078 ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce); 06079 nonce = 0; 06080 goto out_401; 06081 } 06082 06083 AST_RWLIST_WRLOCK(&users); 06084 user = get_manager_by_name_locked(d.username); 06085 if(!user) { 06086 AST_RWLIST_UNLOCK(&users); 06087 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username); 06088 nonce = 0; 06089 goto out_401; 06090 } 06091 06092 ast_sockaddr_from_sin(&addr, remote_address); 06093 /* --- We have User for this auth, now check ACL */ 06094 if (user->ha && !ast_apply_ha(user->ha, &addr)) { 06095 AST_RWLIST_UNLOCK(&users); 06096 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username); 06097 ast_http_error(ser, 403, "Permission denied", "Permission denied\n"); 06098 return -1; 06099 } 06100 06101 /* --- We have auth, so check it */ 06102 06103 /* compute the expected response to compare with what we received */ 06104 { 06105 char a2[256]; 06106 char a2_hash[256]; 06107 char resp[256]; 06108 06109 /* XXX Now request method are hardcoded in A2 */ 06110 snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri); 06111 ast_md5_hash(a2_hash, a2); 06112 06113 if (d.qop) { 06114 /* RFC 2617 */ 06115 snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash); 06116 } else { 06117 /* RFC 2069 */ 06118 snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash); 06119 } 06120 ast_md5_hash(resp_hash, resp); 06121 } 06122 06123 if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) { 06124 /* Something was wrong, so give the client to try with a new challenge */ 06125 AST_RWLIST_UNLOCK(&users); 06126 nonce = 0; 06127 goto out_401; 06128 } 06129 06130 /* 06131 * User are pass Digest authentication. 06132 * Now, cache the user data and unlock user list. 06133 */ 06134 ast_copy_string(u_username, user->username, sizeof(u_username)); 06135 u_readperm = user->readperm; 06136 u_writeperm = user->writeperm; 06137 u_displayconnects = user->displayconnects; 06138 u_writetimeout = user->writetimeout; 06139 AST_RWLIST_UNLOCK(&users); 06140 06141 if (!(session = find_session_by_nonce(d.username, nonce, &stale))) { 06142 /* 06143 * Create new session. 06144 * While it is not in the list we don't need any locking 06145 */ 06146 if (!(session = build_mansession(*remote_address))) { 06147 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 06148 return -1; 06149 } 06150 ao2_lock(session); 06151 06152 ast_copy_string(session->username, u_username, sizeof(session->username)); 06153 session->managerid = nonce; 06154 session->last_ev = grab_last(); 06155 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores); 06156 06157 session->readperm = u_readperm; 06158 session->writeperm = u_writeperm; 06159 session->writetimeout = u_writetimeout; 06160 06161 if (u_displayconnects) { 06162 ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 06163 } 06164 session->noncetime = session->sessionstart = time_now; 06165 session->authenticated = 1; 06166 } else if (stale) { 06167 /* 06168 * Session found, but nonce is stale. 06169 * 06170 * This could be because an old request (w/old nonce) arrived. 06171 * 06172 * This may be as the result of http proxy usage (separate delay or 06173 * multipath) or in a situation where a page was refreshed too quickly 06174 * (seen in Firefox). 06175 * 06176 * In this situation, we repeat the 401 auth with the current nonce 06177 * value. 06178 */ 06179 nonce = session->managerid; 06180 ao2_unlock(session); 06181 stale = 1; 06182 goto out_401; 06183 } else { 06184 sscanf(d.nc, "%30lx", &nc); 06185 if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) { 06186 /* 06187 * Nonce time expired (> 2 minutes) or something wrong with nonce 06188 * counter. 06189 * 06190 * Create new nonce key and resend Digest auth request. Old nonce 06191 * is saved for stale checking... 06192 */ 06193 session->nc = 0; /* Reset nonce counter */ 06194 session->oldnonce = session->managerid; 06195 nonce = session->managerid = ast_random(); 06196 session->noncetime = time_now; 06197 ao2_unlock(session); 06198 stale = 1; 06199 goto out_401; 06200 } else { 06201 session->nc = nc; /* All OK, save nonce counter */ 06202 } 06203 } 06204 06205 06206 /* Reset session timeout. */ 06207 session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5); 06208 ao2_unlock(session); 06209 06210 ast_mutex_init(&s.lock); 06211 s.session = session; 06212 s.fd = mkstemp(template); /* create a temporary file for command output */ 06213 unlink(template); 06214 if (s.fd <= -1) { 06215 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n"); 06216 goto auth_callback_out; 06217 } 06218 s.f = fdopen(s.fd, "w+"); 06219 if (!s.f) { 06220 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno)); 06221 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n"); 06222 close(s.fd); 06223 goto auth_callback_out; 06224 } 06225 06226 if (method == AST_HTTP_POST) { 06227 params = ast_http_get_post_vars(ser, headers); 06228 } 06229 06230 for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) { 06231 hdrlen = strlen(v->name) + strlen(v->value) + 3; 06232 m.headers[m.hdrcount] = ast_malloc(hdrlen); 06233 if (!m.headers[m.hdrcount]) { 06234 /* Allocation failure */ 06235 continue; 06236 } 06237 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value); 06238 ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]); 06239 ++m.hdrcount; 06240 } 06241 06242 if (process_message(&s, &m)) { 06243 if (u_displayconnects) { 06244 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 06245 } 06246 06247 session->needdestroy = 1; 06248 } 06249 06250 /* Free request headers. */ 06251 for (idx = 0; idx < m.hdrcount; ++idx) { 06252 ast_free((void *) m.headers[idx]); 06253 m.headers[idx] = NULL; 06254 } 06255 06256 if (s.f) { 06257 result_size = ftell(s.f); /* Calculate approx. size of result */ 06258 } 06259 06260 http_header = ast_str_create(80); 06261 out = ast_str_create(result_size * 2 + 512); 06262 06263 if (http_header == NULL || out == NULL) { 06264 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n"); 06265 goto auth_callback_out; 06266 } 06267 06268 ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]); 06269 06270 if (format == FORMAT_XML) { 06271 ast_str_append(&out, 0, "<ajax-response>\n"); 06272 } else if (format == FORMAT_HTML) { 06273 ast_str_append(&out, 0, 06274 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 06275 "<html><head>\r\n" 06276 "<title>Asterisk™ Manager Interface</title>\r\n" 06277 "</head><body style=\"background-color: #ffffff;\">\r\n" 06278 "<form method=\"POST\">\r\n" 06279 "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n" 06280 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n" 06281 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>" 06282 "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n"); 06283 } 06284 06285 process_output(&s, &out, params, format); 06286 06287 if (format == FORMAT_XML) { 06288 ast_str_append(&out, 0, "</ajax-response>\n"); 06289 } else if (format == FORMAT_HTML) { 06290 ast_str_append(&out, 0, "</table></form></body></html>\r\n"); 06291 } 06292 06293 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0); 06294 http_header = out = NULL; 06295 06296 auth_callback_out: 06297 ast_mutex_destroy(&s.lock); 06298 06299 /* Clear resources and unlock manager session */ 06300 if (method == AST_HTTP_POST && params) { 06301 ast_variables_destroy(params); 06302 } 06303 06304 ast_free(http_header); 06305 ast_free(out); 06306 06307 ao2_lock(session); 06308 if (session->f) { 06309 fclose(session->f); 06310 } 06311 session->f = NULL; 06312 session->fd = -1; 06313 ao2_unlock(session); 06314 06315 if (session->needdestroy) { 06316 ast_debug(1, "Need destroy, doing it now!\n"); 06317 session_destroy(session); 06318 } 06319 ast_string_field_free_memory(&d); 06320 return 0; 06321 06322 out_401: 06323 if (!nonce) { 06324 nonce = ast_random(); 06325 } 06326 06327 ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL); 06328 ast_string_field_free_memory(&d); 06329 return 0; 06330 }
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 6391 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.
06392 { 06393 int retval; 06394 struct sockaddr_in ser_remote_address_tmp; 06395 06396 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06397 retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers); 06398 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06399 return retval; 06400 }
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 6402 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.
06403 { 06404 int retval; 06405 struct sockaddr_in ser_remote_address_tmp; 06406 06407 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06408 retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers); 06409 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06410 return retval; 06411 }
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 6413 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.
06414 { 06415 int retval; 06416 struct sockaddr_in ser_remote_address_tmp; 06417 06418 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06419 retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers); 06420 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06421 return retval; 06422 }
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 5404 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().
05405 { 05406 struct mansession_session *session; 05407 struct ao2_iterator i; 05408 05409 if (ident == 0) { 05410 return NULL; 05411 } 05412 05413 i = ao2_iterator_init(sessions, 0); 05414 while ((session = ao2_iterator_next(&i))) { 05415 ao2_lock(session); 05416 if (session->managerid == ident && !session->needdestroy) { 05417 ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0); 05418 break; 05419 } 05420 ao2_unlock(session); 05421 unref_mansession(session); 05422 } 05423 ao2_iterator_destroy(&i); 05424 05425 return session; 05426 }
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 5437 of file manager.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().
05438 { 05439 struct mansession_session *session; 05440 struct ao2_iterator i; 05441 05442 if (nonce == 0 || username == NULL || stale == NULL) { 05443 return NULL; 05444 } 05445 05446 i = ao2_iterator_init(sessions, 0); 05447 while ((session = ao2_iterator_next(&i))) { 05448 ao2_lock(session); 05449 if (!strcasecmp(session->username, username) && session->managerid == nonce) { 05450 *stale = 0; 05451 break; 05452 } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) { 05453 *stale = 1; 05454 break; 05455 } 05456 ao2_unlock(session); 05457 unref_mansession(session); 05458 } 05459 ao2_iterator_destroy(&i); 05460 return session; 05461 }
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 5804 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().
05810 { 05811 struct mansession s = { .session = NULL, .tcptls_session = ser }; 05812 struct mansession_session *session = NULL; 05813 uint32_t ident = 0; 05814 int blastaway = 0; 05815 struct ast_variable *v, *cookies, *params = get_params; 05816 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */ 05817 struct ast_str *http_header = NULL, *out = NULL; 05818 struct message m = { 0 }; 05819 unsigned int idx; 05820 size_t hdrlen; 05821 05822 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) { 05823 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 05824 return -1; 05825 } 05826 05827 cookies = ast_http_get_cookies(headers); 05828 for (v = cookies; v; v = v->next) { 05829 if (!strcasecmp(v->name, "mansession_id")) { 05830 sscanf(v->value, "%30x", &ident); 05831 break; 05832 } 05833 } 05834 if (cookies) { 05835 ast_variables_destroy(cookies); 05836 } 05837 05838 if (!(session = find_session(ident, 1))) { 05839 05840 /**/ 05841 /* Create new session. 05842 * While it is not in the list we don't need any locking 05843 */ 05844 if (!(session = build_mansession(*remote_address))) { 05845 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 05846 return -1; 05847 } 05848 ao2_lock(session); 05849 session->sin = *remote_address; 05850 session->fd = -1; 05851 session->waiting_thread = AST_PTHREADT_NULL; 05852 session->send_events = 0; 05853 session->inuse = 1; 05854 /*!\note There is approximately a 1 in 1.8E19 chance that the following 05855 * calculation will produce 0, which is an invalid ID, but due to the 05856 * properties of the rand() function (and the constantcy of s), that 05857 * won't happen twice in a row. 05858 */ 05859 while ((session->managerid = ast_random() ^ (unsigned long) session) == 0); 05860 session->last_ev = grab_last(); 05861 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores); 05862 } 05863 ao2_unlock(session); 05864 05865 http_header = ast_str_create(128); 05866 out = ast_str_create(2048); 05867 05868 ast_mutex_init(&s.lock); 05869 05870 if (http_header == NULL || out == NULL) { 05871 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n"); 05872 goto generic_callback_out; 05873 } 05874 05875 s.session = session; 05876 s.fd = mkstemp(template); /* create a temporary file for command output */ 05877 unlink(template); 05878 if (s.fd <= -1) { 05879 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n"); 05880 goto generic_callback_out; 05881 } 05882 s.f = fdopen(s.fd, "w+"); 05883 if (!s.f) { 05884 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno)); 05885 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n"); 05886 close(s.fd); 05887 goto generic_callback_out; 05888 } 05889 05890 if (method == AST_HTTP_POST) { 05891 params = ast_http_get_post_vars(ser, headers); 05892 } 05893 05894 for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) { 05895 hdrlen = strlen(v->name) + strlen(v->value) + 3; 05896 m.headers[m.hdrcount] = ast_malloc(hdrlen); 05897 if (!m.headers[m.hdrcount]) { 05898 /* Allocation failure */ 05899 continue; 05900 } 05901 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value); 05902 ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]); 05903 ++m.hdrcount; 05904 } 05905 05906 if (process_message(&s, &m)) { 05907 if (session->authenticated) { 05908 if (manager_displayconnects(session)) { 05909 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 05910 } 05911 } else { 05912 if (displayconnects) { 05913 ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr)); 05914 } 05915 } 05916 session->needdestroy = 1; 05917 } 05918 05919 /* Free request headers. */ 05920 for (idx = 0; idx < m.hdrcount; ++idx) { 05921 ast_free((void *) m.headers[idx]); 05922 m.headers[idx] = NULL; 05923 } 05924 05925 ast_str_append(&http_header, 0, 05926 "Content-type: text/%s\r\n" 05927 "Cache-Control: no-cache;\r\n" 05928 "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n" 05929 "Pragma: SuppressEvents\r\n", 05930 contenttype[format], 05931 session->managerid, httptimeout); 05932 05933 if (format == FORMAT_XML) { 05934 ast_str_append(&out, 0, "<ajax-response>\n"); 05935 } else if (format == FORMAT_HTML) { 05936 /* 05937 * When handling AMI-over-HTTP in HTML format, we provide a simple form for 05938 * debugging purposes. This HTML code should not be here, we 05939 * should read from some config file... 05940 */ 05941 05942 #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n" 05943 #define TEST_STRING \ 05944 "<form action=\"manager\" method=\"post\">\n\ 05945 Action: <select name=\"action\">\n\ 05946 <option value=\"\">-----></option>\n\ 05947 <option value=\"login\">login</option>\n\ 05948 <option value=\"command\">Command</option>\n\ 05949 <option value=\"waitevent\">waitevent</option>\n\ 05950 <option value=\"listcommands\">listcommands</option>\n\ 05951 </select>\n\ 05952 or <input name=\"action\"><br/>\n\ 05953 CLI Command <input name=\"command\"><br>\n\ 05954 user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\ 05955 <input type=\"submit\">\n</form>\n" 05956 05957 ast_str_append(&out, 0, "<title>Asterisk™ Manager Interface</title>"); 05958 ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n"); 05959 ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>"); 05960 ast_str_append(&out, 0, ROW_FMT, TEST_STRING); 05961 } 05962 05963 process_output(&s, &out, params, format); 05964 05965 if (format == FORMAT_XML) { 05966 ast_str_append(&out, 0, "</ajax-response>\n"); 05967 } else if (format == FORMAT_HTML) { 05968 ast_str_append(&out, 0, "</table></body>\r\n"); 05969 } 05970 05971 ao2_lock(session); 05972 /* Reset HTTP timeout. If we're not authenticated, keep it extremely short */ 05973 session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5); 05974 05975 if (session->needdestroy) { 05976 if (session->inuse == 1) { 05977 ast_debug(1, "Need destroy, doing it now!\n"); 05978 blastaway = 1; 05979 } else { 05980 ast_debug(1, "Need destroy, but can't do it yet!\n"); 05981 if (session->waiting_thread != AST_PTHREADT_NULL) { 05982 pthread_kill(session->waiting_thread, SIGURG); 05983 } 05984 session->inuse--; 05985 } 05986 } else { 05987 session->inuse--; 05988 } 05989 ao2_unlock(session); 05990 05991 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0); 05992 http_header = out = NULL; 05993 05994 generic_callback_out: 05995 ast_mutex_destroy(&s.lock); 05996 05997 /* Clear resource */ 05998 05999 if (method == AST_HTTP_POST && params) { 06000 ast_variables_destroy(params); 06001 } 06002 if (http_header) { 06003 ast_free(http_header); 06004 } 06005 if (out) { 06006 ast_free(out); 06007 } 06008 06009 if (session && blastaway) { 06010 session_destroy(session); 06011 } else if (session && session->f) { 06012 fclose(session->f); 06013 session->f = NULL; 06014 } 06015 06016 return 0; 06017 }
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 6486 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.
06487 { 06488 switch (cmd) { 06489 case CLI_INIT: 06490 e->command = "manager show settings"; 06491 e->usage = 06492 "Usage: manager show settings\n" 06493 " Provides detailed list of the configuration of the Manager.\n"; 06494 return NULL; 06495 case CLI_GENERATE: 06496 return NULL; 06497 } 06498 #define FORMAT " %-25.25s %-15.15s\n" 06499 #define FORMAT2 " %-25.25s %-15d\n" 06500 if (a->argc != 3) { 06501 return CLI_SHOWUSAGE; 06502 } 06503 ast_cli(a->fd, "\nGlobal Settings:\n"); 06504 ast_cli(a->fd, "----------------\n"); 06505 ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled)); 06506 ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled)); 06507 ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled"); 06508 ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout); 06509 ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled)); 06510 ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled"); 06511 ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile); 06512 ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile); 06513 ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher); 06514 ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin)); 06515 ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects)); 06516 ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents)); 06517 ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, "")); 06518 ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug)); 06519 ast_cli(a->fd, FORMAT, "Block sockets:", AST_CLI_YESNO(block_sockets)); 06520 #undef FORMAT 06521 #undef FORMAT2 06522 06523 return CLI_SUCCESS; 06524 }
int init_manager | ( | void | ) |
Called by Asterisk initialization.
Definition at line 7022 of file manager.c.
References __init_manager().
Referenced by main().
07023 { 07024 return __init_manager(0); 07025 }
static void load_channelvars | ( | struct ast_variable * | var | ) | [static] |
Definition at line 6546 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.
06547 { 06548 struct manager_channel_variable *mcv; 06549 char *remaining = ast_strdupa(var->value); 06550 char *next; 06551 06552 ast_free(manager_channelvars); 06553 manager_channelvars = ast_strdup(var->value); 06554 06555 /* 06556 * XXX TODO: To allow dialplan functions to have more than one 06557 * parameter requires eliminating the '|' as a separator so we 06558 * could use AST_STANDARD_APP_ARGS() to separate items. 06559 */ 06560 free_channelvars(); 06561 AST_RWLIST_WRLOCK(&channelvars); 06562 while ((next = strsep(&remaining, ",|"))) { 06563 if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) { 06564 break; 06565 } 06566 strcpy(mcv->name, next); /* SAFE */ 06567 if (strchr(next, '(')) { 06568 mcv->isfunc = 1; 06569 } 06570 AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry); 06571 } 06572 AST_RWLIST_UNLOCK(&channelvars); 06573 }
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 6332 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.
06333 { 06334 int retval; 06335 struct sockaddr_in ser_remote_address_tmp; 06336 06337 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06338 retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers); 06339 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06340 return retval; 06341 }
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 6343 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.
06344 { 06345 int retval; 06346 struct sockaddr_in ser_remote_address_tmp; 06347 06348 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06349 retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers); 06350 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06351 return retval; 06352 }
static void process_output | ( | struct mansession * | s, | |
struct ast_str ** | out, | |||
struct ast_variable * | params, | |||
enum output_format | format | |||
) | [static] |
Definition at line 5761 of file manager.c.
References ast_log(), ast_str_append(), errno, mansession::f, mansession::fd, FORMAT_HTML, FORMAT_XML, LOG_ERROR, LOG_WARNING, and xml_translate().
05762 { 05763 char *buf; 05764 size_t l; 05765 05766 if (!s->f) 05767 return; 05768 05769 /* Ensure buffer is NULL-terminated */ 05770 fprintf(s->f, "%c", 0); 05771 fflush(s->f); 05772 05773 if ((l = ftell(s->f)) > 0) { 05774 if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) { 05775 ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n"); 05776 } else { 05777 if (format == FORMAT_XML || format == FORMAT_HTML) { 05778 xml_translate(out, buf, params, format); 05779 } else { 05780 ast_str_append(out, 0, "%s", buf); 05781 } 05782 munmap(buf, l); 05783 } 05784 } else if (format == FORMAT_XML || format == FORMAT_HTML) { 05785 xml_translate(out, "", params, format); 05786 } 05787 05788 if (s->f) { 05789 if (fclose(s->f)) { 05790 ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); 05791 } 05792 s->f = NULL; 05793 s->fd = -1; 05794 } else if (s->fd != -1) { 05795 if (close(s->fd)) { 05796 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 05797 } 05798 s->fd = -1; 05799 } else { 05800 ast_log(LOG_ERROR, "process output attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n"); 05801 } 05802 }
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 6457 of file manager.c.
References purge_events(), and purge_sessions().
06458 { 06459 purge_sessions(1); 06460 purge_events(); 06461 }
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 6354 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.
06355 { 06356 int retval; 06357 struct sockaddr_in ser_remote_address_tmp; 06358 06359 ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); 06360 retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers); 06361 ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); 06362 return retval; 06363 }
int reload_manager | ( | void | ) |
Called by Asterisk module functions and the CLI command.
Definition at line 7027 of file manager.c.
References __init_manager().
Referenced by handle_manager_reload().
07028 { 07029 return __init_manager(1); 07030 }
static int variable_count_cmp_fn | ( | void * | obj, | |
void * | vstr, | |||
int | flags | |||
) | [static] |
Definition at line 5605 of file manager.c.
References CMP_MATCH, CMP_STOP, str, and variable_count::varname.
05606 { 05607 /* Due to the simplicity of struct variable_count, it makes no difference 05608 * if you pass in objects or strings, the same operation applies. This is 05609 * due to the fact that the hash occurs on the first element, which means 05610 * the address of both the struct and the string are exactly the same. */ 05611 struct variable_count *vc = obj; 05612 char *str = vstr; 05613 return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0; 05614 }
static int variable_count_hash_fn | ( | const void * | vvc, | |
const int | flags | |||
) | [static] |
Definition at line 5598 of file manager.c.
References ast_str_hash(), and variable_count::varname.
05599 { 05600 const struct variable_count *vc = vvc; 05601 05602 return ast_str_hash(vc->varname); 05603 }
static void xml_copy_escape | ( | struct ast_str ** | out, | |
const char * | src, | |||
int | mode | |||
) | [static] |
Definition at line 5536 of file manager.c.
References ast_str_append().
05537 { 05538 /* store in a local buffer to avoid calling ast_str_append too often */ 05539 char buf[256]; 05540 char *dst = buf; 05541 int space = sizeof(buf); 05542 /* repeat until done and nothing to flush */ 05543 for ( ; *src || dst != buf ; src++) { 05544 if (*src == '\0' || space < 10) { /* flush */ 05545 *dst++ = '\0'; 05546 ast_str_append(out, 0, "%s", buf); 05547 dst = buf; 05548 space = sizeof(buf); 05549 if (*src == '\0') { 05550 break; 05551 } 05552 } 05553 05554 if ( (mode & 2) && !isalnum(*src)) { 05555 *dst++ = '_'; 05556 space--; 05557 continue; 05558 } 05559 switch (*src) { 05560 case '<': 05561 strcpy(dst, "<"); 05562 dst += 4; 05563 space -= 4; 05564 break; 05565 case '>': 05566 strcpy(dst, ">"); 05567 dst += 4; 05568 space -= 4; 05569 break; 05570 case '\"': 05571 strcpy(dst, """); 05572 dst += 6; 05573 space -= 6; 05574 break; 05575 case '\'': 05576 strcpy(dst, "'"); 05577 dst += 6; 05578 space -= 6; 05579 break; 05580 case '&': 05581 strcpy(dst, "&"); 05582 dst += 5; 05583 space -= 5; 05584 break; 05585 05586 default: 05587 *dst++ = mode ? tolower(*src) : *src; 05588 space--; 05589 } 05590 } 05591 }
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 5644 of file manager.c.
References FORMAT_XML, ast_variable::name, ast_variable::next, ast_variable::value, and var.
Referenced by process_output().
05645 { 05646 struct ast_variable *v; 05647 const char *dest = NULL; 05648 char *var, *val; 05649 const char *objtype = NULL; 05650 int in_data = 0; /* parsing data */ 05651 int inobj = 0; 05652 int xml = (format == FORMAT_XML); 05653 struct variable_count *vc = NULL; 05654 struct ao2_container *vco = NULL; 05655 05656 if (xml) { 05657 /* dest and objtype need only for XML format */ 05658 for (v = get_vars; v; v = v->next) { 05659 if (!strcasecmp(v->name, "ajaxdest")) { 05660 dest = v->value; 05661 } else if (!strcasecmp(v->name, "ajaxobjtype")) { 05662 objtype = v->value; 05663 } 05664 } 05665 if (ast_strlen_zero(dest)) { 05666 dest = "unknown"; 05667 } 05668 if (ast_strlen_zero(objtype)) { 05669 objtype = "generic"; 05670 } 05671 } 05672 05673 /* we want to stop when we find an empty line */ 05674 while (in && *in) { 05675 val = strsep(&in, "\r\n"); /* mark start and end of line */ 05676 if (in && *in == '\n') { /* remove trailing \n if any */ 05677 in++; 05678 } 05679 ast_trim_blanks(val); 05680 ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val); 05681 if (ast_strlen_zero(val)) { 05682 /* empty line */ 05683 if (in_data) { 05684 /* close data in Opaque mode */ 05685 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n"); 05686 in_data = 0; 05687 } 05688 05689 if (inobj) { 05690 /* close block */ 05691 ast_str_append(out, 0, xml ? " /></response>\n" : 05692 "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 05693 inobj = 0; 05694 ao2_ref(vco, -1); 05695 vco = NULL; 05696 } 05697 continue; 05698 } 05699 05700 if (!inobj) { 05701 /* start new block */ 05702 if (xml) { 05703 ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype); 05704 } 05705 vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn); 05706 inobj = 1; 05707 } 05708 05709 if (in_data) { 05710 /* Process data field in Opaque mode. This is a 05711 * followup, so we re-add line feeds. */ 05712 ast_str_append(out, 0, xml ? "\n" : "<br>\n"); 05713 xml_copy_escape(out, val, 0); /* data field */ 05714 continue; 05715 } 05716 05717 /* We expect "Name: value" line here */ 05718 var = strsep(&val, ":"); 05719 if (val) { 05720 /* found the field name */ 05721 val = ast_skip_blanks(val); 05722 ast_trim_blanks(var); 05723 } else { 05724 /* field name not found, switch to opaque mode */ 05725 val = var; 05726 var = "Opaque-data"; 05727 in_data = 1; 05728 } 05729 05730 05731 ast_str_append(out, 0, xml ? " " : "<tr><td>"); 05732 if ((vc = ao2_find(vco, var, 0))) { 05733 vc->count++; 05734 } else { 05735 /* Create a new entry for this one */ 05736 vc = ao2_alloc(sizeof(*vc), NULL); 05737 vc->varname = var; 05738 vc->count = 1; 05739 ao2_link(vco, vc); 05740 } 05741 05742 xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */ 05743 if (vc->count > 1) { 05744 ast_str_append(out, 0, "-%d", vc->count); 05745 } 05746 ao2_ref(vc, -1); 05747 ast_str_append(out, 0, xml ? "='" : "</td><td>"); 05748 xml_copy_escape(out, val, 0); /* data field */ 05749 if (!in_data || !*in) { 05750 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n"); 05751 } 05752 } 05753 05754 if (inobj) { 05755 ast_str_append(out, 0, xml ? " /></response>\n" : 05756 "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 05757 ao2_ref(vco, -1); 05758 } 05759 }
struct ast_http_uri amanageruri [static] |
struct ast_http_uri amanagerxmluri [static] |
struct ast_tcptls_session_args ami_desc [static] |
Definition at line 6464 of file manager.c.
Referenced by __init_manager(), and handle_manager_show_settings().
struct ast_tls_config ami_tls_cfg [static] |
Definition at line 6463 of file manager.c.
Referenced by __init_manager(), and handle_manager_show_settings().
struct ast_tcptls_session_args amis_desc [static] |
Definition at line 6475 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] |