Wed Oct 28 13:33:09 2009

Asterisk developer's documentation


manager.c File Reference

The Asterisk Management Interface - AMI. More...

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

Include dependency graph for manager.c:

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=\"\">-----&gt;</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_datastoreastman_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_variableastman_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_sessionbuild_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_sessionfind_session (uint32_t ident, int incinuse)
static struct mansession_sessionfind_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_userget_manager_by_name_locked (const char *name)
static int get_perm (const char *instr)
static struct eventqentgrab_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 eventqentunref_event (struct eventqent *e)
static struct mansession_sessionunref_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_containersessions = 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


Detailed Description

The Asterisk Management Interface - AMI.

Author:
Mark Spencer <markster@digium.com>
ExtRef:
OpenSSL http://www.openssl.org - for AMI/SSL
At the moment this file contains a number of functions, namely:

manager.conf

Definition in file manager.c.


Define Documentation

#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=\"\">-----&gt;</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().


Enumeration Type Documentation

END Doxygen group

Enumerator:
FORMAT_RAW 
FORMAT_HTML 
FORMAT_XML 

Definition at line 4363 of file manager.c.

04363                    {
04364    FORMAT_RAW,
04365    FORMAT_HTML,
04366    FORMAT_XML,
04367 };


Function Documentation

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.

Return values:
0 success
non-zero failure
Since:
1.6.1

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.

Return values:
pointer to the datastore if found
NULL if not found
Since:
1.6.1

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.

Return values:
0 success
non-zero failure
Since:
1.6.1

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.

Parameters:
ident session identity
perm permission mask to verify
Return values:
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.

Parameters:
ident session identity
perm permission mask to verify
Return values:
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&trade; 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]

Note:
There is approximately a 1 in 1.8E19 chance that the following calculation will produce 0, which is an invalid ID, but due to the properties of the rand() function (and the constantcy of s), that won't happen twice in a row.

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=\"\">-----&gt;</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&trade; 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, "&lt;");
04534          dst += 4;
04535          space -= 4;
04536          break;
04537       case '>':
04538          strcpy(dst, "&gt;");
04539          dst += 4;
04540          space -= 4;
04541          break;
04542       case '\"':
04543          strcpy(dst, "&quot;");
04544          dst += 6;
04545          space -= 6;
04546          break;
04547       case '\'':
04548          strcpy(dst, "&apos;");
04549          dst += 6;
04550          space -= 6;
04551          break;
04552       case '&':
04553          strcpy(dst, "&amp;");
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 }


Variable Documentation

struct ast_http_uri amanageruri [static]

Definition at line 5344 of file manager.c.

Referenced by __init_manager().

struct ast_http_uri amanagerxmluri [static]

Definition at line 5353 of file manager.c.

Referenced by __init_manager().

Definition at line 5375 of file manager.c.

Referenced by __init_manager().

struct ast_tls_config ami_tls_cfg [static]

Definition at line 5374 of file manager.c.

Referenced by __init_manager().

Definition at line 5386 of file manager.c.

Referenced by __init_manager().

struct ast_http_uri arawmanuri [static]

Definition at line 5335 of file manager.c.

Referenced by __init_manager().

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]

Definition at line 5302 of file manager.c.

Referenced by __init_manager().

struct ast_http_uri managerxmluri [static]

Definition at line 5310 of file manager.c.

Referenced by __init_manager().

struct ast_http_uri rawmanuri [static]

Definition at line 5294 of file manager.c.

Referenced by __init_manager().

int registered = 0 [static]

Definition at line 5362 of file manager.c.

Referenced by __init_manager().

int webregged = 0 [static]

Definition at line 5363 of file manager.c.

Referenced by __init_manager().

const char* words[AST_MAX_CMD_LEN]

Definition at line 760 of file manager.c.

Referenced by check_blacklist().


Generated on Wed Oct 28 13:33:09 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6