#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 "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"

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 | eventqent |
| struct | fast_originate_helper |
| helper function for originate More... | |
| 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 | 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 | NEW_EVENT(m) (AST_LIST_NEXT(m->session->last_ev, eq_next)) |
| #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 | |
| static const char * | __astman_get_header (const struct message *m, char *var, int mode) |
| static void | __fini_actions (void) |
| static void | __fini_manager_hooks (void) |
| static void | __fini_users (void) |
| static void | __init_actions (void) |
| 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_hooks (void) |
| static void | __init_userevent_buf (void) |
| static void | __init_users (void) |
| int | __manager_event (int category, const char *event, const char *file, int line, const char *func, const char *fmt,...) |
| manager_event: Send AMI event to client | |
| static int | action_atxfer (struct mansession *s, const struct message *m) |
| static int | action_challenge (struct mansession *s, const struct message *m) |
| static int | action_command (struct mansession *s, const struct message *m) |
| Manager command "command" - execute CLI command. | |
| static int | action_coresettings (struct mansession *s, const struct message *m) |
| Show PBX core settings information. | |
| static int | action_coreshowchannels (struct mansession *s, const struct message *m) |
| Manager command "CoreShowChannels" - List currently defined channels and some information about them. | |
| static int | action_corestatus (struct mansession *s, const struct message *m) |
| Show PBX core status information. | |
| static int | action_createconfig (struct mansession *s, const struct message *m) |
| static int | action_events (struct mansession *s, const struct message *m) |
| static int | action_extensionstate (struct mansession *s, const struct message *m) |
| static int | action_getconfig (struct mansession *s, const struct message *m) |
| static int | action_getconfigjson (struct mansession *s, const struct message *m) |
| static int | action_getvar (struct mansession *s, const struct message *m) |
| static int | action_hangup (struct mansession *s, const struct message *m) |
| static int | action_listcategories (struct mansession *s, const struct message *m) |
| static int | action_listcommands (struct mansession *s, const struct message *m) |
| static int | action_login (struct mansession *s, const struct message *m) |
| static int | action_logoff (struct mansession *s, const struct message *m) |
| static int | action_mailboxcount (struct mansession *s, const struct message *m) |
| static int | action_mailboxstatus (struct mansession *s, const struct message *m) |
| static int | action_originate (struct mansession *s, const struct message *m) |
| static int | action_ping (struct mansession *s, const struct message *m) |
| static int | action_redirect (struct mansession *s, const struct message *m) |
| action_redirect: The redirect manager command | |
| static int | action_reload (struct mansession *s, const struct message *m) |
| Send a reload event. | |
| static int | action_sendtext (struct mansession *s, const struct message *m) |
| static int | action_setvar (struct mansession *s, const struct message *m) |
| static int | action_status (struct mansession *s, const struct message *m) |
| Manager "status" command to show channels. | |
| static int | action_timeout (struct mansession *s, const struct message *m) |
| static int | action_updateconfig (struct mansession *s, const struct message *m) |
| static int | action_userevent (struct mansession *s, const struct message *m) |
| static int | action_waitevent (struct mansession *s, const struct message *m) |
| static int | append_event (const char *str, int category) |
| 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 new command with manager, including online help. This is the preferred way to register a manager command | |
| void | ast_manager_register_hook (struct manager_custom_hook *hook) |
| Add a custom hook to be called when an event is fired. | |
| static int | ast_manager_register_struct (struct manager_action *act) |
| int | ast_manager_unregister (char *action) |
| Unregister a registered manager command. | |
| void | ast_manager_unregister_hook (struct manager_custom_hook *hook) |
| Delete a custom hook to be called when an event is fired. | |
| void | astman_append (struct mansession *s, const char *fmt,...) |
| int | astman_datastore_add (struct mansession *s, struct ast_datastore *datastore) |
| Add a datastore to a session. | |
| struct ast_datastore * | astman_datastore_find (struct mansession *s, const struct ast_datastore_info *info, const char *uid) |
| Find a datastore on a session. | |
| int | astman_datastore_remove (struct mansession *s, struct ast_datastore *datastore) |
| Remove a datastore from a session. | |
| const char * | astman_get_header (const struct message *m, char *var) |
| Get header from mananger transaction. | |
| struct ast_variable * | astman_get_variables (const struct message *m) |
| Get a linked list of the Variable: headers. | |
| int | astman_is_authed (uint32_t ident) |
| Determinie if a manager session ident is authenticated. | |
| void | astman_send_ack (struct mansession *s, const struct message *m, char *msg) |
| Send ack in manager transaction. | |
| void | astman_send_error (struct mansession *s, const struct message *m, char *error) |
| Send error in manager transaction. | |
| void | astman_send_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 struct mansession_session * | build_mansession (struct sockaddr_in sin) |
| Allocate manager session structure and add it to the list of sessions. | |
| static int | check_blacklist (const char *cmd) |
| int | check_manager_enabled () |
| Check if AMI is enabled. | |
| static int | check_manager_session_inuse (const char *name) |
| int | check_webmanager_enabled () |
| Check if AMI/HTTP is enabled. | |
| static int | do_message (struct mansession *s) |
| static void * | 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 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_mandebug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_showmanager (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_showmanagers (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_showmancmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_showmancmds (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| CLI command manager list commands. | |
| static char * | handle_showmanconn (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| CLI command manager list connected. | |
| static char * | handle_showmaneventq (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| CLI command manager list eventq. | |
| static enum error_type | handle_updates (struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn) |
| int | init_manager (void) |
| Called by Asterisk initialization. | |
| static void | json_escape (char *out, const char *in) |
| static int | manager_displayconnects (struct mansession_session *session) |
| Get displayconnects config option. | |
| static int | manager_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) |
| static int | manager_modulecheck (struct mansession *s, const struct message *m) |
| static int | manager_moduleload (struct mansession *s, const struct message *m) |
| static int | manager_state_cb (char *context, char *exten, int state, void *data) |
| static int | mansession_cmp_fn (void *obj, void *arg, int flags) |
| static struct sockaddr_in * | mansession_encode_sin_local (const struct mansession *s, struct sockaddr_in *sin_local) |
| static enum ast_security_event_transport_type | mansession_get_transport (const struct mansession *s) |
| static void | mansession_lock (struct mansession *s) |
| Lock the 'mansession' structure. | |
| static void | mansession_unlock (struct mansession *s) |
| Unlock the 'mansession' structure. | |
| static int | mxml_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) |
| static int | process_events (struct mansession *s) |
| static int | process_message (struct mansession *s, const struct message *m) |
| static void | purge_events (void) |
| static void | purge_old_stuff (void *data) |
| cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most | |
| static void | purge_sessions (int n_max) |
| remove at most n_max stale session from the list. | |
| static int | rawman_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) |
| static void | ref_event (struct eventqent *e) |
| 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 eventqent * | unref_event (struct eventqent *e) |
| 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 void | xml_copy_escape (struct ast_str **out, const char *src, int mode) |
| static void | xml_translate (struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format) |
| Convert the input into XML or HTML. The input is supposed to be a sequence of lines of the form Name: value optionally followed by a blob of unformatted text. A blank line is a section separator. Basically, this is a mixture of the format of Manager Interface and CLI commands. The unformatted text is considered as a single value of a field named 'Opaque-data'. | |
Variables | |
| static int | allowmultiplelogin = 1 |
| static struct ast_http_uri | amanageruri |
| static struct ast_http_uri | amanagerxmluri |
| static struct ast_tcptls_session_args | ami_desc |
| static struct ast_tls_config | ami_tls_cfg |
| static struct ast_tcptls_session_args | amis_desc |
| static struct ast_http_uri | arawmanuri |
| static struct ast_threadstorage | astman_append_buf = { .once = PTHREAD_ONCE_INIT, .key_init = __init_astman_append_buf , .custom_init = NULL , } |
| static int | block_sockets |
| static struct ast_cli_entry | cli_manager [] |
| struct { | |
| const char * words [AST_MAX_CMD_LEN] | |
| } | command_blacklist [] |
| static const char *const | contenttype [] |
| static int | displayconnects = 1 |
| static char | global_realm [MAXHOSTNAMELEN] |
| static int | httptimeout = 60 |
| static int | manager_debug |
| static int | manager_enabled = 0 |
| static struct ast_threadstorage | manager_event_buf = { .once = PTHREAD_ONCE_INIT, .key_init = __init_manager_event_buf , .custom_init = NULL , } |
| static struct ast_http_uri | manageruri |
| static struct ast_http_uri | managerxmluri |
| static struct permalias | perms [] |
| static struct ast_http_uri | rawmanuri |
| static int | registered = 0 |
| static struct ao2_container * | sessions = NULL |
| static int | timestampevents |
| static struct ast_threadstorage | userevent_buf = { .once = PTHREAD_ONCE_INIT, .key_init = __init_userevent_buf , .custom_init = NULL , } |
| static int | webmanager_enabled = 0 |
| static int | webregged = 0 |
Definition in file manager.c.
| #define 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" |
Referenced by generic_http_callback().
| #define TEST_STRING "<form action=\"manager\" method=\"post\">\n\ Action: <select name=\"action\">\n\ <option value=\"\">-----></option>\n\ <option value=\"login\">login</option>\n\ <option value=\"command\">Command</option>\n\ <option value=\"waitevent\">waitevent</option>\n\ <option value=\"listcommands\">listcommands</option>\n\ </select>\n\ or <input name=\"action\"><br/>\n\ CLI Command <input name=\"command\"><br>\n\ user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\ <input type=\"submit\">\n</form>\n" |
Referenced by generic_http_callback().
| enum output_format |
END Doxygen group
Definition at line 4363 of file manager.c.
04363 { 04364 FORMAT_RAW, 04365 FORMAT_HTML, 04366 FORMAT_XML, 04367 };
| static int __init_manager | ( | int | reload | ) | [static] |
Definition at line 5396 of file manager.c.
References ast_manager_user::a1_hash, 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(), amanageruri, amanagerxmluri, ami_desc, ami_tls_cfg, amis_desc, ao2_container_alloc, append_event(), arawmanuri, ARRAY_LEN, ast_append_ha(), ast_calloc, ast_category_browse(), AST_CERTFILE, ast_cli_register_multiple(), ast_config_AST_SYSTEM_NAME, ast_config_destroy(), ast_config_load2(), ast_copy_string(), ast_debug, ast_extension_state_add(), ast_free, ast_free_ha(), ast_http_uri_link(), ast_http_uri_unlink(), AST_LIST_INSERT_TAIL, ast_log(), ast_manager_register_xml, ast_md5_hash(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_ssl_setup(), ast_strdup, ast_strlen_zero(), ast_tcptls_server_start(), ast_tls_read_conf(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), block_sockets, ast_tls_config::certfile, ast_tls_config::cipher, cli_manager, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_MANAGER_PORT, DEFAULT_REALM, ast_manager_user::displayconnects, ast_tls_config::enabled, EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, EVENT_FLAG_CONFIG, EVENT_FLAG_ORIGINATE, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, get_manager_by_name_locked(), get_perm(), global_realm, ast_manager_user::ha, inet_aton(), ast_manager_user::keep, ast_variable::lineno, ast_tcptls_session_args::local_address, LOG_NOTICE, LOG_WARNING, manager_debug, manager_event, manager_modulecheck(), manager_moduleload(), manager_state_cb(), manageruri, managerxmluri, mansession_cmp_fn(), ast_variable::name, ast_variable::next, ast_tls_config::pvtfile, rawmanuri, ast_manager_user::readperm, registered, S_OR, ast_manager_user::secret, ast_tcptls_session_args::tls_cfg, ast_manager_user::username, value, ast_variable::value, var, webregged, ast_manager_user::writeperm, and ast_manager_user::writetimeout.
Referenced by init_manager(), and reload_manager().
05397 { 05398 struct ast_config *ucfg = NULL, *cfg = NULL; 05399 const char *val; 05400 char *cat = NULL; 05401 int newhttptimeout = 60; 05402 struct ast_manager_user *user = NULL; 05403 struct ast_variable *var; 05404 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 05405 char a1[256]; 05406 char a1_hash[256]; 05407 05408 manager_enabled = 0; 05409 05410 if (!registered) { 05411 /* Register default actions */ 05412 ast_manager_register_xml("Ping", 0, action_ping); 05413 ast_manager_register_xml("Events", 0, action_events); 05414 ast_manager_register_xml("Logoff", 0, action_logoff); 05415 ast_manager_register_xml("Login", 0, action_login); 05416 ast_manager_register_xml("Challenge", 0, action_challenge); 05417 ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup); 05418 ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status); 05419 ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar); 05420 ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar); 05421 ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig); 05422 ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson); 05423 ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig); 05424 ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig); 05425 ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories); 05426 ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect); 05427 ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer); 05428 ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate); 05429 ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command); 05430 ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate); 05431 ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout); 05432 ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus); 05433 ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount); 05434 ast_manager_register_xml("ListCommands", 0, action_listcommands); 05435 ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext); 05436 ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent); 05437 ast_manager_register_xml("WaitEvent", 0, action_waitevent); 05438 ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings); 05439 ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus); 05440 ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload); 05441 ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels); 05442 ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload); 05443 ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck); 05444 05445 ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager)); 05446 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL); 05447 registered = 1; 05448 /* Append placeholder event so master_eventq never runs dry */ 05449 append_event("Event: Placeholder\r\n\r\n", 0); 05450 } 05451 if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) { 05452 return 0; 05453 } 05454 05455 displayconnects = 1; 05456 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { 05457 ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled.\n"); 05458 return 0; 05459 } 05460 05461 /* default values */ 05462 ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm)); 05463 memset(&ami_desc.local_address, 0, sizeof(struct sockaddr_in)); 05464 memset(&amis_desc.local_address, 0, sizeof(amis_desc.local_address)); 05465 amis_desc.local_address.sin_port = htons(5039); 05466 ami_desc.local_address.sin_port = htons(DEFAULT_MANAGER_PORT); 05467 05468 ami_tls_cfg.enabled = 0; 05469 if (ami_tls_cfg.certfile) { 05470 ast_free(ami_tls_cfg.certfile); 05471 } 05472 ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE); 05473 if (ami_tls_cfg.pvtfile) { 05474 ast_free(ami_tls_cfg.pvtfile); 05475 } 05476 ami_tls_cfg.pvtfile = ast_strdup(""); 05477 if (ami_tls_cfg.cipher) { 05478 ast_free(ami_tls_cfg.cipher); 05479 } 05480 ami_tls_cfg.cipher = ast_strdup(""); 05481 05482 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 05483 val = var->value; 05484 05485 if (!ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) { 05486 continue; 05487 } 05488 05489 if (!strcasecmp(var->name, "enabled")) { 05490 manager_enabled = ast_true(val); 05491 } else if (!strcasecmp(var->name, "block-sockets")) { 05492 block_sockets = ast_true(val); 05493 } else if (!strcasecmp(var->name, "webenabled")) { 05494 webmanager_enabled = ast_true(val); 05495 } else if (!strcasecmp(var->name, "port")) { 05496 ami_desc.local_address.sin_port = htons(atoi(val)); 05497 } else if (!strcasecmp(var->name, "bindaddr")) { 05498 if (!inet_aton(val, &ami_desc.local_address.sin_addr)) { 05499 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val); 05500 memset(&ami_desc.local_address.sin_addr, 0, sizeof(ami_desc.local_address.sin_addr)); 05501 } 05502 } else if (!strcasecmp(var->name, "allowmultiplelogin")) { 05503 allowmultiplelogin = ast_true(val); 05504 } else if (!strcasecmp(var->name, "displayconnects")) { 05505 displayconnects = ast_true(val); 05506 } else if (!strcasecmp(var->name, "timestampevents")) { 05507 timestampevents = ast_true(val); 05508 } else if (!strcasecmp(var->name, "debug")) { 05509 manager_debug = ast_true(val); 05510 } else if (!strcasecmp(var->name, "httptimeout")) { 05511 newhttptimeout = atoi(val); 05512 } else { 05513 ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n", 05514 var->name, val); 05515 } 05516 } 05517 05518 if (manager_enabled) { 05519 ami_desc.local_address.sin_family = AF_INET; 05520 } 05521 /* if the amis address has not been set, default is the same as non secure ami */ 05522 if (!amis_desc.local_address.sin_addr.s_addr) { 05523 amis_desc.local_address.sin_addr = ami_desc.local_address.sin_addr; 05524 } 05525 if (ami_tls_cfg.enabled) { 05526 amis_desc.local_address.sin_family = AF_INET; 05527 } 05528 05529 AST_RWLIST_WRLOCK(&users); 05530 05531 /* First, get users from users.conf */ 05532 ucfg = ast_config_load2("users.conf", "manager", config_flags); 05533 if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) { 05534 const char *hasmanager; 05535 int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager")); 05536 05537 while ((cat = ast_category_browse(ucfg, cat))) { 05538 if (!strcasecmp(cat, "general")) { 05539 continue; 05540 } 05541 05542 hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager"); 05543 if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) { 05544 const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret"); 05545 const char *user_read = ast_variable_retrieve(ucfg, cat, "read"); 05546 const char *user_write = ast_variable_retrieve(ucfg, cat, "write"); 05547 const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects"); 05548 const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout"); 05549 05550 /* Look for an existing entry, 05551 * if none found - create one and add it to the list 05552 */ 05553 if (!(user = get_manager_by_name_locked(cat))) { 05554 if (!(user = ast_calloc(1, sizeof(*user)))) { 05555 break; 05556 } 05557 05558 /* Copy name over */ 05559 ast_copy_string(user->username, cat, sizeof(user->username)); 05560 /* Insert into list */ 05561 AST_LIST_INSERT_TAIL(&users, user, list); 05562 user->ha = NULL; 05563 user->keep = 1; 05564 user->readperm = -1; 05565 user->writeperm = -1; 05566 /* Default displayconnect from [general] */ 05567 user->displayconnects = displayconnects; 05568 user->writetimeout = 100; 05569 } 05570 05571 if (!user_secret) { 05572 user_secret = ast_variable_retrieve(ucfg, "general", "secret"); 05573 } 05574 if (!user_read) { 05575 user_read = ast_variable_retrieve(ucfg, "general", "read"); 05576 } 05577 if (!user_write) { 05578 user_write = ast_variable_retrieve(ucfg, "general", "write"); 05579 } 05580 if (!user_displayconnects) { 05581 user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects"); 05582 } 05583 if (!user_writetimeout) { 05584 user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout"); 05585 } 05586 05587 if (!ast_strlen_zero(user_secret)) { 05588 if (user->secret) { 05589 ast_free(user->secret); 05590 } 05591 user->secret = ast_strdup(user_secret); 05592 } 05593 05594 if (user_read) { 05595 user->readperm = get_perm(user_read); 05596 } 05597 if (user_write) { 05598 user->writeperm = get_perm(user_write); 05599 } 05600 if (user_displayconnects) { 05601 user->displayconnects = ast_true(user_displayconnects); 05602 } 05603 if (user_writetimeout) { 05604 int value = atoi(user_writetimeout); 05605 if (value < 100) { 05606 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at users.conf line %d\n", var->value, var->lineno); 05607 } else { 05608 user->writetimeout = value; 05609 } 05610 } 05611 } 05612 } 05613 ast_config_destroy(ucfg); 05614 } 05615 05616 /* cat is NULL here in any case */ 05617 05618 while ((cat = ast_category_browse(cfg, cat))) { 05619 struct ast_ha *oldha; 05620 05621 if (!strcasecmp(cat, "general")) { 05622 continue; 05623 } 05624 05625 /* Look for an existing entry, if none found - create one and add it to the list */ 05626 if (!(user = get_manager_by_name_locked(cat))) { 05627 if (!(user = ast_calloc(1, sizeof(*user)))) { 05628 break; 05629 } 05630 /* Copy name over */ 05631 ast_copy_string(user->username, cat, sizeof(user->username)); 05632 05633 user->ha = NULL; 05634 user->readperm = 0; 05635 user->writeperm = 0; 05636 /* Default displayconnect from [general] */ 05637 user->displayconnects = displayconnects; 05638 user->writetimeout = 100; 05639 05640 /* Insert into list */ 05641 AST_RWLIST_INSERT_TAIL(&users, user, list); 05642 } 05643 05644 /* Make sure we keep this user and don't destroy it during cleanup */ 05645 user->keep = 1; 05646 oldha = user->ha; 05647 user->ha = NULL; 05648 05649 var = ast_variable_browse(cfg, cat); 05650 for (; var; var = var->next) { 05651 if (!strcasecmp(var->name, "secret")) { 05652 if (user->secret) { 05653 ast_free(user->secret); 05654 } 05655 user->secret = ast_strdup(var->value); 05656 } else if (!strcasecmp(var->name, "deny") || 05657 !strcasecmp(var->name, "permit")) { 05658 user->ha = ast_append_ha(var->name, var->value, user->ha, NULL); 05659 } else if (!strcasecmp(var->name, "read") ) { 05660 user->readperm = get_perm(var->value); 05661 } else if (!strcasecmp(var->name, "write") ) { 05662 user->writeperm = get_perm(var->value); 05663 } else if (!strcasecmp(var->name, "displayconnects") ) { 05664 user->displayconnects = ast_true(var->value); 05665 } else if (!strcasecmp(var->name, "writetimeout")) { 05666 int value = atoi(var->value); 05667 if (value < 100) { 05668 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno); 05669 } else { 05670 user->writetimeout = value; 05671 } 05672 } else { 05673 ast_debug(1, "%s is an unknown option.\n", var->name); 05674 } 05675 } 05676 ast_free_ha(oldha); 05677 } 05678 ast_config_destroy(cfg); 05679 05680 /* Perform cleanup - essentially prune out old users that no longer exist */ 05681 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) { 05682 if (user->keep) { /* valid record. clear flag for the next round */ 05683 user->keep = 0; 05684 05685 /* Calculate A1 for Digest auth */ 05686 snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret); 05687 ast_md5_hash(a1_hash,a1); 05688 if (user->a1_hash) { 05689 ast_free(user->a1_hash); 05690 } 05691 user->a1_hash = ast_strdup(a1_hash); 05692 continue; 05693 } 05694 /* We do not need to keep this user so take them out of the list */ 05695 AST_RWLIST_REMOVE_CURRENT(list); 05696 /* Free their memory now */ 05697 if (user->a1_hash) { 05698 ast_free(user->a1_hash); 05699 } 05700 if (user->secret) { 05701 ast_free(user->secret); 05702 } 05703 ast_free_ha(user->ha); 05704 ast_free(user); 05705 } 05706 AST_RWLIST_TRAVERSE_SAFE_END; 05707 05708 AST_RWLIST_UNLOCK(&users); 05709 05710 if (!reload) { 05711 /* If you have a NULL hash fn, you only need a single bucket */ 05712 sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn); 05713 } 05714 05715 if (webmanager_enabled && manager_enabled) { 05716 if (!webregged) { 05717 05718 ast_http_uri_link(&rawmanuri); 05719 ast_http_uri_link(&manageruri); 05720 ast_http_uri_link(&managerxmluri); 05721 05722 ast_http_uri_link(&arawmanuri); 05723 ast_http_uri_link(&amanageruri); 05724 ast_http_uri_link(&amanagerxmluri); 05725 webregged = 1; 05726 } 05727 } else { 05728 if (webregged) { 05729 ast_http_uri_unlink(&rawmanuri); 05730 ast_http_uri_unlink(&manageruri); 05731 ast_http_uri_unlink(&managerxmluri); 05732 05733 ast_http_uri_unlink(&arawmanuri); 05734 ast_http_uri_unlink(&amanageruri); 05735 ast_http_uri_unlink(&amanagerxmluri); 05736 webregged = 0; 05737 } 05738 } 05739 05740 if (newhttptimeout > 0) { 05741 httptimeout = newhttptimeout; 05742 } 05743 05744 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled"); 05745 05746 ast_tcptls_server_start(&ami_desc); 05747 if (ast_ssl_setup(amis_desc.tls_cfg)) { 05748 ast_tcptls_server_start(&amis_desc); 05749 } 05750 return 0; 05751 }
| 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 5763 of file manager.c.
References AST_LIST_INSERT_HEAD, mansession_session::datastores, and mansession::session.
05764 { 05765 AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry); 05766 05767 return 0; 05768 }
| struct ast_datastore* astman_datastore_find | ( | struct mansession * | s, | |
| const struct ast_datastore_info * | info, | |||
| const char * | uid | |||
| ) | [read] |
Find a datastore on a session.
| pointer | to the datastore if found | |
| NULL | if not found |
Definition at line 5775 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.
05776 { 05777 struct ast_datastore *datastore = NULL; 05778 05779 if (info == NULL) 05780 return NULL; 05781 05782 AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) { 05783 if (datastore->info != info) { 05784 continue; 05785 } 05786 05787 if (uid == NULL) { 05788 /* matched by type only */ 05789 break; 05790 } 05791 05792 if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) { 05793 /* Matched by type AND uid */ 05794 break; 05795 } 05796 } 05797 AST_LIST_TRAVERSE_SAFE_END; 05798 05799 return datastore; 05800 }
| 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 5770 of file manager.c.
References AST_LIST_REMOVE, mansession_session::datastores, and mansession::session.
05771 { 05772 return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1; 05773 }
| int astman_is_authed | ( | uint32_t | ident | ) |
Determinie if a manager session ident is authenticated.
Definition at line 4437 of file manager.c.
References ao2_unlock(), mansession_session::authenticated, find_session(), and unref_mansession().
Referenced by http_post_callback(), and static_callback().
04438 { 04439 int authed; 04440 struct mansession_session *session; 04441 04442 if (!(session = find_session(ident, 0))) 04443 return 0; 04444 04445 authed = (session->authenticated != 0); 04446 04447 ao2_unlock(session); 04448 unref_mansession(session); 04449 04450 return authed; 04451 }
| 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 4453 of file manager.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_unlock(), mansession_session::managerid, mansession_session::readperm, and unref_mansession().
04454 { 04455 int result = 0; 04456 struct mansession_session *session; 04457 struct ao2_iterator i; 04458 04459 if (ident == 0) { 04460 return 0; 04461 } 04462 04463 i = ao2_iterator_init(sessions, 0); 04464 while ((session = ao2_iterator_next(&i))) { 04465 ao2_lock(session); 04466 if ((session->managerid == ident) && (session->readperm & perm)) { 04467 result = 1; 04468 ao2_unlock(session); 04469 unref_mansession(session); 04470 break; 04471 } 04472 ao2_unlock(session); 04473 unref_mansession(session); 04474 } 04475 return result; 04476 }
| 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 4478 of file manager.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_unlock(), mansession_session::managerid, unref_mansession(), and mansession_session::writeperm.
Referenced by http_post_callback().
04479 { 04480 int result = 0; 04481 struct mansession_session *session; 04482 struct ao2_iterator i; 04483 04484 if (ident == 0) { 04485 return 0; 04486 } 04487 04488 i = ao2_iterator_init(sessions, 0); 04489 while ((session = ao2_iterator_next(&i))) { 04490 ao2_lock(session); 04491 if ((session->managerid == ident) && (session->writeperm & perm)) { 04492 result = 1; 04493 ao2_unlock(session); 04494 unref_mansession(session); 04495 break; 04496 } 04497 ao2_unlock(session); 04498 unref_mansession(session); 04499 } 04500 return result; 04501 }
| 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 4959 of file manager.c.
References ast_manager_user::a1_hash, ao2_lock(), ao2_unlock(), ast_apply_ha(), ast_copy_string(), ast_debug, ast_free, ast_get_http_method(), ast_http_auth(), ast_http_error(), AST_HTTP_GET, ast_http_get_post_vars(), AST_HTTP_HEAD, AST_HTTP_POST, ast_http_send(), ast_inet_ntoa(), AST_LIST_HEAD_INIT_NOLOCK, ast_log(), AST_MAX_MANHEADERS, ast_md5_hash(), ast_mutex_destroy(), ast_mutex_init(), ast_parse_digest(), ast_random(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_str_append(), ast_str_create(), ast_string_field_free_memory, ast_string_field_init, ast_strlen_zero(), ast_variables_destroy(), ast_verb, mansession_session::authenticated, buf, build_mansession(), ast_http_digest::cnonce, contenttype, mansession_session::datastores, ast_manager_user::displayconnects, errno, mansession_session::f, mansession::f, mansession_session::fd, mansession::fd, find_session_by_nonce(), FORMAT_HTML, FORMAT_XML, get_manager_by_name_locked(), global_realm, grab_last(), ast_manager_user::ha, message::hdrcount, message::headers, mansession_session::last_ev, mansession::lock, LOG_NOTICE, LOG_WARNING, mansession_session::managerid, ast_variable::name, mansession_session::nc, ast_http_digest::nc, mansession_session::needdestroy, ast_variable::next, ast_http_digest::nonce, mansession_session::noncetime, mansession_session::oldnonce, process_message(), ast_http_digest::qop, mansession_session::readperm, ast_manager_user::readperm, ast_http_digest::response, s, mansession::session, session_destroy(), mansession_session::sessionstart, mansession_session::sessiontimeout, mansession_session::sin, ast_http_digest::uri, mansession_session::username, ast_manager_user::username, ast_http_digest::username, ast_variable::value, mansession_session::writeperm, ast_manager_user::writeperm, mansession_session::writetimeout, ast_manager_user::writetimeout, and xml_translate().
Referenced by auth_manager_http_callback(), auth_mxml_http_callback(), and auth_rawman_http_callback().
04965 { 04966 struct mansession_session *session = NULL; 04967 struct mansession s = { NULL, }; 04968 struct ast_variable *v, *params = get_params; 04969 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */ 04970 struct ast_str *http_header = NULL, *out = NULL; 04971 size_t result_size = 512; 04972 struct message m = { 0 }; 04973 unsigned int x; 04974 size_t hdrlen; 04975 04976 time_t time_now = time(NULL); 04977 unsigned long nonce = 0, nc; 04978 struct ast_http_digest d = { NULL, }; 04979 struct ast_manager_user *user = NULL; 04980 int stale = 0; 04981 char resp_hash[256]=""; 04982 /* Cache for user data */ 04983 char u_username[80]; 04984 int u_readperm; 04985 int u_writeperm; 04986 int u_writetimeout; 04987 int u_displayconnects; 04988 04989 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) { 04990 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 04991 return -1; 04992 } 04993 04994 /* Find "Authorization: " header */ 04995 for (v = headers; v; v = v->next) { 04996 if (!strcasecmp(v->name, "Authorization")) { 04997 break; 04998 } 04999 } 05000 05001 if (!v || ast_strlen_zero(v->value)) { 05002 goto out_401; /* Authorization Header not present - send auth request */ 05003 } 05004 05005 /* Digest found - parse */ 05006 if (ast_string_field_init(&d, 128)) { 05007 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 05008 return -1; 05009 } 05010 05011 if (ast_parse_digest(v->value, &d, 0, 1)) { 05012 /* Error in Digest - send new one */ 05013 nonce = 0; 05014 goto out_401; 05015 } 05016 if (sscanf(d.nonce, "%30lx", &nonce) != 1) { 05017 ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce); 05018 nonce = 0; 05019 goto out_401; 05020 } 05021 05022 AST_RWLIST_WRLOCK(&users); 05023 user = get_manager_by_name_locked(d.username); 05024 if(!user) { 05025 AST_RWLIST_UNLOCK(&users); 05026 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username); 05027 nonce = 0; 05028 goto out_401; 05029 } 05030 05031 /* --- We have User for this auth, now check ACL */ 05032 if (user->ha && !ast_apply_ha(user->ha, remote_address)) { 05033 AST_RWLIST_UNLOCK(&users); 05034 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username); 05035 ast_http_error(ser, 403, "Permission denied", "Permission denied\n"); 05036 return -1; 05037 } 05038 05039 /* --- We have auth, so check it */ 05040 05041 /* compute the expected response to compare with what we received */ 05042 { 05043 char a2[256]; 05044 char a2_hash[256]; 05045 char resp[256]; 05046 05047 /* XXX Now request method are hardcoded in A2 */ 05048 snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri); 05049 ast_md5_hash(a2_hash, a2); 05050 05051 if (d.qop) { 05052 /* RFC 2617 */ 05053 snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash); 05054 } else { 05055 /* RFC 2069 */ 05056 snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash); 05057 } 05058 ast_md5_hash(resp_hash, resp); 05059 } 05060 05061 if (!d.nonce || strncasecmp(d.response, resp_hash, strlen(resp_hash))) { 05062 /* Something was wrong, so give the client to try with a new challenge */ 05063 AST_RWLIST_UNLOCK(&users); 05064 nonce = 0; 05065 goto out_401; 05066 } 05067 05068 /* 05069 * User are pass Digest authentication. 05070 * Now, cache the user data and unlock user list. 05071 */ 05072 ast_copy_string(u_username, user->username, sizeof(u_username)); 05073 u_readperm = user->readperm; 05074 u_writeperm = user->writeperm; 05075 u_displayconnects = user->displayconnects; 05076 u_writetimeout = user->writetimeout; 05077 AST_RWLIST_UNLOCK(&users); 05078 05079 if (!(session = find_session_by_nonce(d.username, nonce, &stale))) { 05080 /* 05081 * Create new session. 05082 * While it is not in the list we don't need any locking 05083 */ 05084 if (!(session = build_mansession(*remote_address))) { 05085 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 05086 return -1; 05087 } 05088 ao2_lock(session); 05089 05090 ast_copy_string(session->username, u_username, sizeof(session->username)); 05091 session->managerid = nonce; 05092 session->last_ev = grab_last(); 05093 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores); 05094 05095 session->readperm = u_readperm; 05096 session->writeperm = u_writeperm; 05097 session->writetimeout = u_writetimeout; 05098 05099 if (u_displayconnects) { 05100 ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 05101 } 05102 session->noncetime = session->sessionstart = time_now; 05103 session->authenticated = 1; 05104 } else if (stale) { 05105 /* 05106 * Session found, but nonce is stale. 05107 * 05108 * This could be because an old request (w/old nonce) arrived. 05109 * 05110 * This may be as the result of http proxy usage (separate delay or 05111 * multipath) or in a situation where a page was refreshed too quickly 05112 * (seen in Firefox). 05113 * 05114 * In this situation, we repeat the 401 auth with the current nonce 05115 * value. 05116 */ 05117 nonce = session->managerid; 05118 ao2_unlock(session); 05119 stale = 1; 05120 goto out_401; 05121 } else { 05122 sscanf(d.nc, "%30lx", &nc); 05123 if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) { 05124 /* 05125 * Nonce time expired (> 2 minutes) or something wrong with nonce 05126 * counter. 05127 * 05128 * Create new nonce key and resend Digest auth request. Old nonce 05129 * is saved for stale checking... 05130 */ 05131 session->nc = 0; /* Reset nonce counter */ 05132 session->oldnonce = session->managerid; 05133 nonce = session->managerid = ast_random(); 05134 session->noncetime = time_now; 05135 ao2_unlock(session); 05136 stale = 1; 05137 goto out_401; 05138 } else { 05139 session->nc = nc; /* All OK, save nonce counter */ 05140 } 05141 } 05142 05143 05144 /* Reset session timeout. */ 05145 session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5); 05146 ao2_unlock(session); 05147 05148 ast_mutex_init(&s.lock); 05149 s.session = session; 05150 s.fd = mkstemp(template); /* create a temporary file for command output */ 05151 unlink(template); 05152 if (s.fd <= -1) { 05153 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n"); 05154 goto auth_callback_out; 05155 } 05156 s.f = fdopen(s.fd, "w+"); 05157 if (!s.f) { 05158 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno)); 05159 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n"); 05160 close(s.fd); 05161 goto auth_callback_out; 05162 } 05163 05164 if (method == AST_HTTP_POST) { 05165 params = ast_http_get_post_vars(ser, headers); 05166 } 05167 05168 for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) { 05169 hdrlen = strlen(v->name) + strlen(v->value) + 3; 05170 m.headers[m.hdrcount] = alloca(hdrlen); 05171 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value); 05172 ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]); 05173 m.hdrcount = x + 1; 05174 } 05175 05176 if (process_message(&s, &m)) { 05177 if (u_displayconnects) { 05178 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 05179 } 05180 05181 session->needdestroy = 1; 05182 } 05183 05184 if (s.f) { 05185 result_size = ftell(s.f); /* Calculate approx. size of result */ 05186 } 05187 05188 http_header = ast_str_create(80); 05189 out = ast_str_create(result_size * 2 + 512); 05190 05191 if (http_header == NULL || out == NULL) { 05192 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n"); 05193 goto auth_callback_out; 05194 } 05195 05196 ast_str_append(&http_header, 0, "Content-type: text/%s", contenttype[format]); 05197 05198 if (format == FORMAT_XML) { 05199 ast_str_append(&out, 0, "<ajax-response>\n"); 05200 } else if (format == FORMAT_HTML) { 05201 ast_str_append(&out, 0, 05202 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 05203 "<html><head>\r\n" 05204 "<title>Asterisk™ Manager Interface</title>\r\n" 05205 "</head><body style=\"background-color: #ffffff;\">\r\n" 05206 "<form method=\"POST\">\r\n" 05207 "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n" 05208 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n" 05209 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>" 05210 "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n"); 05211 } 05212 05213 if (s.f != NULL) { /* have temporary output */ 05214 char *buf; 05215 size_t l = ftell(s.f); 05216 05217 if (l) { 05218 if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s.fd, 0))) { 05219 if (format == FORMAT_XML || format == FORMAT_HTML) { 05220 xml_translate(&out, buf, params, format); 05221 } else { 05222 ast_str_append(&out, 0, "%s", buf); 05223 } 05224 munmap(buf, l); 05225 } 05226 } else if (format == FORMAT_XML || format == FORMAT_HTML) { 05227 xml_translate(&out, "", params, format); 05228 } 05229 fclose(s.f); 05230 s.f = NULL; 05231 s.fd = -1; 05232 } 05233 05234 if (format == FORMAT_XML) { 05235 ast_str_append(&out, 0, "</ajax-response>\n"); 05236 } else if (format == FORMAT_HTML) { 05237 ast_str_append(&out, 0, "</table></form></body></html>\r\n"); 05238 } 05239 05240 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0); 05241 http_header = out = NULL; 05242 05243 auth_callback_out: 05244 ast_mutex_destroy(&s.lock); 05245 05246 /* Clear resources and unlock manager session */ 05247 if (method == AST_HTTP_POST && params) { 05248 ast_variables_destroy(params); 05249 } 05250 05251 ast_free(http_header); 05252 ast_free(out); 05253 05254 ao2_lock(session); 05255 if (session->f) { 05256 fclose(session->f); 05257 } 05258 session->f = NULL; 05259 session->fd = -1; 05260 ao2_unlock(session); 05261 05262 if (session->needdestroy) { 05263 ast_debug(1, "Need destroy, doing it now!\n"); 05264 session_destroy(session); 05265 } 05266 ast_string_field_free_memory(&d); 05267 return 0; 05268 05269 out_401: 05270 if (!nonce) { 05271 nonce = ast_random(); 05272 } 05273 05274 ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL); 05275 ast_string_field_free_memory(&d); 05276 return 0; 05277 }
| 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 5320 of file manager.c.
References auth_http_callback(), FORMAT_HTML, and ast_tcptls_session_instance::remote_address.
05321 { 05322 return auth_http_callback(ser, method, FORMAT_HTML, &ser->remote_address, uri, get_params, headers); 05323 }
| 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 5325 of file manager.c.
References auth_http_callback(), FORMAT_XML, and ast_tcptls_session_instance::remote_address.
05326 { 05327 return auth_http_callback(ser, method, FORMAT_XML, &ser->remote_address, uri, get_params, headers); 05328 }
| 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 5330 of file manager.c.
References auth_http_callback(), FORMAT_RAW, and ast_tcptls_session_instance::remote_address.
05331 { 05332 return auth_http_callback(ser, method, FORMAT_RAW, &ser->remote_address, uri, get_params, headers); 05333 }
| static struct mansession_session* find_session | ( | uint32_t | ident, | |
| int | incinuse | |||
| ) | [static, read] |
locate an http session in the list. The search key (ident) is the value of the mansession_id cookie (0 is not valid and means a session on the AMI socket).
Definition at line 4380 of file manager.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_unlock(), ast_atomic_fetchadd_int(), mansession_session::inuse, mansession_session::managerid, mansession_session::needdestroy, and unref_mansession().
Referenced by astman_is_authed(), and generic_http_callback().
04381 { 04382 struct mansession_session *session; 04383 struct ao2_iterator i; 04384 04385 if (ident == 0) { 04386 return NULL; 04387 } 04388 04389 i = ao2_iterator_init(sessions, 0); 04390 while ((session = ao2_iterator_next(&i))) { 04391 ao2_lock(session); 04392 if (session->managerid == ident && !session->needdestroy) { 04393 ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0); 04394 break; 04395 } 04396 ao2_unlock(session); 04397 unref_mansession(session); 04398 } 04399 04400 return session; 04401 }
| static struct mansession_session* find_session_by_nonce | ( | const char * | username, | |
| unsigned long | nonce, | |||
| int * | stale | |||
| ) | [static, read] |
locate an http session in the list. The search keys (nonce) and (username) is value from received "Authorization" http header. As well as in find_session() function, the value of the nonce can't be zero. (0 meansi, that the session used for AMI socket connection). Flag (stale) is set, if client used valid, but old, nonce value.
Definition at line 4412 of file manager.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_unlock(), mansession_session::managerid, mansession_session::oldnonce, unref_mansession(), and mansession_session::username.
Referenced by auth_http_callback().
04413 { 04414 struct mansession_session *session; 04415 struct ao2_iterator i; 04416 04417 if (nonce == 0 || username == NULL || stale == NULL) { 04418 return NULL; 04419 } 04420 04421 i = ao2_iterator_init(sessions, 0); 04422 while ((session = ao2_iterator_next(&i))) { 04423 ao2_lock(session); 04424 if (!strcasecmp(session->username, username) && session->managerid == nonce) { 04425 *stale = 0; 04426 break; 04427 } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) { 04428 *stale = 1; 04429 break; 04430 } 04431 ao2_unlock(session); 04432 unref_mansession(session); 04433 } 04434 return session; 04435 }
| 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 4730 of file manager.c.
References ao2_lock(), ao2_unlock(), ast_debug, ast_free, ast_http_error(), AST_HTTP_GET, ast_http_get_cookies(), ast_http_get_post_vars(), AST_HTTP_HEAD, AST_HTTP_POST, ast_http_send(), ast_inet_ntoa(), AST_LIST_HEAD_INIT_NOLOCK, ast_log(), AST_MAX_MANHEADERS, ast_mutex_destroy(), ast_mutex_init(), AST_PTHREADT_NULL, ast_random(), ast_str_append(), ast_str_create(), ast_variables_destroy(), ast_verb, mansession_session::authenticated, buf, build_mansession(), contenttype, errno, mansession_session::f, mansession::f, mansession::fd, mansession_session::fd, find_session(), FORMAT_HTML, FORMAT_XML, grab_last(), message::hdrcount, message::headers, mansession_session::inuse, mansession::lock, LOG_WARNING, manager_displayconnects(), mansession_session::managerid, ast_variable::name, mansession_session::needdestroy, ast_variable::next, process_message(), ROW_FMT, s, mansession_session::send_events, mansession::session, session_destroy(), mansession_session::sessiontimeout, mansession_session::sin, TEST_STRING, mansession_session::username, ast_variable::value, mansession_session::waiting_thread, and xml_translate().
Referenced by manager_http_callback(), mxml_http_callback(), and rawman_http_callback().
04736 { 04737 struct mansession s = { .session = NULL, .tcptls_session = ser }; 04738 struct mansession_session *session = NULL; 04739 uint32_t ident = 0; 04740 int blastaway = 0; 04741 struct ast_variable *v, *cookies, *params = get_params; 04742 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */ 04743 struct ast_str *http_header = NULL, *out = NULL; 04744 struct message m = { 0 }; 04745 unsigned int x; 04746 size_t hdrlen; 04747 04748 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) { 04749 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 04750 return -1; 04751 } 04752 04753 cookies = ast_http_get_cookies(headers); 04754 for (v = cookies; v; v = v->next) { 04755 if (!strcasecmp(v->name, "mansession_id")) { 04756 sscanf(v->value, "%30x", &ident); 04757 break; 04758 } 04759 } 04760 if (cookies) { 04761 ast_variables_destroy(cookies); 04762 } 04763 04764 if (!(session = find_session(ident, 1))) { 04765 04766 /**/ 04767 /* Create new session. 04768 * While it is not in the list we don't need any locking 04769 */ 04770 if (!(session = build_mansession(*remote_address))) { 04771 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n"); 04772 return -1; 04773 } 04774 ao2_lock(session); 04775 session->sin = *remote_address; 04776 session->fd = -1; 04777 session->waiting_thread = AST_PTHREADT_NULL; 04778 session->send_events = 0; 04779 session->inuse = 1; 04780 /*!\note There is approximately a 1 in 1.8E19 chance that the following 04781 * calculation will produce 0, which is an invalid ID, but due to the 04782 * properties of the rand() function (and the constantcy of s), that 04783 * won't happen twice in a row. 04784 */ 04785 while ((session->managerid = ast_random() ^ (unsigned long) session) == 0); 04786 session->last_ev = grab_last(); 04787 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores); 04788 } 04789 ao2_unlock(session); 04790 04791 http_header = ast_str_create(128); 04792 out = ast_str_create(2048); 04793 04794 ast_mutex_init(&s.lock); 04795 04796 if (http_header == NULL || out == NULL) { 04797 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n"); 04798 goto generic_callback_out; 04799 } 04800 04801 s.session = session; 04802 s.fd = mkstemp(template); /* create a temporary file for command output */ 04803 unlink(template); 04804 if (s.fd <= -1) { 04805 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n"); 04806 goto generic_callback_out; 04807 } 04808 s.f = fdopen(s.fd, "w+"); 04809 if (!s.f) { 04810 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno)); 04811 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n"); 04812 close(s.fd); 04813 goto generic_callback_out; 04814 } 04815 04816 if (method == AST_HTTP_POST) { 04817 params = ast_http_get_post_vars(ser, headers); 04818 } 04819 04820 for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) { 04821 hdrlen = strlen(v->name) + strlen(v->value) + 3; 04822 m.headers[m.hdrcount] = alloca(hdrlen); 04823 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value); 04824 ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]); 04825 m.hdrcount = x + 1; 04826 } 04827 04828 if (process_message(&s, &m)) { 04829 if (session->authenticated) { 04830 if (manager_displayconnects(session)) { 04831 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr)); 04832 } 04833 } else { 04834 if (displayconnects) { 04835 ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr)); 04836 } 04837 } 04838 session->needdestroy = 1; 04839 } 04840 04841 ast_str_append(&http_header, 0, 04842 "Content-type: text/%s\r\n" 04843 "Cache-Control: no-cache;\r\n" 04844 "Set-Cookie: mansession_id=\"%08x\"; Version=\"1\"; Max-Age=%d" 04845 "Pragma: SuppressEvents\r\n", 04846 contenttype[format], 04847 session->managerid, httptimeout); 04848 04849 if (format == FORMAT_XML) { 04850 ast_str_append(&out, 0, "<ajax-response>\n"); 04851 } else if (format == FORMAT_HTML) { 04852 /* 04853 * When handling AMI-over-HTTP in HTML format, we provide a simple form for 04854 * debugging purposes. This HTML code should not be here, we 04855 * should read from some config file... 04856 */ 04857 04858 #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n" 04859 #define TEST_STRING \ 04860 "<form action=\"manager\" method=\"post\">\n\ 04861 Action: <select name=\"action\">\n\ 04862 <option value=\"\">-----></option>\n\ 04863 <option value=\"login\">login</option>\n\ 04864 <option value=\"command\">Command</option>\n\ 04865 <option value=\"waitevent\">waitevent</option>\n\ 04866 <option value=\"listcommands\">listcommands</option>\n\ 04867 </select>\n\ 04868 or <input name=\"action\"><br/>\n\ 04869 CLI Command <input name=\"command\"><br>\n\ 04870 user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\ 04871 <input type=\"submit\">\n</form>\n" 04872 04873 ast_str_append(&out, 0, "<title>Asterisk™ Manager Interface</title>"); 04874 ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n"); 04875 ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>"); 04876 ast_str_append(&out, 0, ROW_FMT, TEST_STRING); 04877 } 04878 04879 if (s.f != NULL) { /* have temporary output */ 04880 char *buf; 04881 size_t l; 04882 04883 /* Ensure buffer is NULL-terminated */ 04884 fprintf(s.f, "%c", 0); 04885 04886 if ((l = ftell(s.f))) { 04887 if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s.fd, 0))) { 04888 ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n"); 04889 } else { 04890 if (format == FORMAT_XML || format == FORMAT_HTML) { 04891 xml_translate(&out, buf, params, format); 04892 } else { 04893 ast_str_append(&out, 0, "%s", buf); 04894 } 04895 munmap(buf, l); 04896 } 04897 } else if (format == FORMAT_XML || format == FORMAT_HTML) { 04898 xml_translate(&out, "", params, format); 04899 } 04900 fclose(s.f); 04901 s.f = NULL; 04902 s.fd = -1; 04903 } 04904 04905 if (format == FORMAT_XML) { 04906 ast_str_append(&out, 0, "</ajax-response>\n"); 04907 } else if (format == FORMAT_HTML) { 04908 ast_str_append(&out, 0, "</table></body>\r\n"); 04909 } 04910 04911 ao2_lock(session); 04912 /* Reset HTTP timeout. If we're not authenticated, keep it extremely short */ 04913 session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5); 04914 04915 if (session->needdestroy) { 04916 if (session->inuse == 1) { 04917 ast_debug(1, "Need destroy, doing it now!\n"); 04918 blastaway = 1; 04919 } else { 04920 ast_debug(1, "Need destroy, but can't do it yet!\n"); 04921 if (session->waiting_thread != AST_PTHREADT_NULL) { 04922 pthread_kill(session->waiting_thread, SIGURG); 04923 } 04924 session->inuse--; 04925 } 04926 } else { 04927 session->inuse--; 04928 } 04929 ao2_unlock(session); 04930 04931 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0); 04932 http_header = out = NULL; 04933 04934 generic_callback_out: 04935 ast_mutex_destroy(&s.lock); 04936 04937 /* Clear resource */ 04938 04939 if (method == AST_HTTP_POST && params) { 04940 ast_variables_destroy(params); 04941 } 04942 if (http_header) { 04943 ast_free(http_header); 04944 } 04945 if (out) { 04946 ast_free(out); 04947 } 04948 04949 if (session && blastaway) { 04950 session_destroy(session); 04951 } else if (session && session->f) { 04952 fclose(session->f); 04953 session->f = NULL; 04954 } 04955 04956 return 0; 04957 }
| int init_manager | ( | void | ) |
Called by Asterisk initialization.
Definition at line 5753 of file manager.c.
References __init_manager().
Referenced by main().
05754 { 05755 return __init_manager(0); 05756 }
| 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 5279 of file manager.c.
References FORMAT_HTML, generic_http_callback(), and ast_tcptls_session_instance::remote_address.
05280 { 05281 return generic_http_callback(ser, method, FORMAT_HTML, &ser->remote_address, uri, get_params, headers); 05282 }
| 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 5284 of file manager.c.
References FORMAT_XML, generic_http_callback(), and ast_tcptls_session_instance::remote_address.
05285 { 05286 return generic_http_callback(ser, method, FORMAT_XML, &ser->remote_address, uri, get_params, headers); 05287 }
| 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 5368 of file manager.c.
References purge_events(), and purge_sessions().
05369 { 05370 purge_sessions(1); 05371 purge_events(); 05372 }
| 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 5289 of file manager.c.
References FORMAT_RAW, generic_http_callback(), and ast_tcptls_session_instance::remote_address.
05290 { 05291 return generic_http_callback(ser, method, FORMAT_RAW, &ser->remote_address, uri, get_params, headers); 05292 }
| int reload_manager | ( | void | ) |
Called by Asterisk module functions and the CLI command.
Definition at line 5758 of file manager.c.
References __init_manager().
Referenced by handle_manager_reload().
05759 { 05760 return __init_manager(1); 05761 }
| static int variable_count_cmp_fn | ( | void * | obj, | |
| void * | vstr, | |||
| int | flags | |||
| ) | [static] |
Definition at line 4577 of file manager.c.
References CMP_MATCH, CMP_STOP, str, and variable_count::varname.
Referenced by xml_translate().
04578 { 04579 /* Due to the simplicity of struct variable_count, it makes no difference 04580 * if you pass in objects or strings, the same operation applies. This is 04581 * due to the fact that the hash occurs on the first element, which means 04582 * the address of both the struct and the string are exactly the same. */ 04583 struct variable_count *vc = obj; 04584 char *str = vstr; 04585 return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0; 04586 }
| static int variable_count_hash_fn | ( | const void * | vvc, | |
| const int | flags | |||
| ) | [static] |
Definition at line 4570 of file manager.c.
References ast_str_hash(), and variable_count::varname.
Referenced by xml_translate().
04571 { 04572 const struct variable_count *vc = vvc; 04573 04574 return ast_str_hash(vc->varname); 04575 }
| static void xml_copy_escape | ( | struct ast_str ** | out, | |
| const char * | src, | |||
| int | mode | |||
| ) | [static] |
Definition at line 4508 of file manager.c.
References ast_str_append(), and buf.
Referenced by xml_translate().
04509 { 04510 /* store in a local buffer to avoid calling ast_str_append too often */ 04511 char buf[256]; 04512 char *dst = buf; 04513 int space = sizeof(buf); 04514 /* repeat until done and nothing to flush */ 04515 for ( ; *src || dst != buf ; src++) { 04516 if (*src == '\0' || space < 10) { /* flush */ 04517 *dst++ = '\0'; 04518 ast_str_append(out, 0, "%s", buf); 04519 dst = buf; 04520 space = sizeof(buf); 04521 if (*src == '\0') { 04522 break; 04523 } 04524 } 04525 04526 if ( (mode & 2) && !isalnum(*src)) { 04527 *dst++ = '_'; 04528 space--; 04529 continue; 04530 } 04531 switch (*src) { 04532 case '<': 04533 strcpy(dst, "<"); 04534 dst += 4; 04535 space -= 4; 04536 break; 04537 case '>': 04538 strcpy(dst, ">"); 04539 dst += 4; 04540 space -= 4; 04541 break; 04542 case '\"': 04543 strcpy(dst, """); 04544 dst += 6; 04545 space -= 6; 04546 break; 04547 case '\'': 04548 strcpy(dst, "'"); 04549 dst += 6; 04550 space -= 6; 04551 break; 04552 case '&': 04553 strcpy(dst, "&"); 04554 dst += 5; 04555 space -= 5; 04556 break; 04557 04558 default: 04559 *dst++ = mode ? tolower(*src) : *src; 04560 space--; 04561 } 04562 } 04563 }
| 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 4616 of file manager.c.
References ao2_alloc, ao2_container_alloc, ao2_find, ao2_link, ao2_ref, ast_debug, ast_skip_blanks(), ast_str_append(), ast_strlen_zero(), ast_trim_blanks(), variable_count::count, FORMAT_XML, ast_variable::name, ast_variable::next, strsep(), ast_variable::value, var, variable_count_cmp_fn(), variable_count_hash_fn(), variable_count::varname, and xml_copy_escape().
Referenced by auth_http_callback(), and generic_http_callback().
04617 { 04618 struct ast_variable *v; 04619 const char *dest = NULL; 04620 char *var, *val; 04621 const char *objtype = NULL; 04622 int in_data = 0; /* parsing data */ 04623 int inobj = 0; 04624 int xml = (format == FORMAT_XML); 04625 struct variable_count *vc = NULL; 04626 struct ao2_container *vco = NULL; 04627 04628 if (xml) { 04629 /* dest and objtype need only for XML format */ 04630 for (v = get_vars; v; v = v->next) { 04631 if (!strcasecmp(v->name, "ajaxdest")) { 04632 dest = v->value; 04633 } else if (!strcasecmp(v->name, "ajaxobjtype")) { 04634 objtype = v->value; 04635 } 04636 } 04637 if (ast_strlen_zero(dest)) { 04638 dest = "unknown"; 04639 } 04640 if (ast_strlen_zero(objtype)) { 04641 objtype = "generic"; 04642 } 04643 } 04644 04645 /* we want to stop when we find an empty line */ 04646 while (in && *in) { 04647 val = strsep(&in, "\r\n"); /* mark start and end of line */ 04648 if (in && *in == '\n') { /* remove trailing \n if any */ 04649 in++; 04650 } 04651 ast_trim_blanks(val); 04652 ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val); 04653 if (ast_strlen_zero(val)) { 04654 /* empty line */ 04655 if (in_data) { 04656 /* close data in Opaque mode */ 04657 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n"); 04658 in_data = 0; 04659 } 04660 04661 if (inobj) { 04662 /* close block */ 04663 ast_str_append(out, 0, xml ? " /></response>\n" : 04664 "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 04665 inobj = 0; 04666 ao2_ref(vco, -1); 04667 vco = NULL; 04668 } 04669 continue; 04670 } 04671 04672 if (!inobj) { 04673 /* start new block */ 04674 if (xml) { 04675 ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype); 04676 } 04677 vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn); 04678 inobj = 1; 04679 } 04680 04681 if (in_data) { 04682 /* Process data field in Opaque mode */ 04683 xml_copy_escape(out, val, 0); /* data field */ 04684 ast_str_append(out, 0, xml ? "\n" : "<br>\n"); 04685 continue; 04686 } 04687 04688 /* We expect "Name: value" line here */ 04689 var = strsep(&val, ":"); 04690 if (val) { 04691 /* found the field name */ 04692 val = ast_skip_blanks(val); 04693 ast_trim_blanks(var); 04694 } else { 04695 /* field name not found, switch to opaque mode */ 04696 val = var; 04697 var = "Opaque-data"; 04698 in_data = 1; 04699 } 04700 04701 04702 ast_str_append(out, 0, xml ? " " : "<tr><td>"); 04703 if ((vc = ao2_find(vco, var, 0))) { 04704 vc->count++; 04705 } else { 04706 /* Create a new entry for this one */ 04707 vc = ao2_alloc(sizeof(*vc), NULL); 04708 vc->varname = var; 04709 vc->count = 1; 04710 ao2_link(vco, vc); 04711 } 04712 04713 xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */ 04714 if (vc->count > 1) { 04715 ast_str_append(out, 0, "-%d", vc->count); 04716 } 04717 ao2_ref(vc, -1); 04718 ast_str_append(out, 0, xml ? "='" : "</td><td>"); 04719 xml_copy_escape(out, val, 0); /* data field */ 04720 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n"); 04721 } 04722 04723 if (inobj) { 04724 ast_str_append(out, 0, xml ? " /></response>\n" : 04725 "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 04726 ao2_ref(vco, -1); 04727 } 04728 }
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] |
const char* const contenttype[] [static] |
Initial value:
{
[FORMAT_RAW] = "plain",
[FORMAT_HTML] = "html",
[FORMAT_XML] = "xml",
}
Definition at line 4369 of file manager.c.
Referenced by auth_http_callback(), and generic_http_callback().
struct ast_http_uri manageruri [static] |
struct ast_http_uri managerxmluri [static] |
struct ast_http_uri rawmanuri [static] |
int registered = 0 [static] |
int webregged = 0 [static] |
| const char* words[AST_MAX_CMD_LEN] |
1.5.6