manager.c File Reference

The Asterisk Management Interface - AMI. More...

#include "asterisk.h"
#include "asterisk/paths.h"
#include <ctype.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <regex.h>
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/manager.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/callerid.h"
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/md5.h"
#include "asterisk/acl.h"
#include "asterisk/utils.h"
#include "asterisk/tcptls.h"
#include "asterisk/http.h"
#include "asterisk/ast_version.h"
#include "asterisk/threadstorage.h"
#include "asterisk/linkedlists.h"
#include "asterisk/term.h"
#include "asterisk/astobj2.h"
#include "asterisk/features.h"
#include "asterisk/security_events.h"
#include "asterisk/aoc.h"
#include "asterisk/strings.h"
#include "asterisk/stringfields.h"
#include "asterisk/presencestate.h"
#include "asterisk/stasis_message_router.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_bridges.h"
#include "asterisk/test.h"
#include "asterisk/json.h"
#include "asterisk/bridge.h"
#include "asterisk/features_config.h"
#include "asterisk/rtp_engine.h"
#include "asterisk/format_cache.h"
#include "asterisk/translate.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
 In case you didn't read that giant block of text above the mansession_session struct, the struct mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data. More...
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 and astman_send_*_va
#define DEFAULT_REALM   "asterisk"
#define EVENT_FLAG_SHUTDOWN   -1
 Fake event class used to end sessions at shutdown.
#define FORMAT   " %-25.25s %-15.55s\n"
#define FORMAT2   " %-25.25s %-15d\n"
#define GET_HEADER_FIRST_MATCH   0
#define GET_HEADER_LAST_MATCH   1
#define GET_HEADER_SKIP_EMPTY   2
#define HSMC_FORMAT   " %-*.*s %-.*s\n"
#define HSMCONN_FORMAT1   " %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
#define HSMCONN_FORMAT2   " %-15.15s %-55.55s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
#define MANAGER_EVENT_BUF_INITSIZE   256
#define MAX_AUTH_PERM_STRING   150
#define MAX_BLACKLIST_CMD_LEN   2
 Descriptor for a manager session, either on the AMI socket or over HTTP.
#define MAX_VARS   128
#define MGR_SHOW_TERMINAL_WIDTH   80
#define MSG_MOREDATA   ((char *)astman_send_response)
#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  add_filter_result { FILTER_SUCCESS, FILTER_ALLOC_FAILED, FILTER_COMPILE_FAIL }
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, FAILURE_TEMPLATE
}
enum  mansession_message_parsing { MESSAGE_OKAY, MESSAGE_LINE_TOO_LONG }
enum  output_format { FORMAT_RAW, FORMAT_HTML, FORMAT_XML }

Functions

int __ast_manager_event_multichan (int category, const char *event, int chancount, struct ast_channel **chans, const char *file, int line, const char *func, const char *fmt,...)
static const char * __astman_get_header (const struct message *m, char *var, int mode)
 Return a matching header value.
static void __fini_actions (void)
static void __fini_all_events (void)
static void __fini_manager_hooks (void)
static void __fini_users (void)
static void __init_actions (void)
static void __init_all_events (void)
static void __init_astman_append_buf (void)
 thread local buffer for astman_append
static int __init_manager (int reload, int by_external_config)
static void __init_manager_event_buf (void)
static void __init_manager_hooks (void)
static void __init_userevent_buf (void)
static void __init_users (void)
static void acl_change_stasis_cb (void *data, struct stasis_subscription *sub, struct stasis_message *message)
static void acl_change_stasis_subscribe (void)
static void acl_change_stasis_unsubscribe (void)
static int action_aocmessage (struct mansession *s, const struct message *m)
static int action_atxfer (struct mansession *s, const struct message *m)
static int action_blind_transfer (struct mansession *s, const struct message *m)
static int action_challenge (struct mansession *s, const struct message *m)
static int action_command (struct mansession *s, const struct message *m)
 Manager command "command" - execute CLI command.
static int action_coresettings (struct mansession *s, const struct message *m)
 Show PBX core settings information.
static int action_coreshowchannels (struct mansession *s, const struct message *m)
 Manager command "CoreShowChannels" - List currently defined channels and some information about them.
static int action_corestatus (struct mansession *s, const struct message *m)
 Show PBX core status information.
static int action_createconfig (struct mansession *s, const struct message *m)
static void action_destroy (void *obj)
static int action_events (struct mansession *s, const struct message *m)
static int action_extensionstate (struct mansession *s, const struct message *m)
static int action_filter (struct mansession *s, const struct message *m)
 Manager command to add an event filter to a manager session.
static struct manager_actionaction_find (const char *name)
static int action_getconfig (struct mansession *s, const struct message *m)
static int action_getconfigjson (struct mansession *s, const struct message *m)
static int action_getvar (struct mansession *s, const struct message *m)
static int action_hangup (struct mansession *s, const struct message *m)
static int action_listcategories (struct mansession *s, const struct message *m)
static int action_listcommands (struct mansession *s, const struct message *m)
static int action_loggerrotate (struct mansession *s, const struct message *m)
 Manager command "LoggerRotate" - reloads and rotates the logger in the same manner as the CLI command 'logger rotate'.
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_presencestate (struct mansession *s, const struct message *m)
static int action_redirect (struct mansession *s, const struct message *m)
 action_redirect: The redirect manager command
static int action_reload (struct mansession *s, const struct message *m)
 Send a reload event.
static int action_sendtext (struct mansession *s, const struct message *m)
static int action_setvar (struct mansession *s, const struct message *m)
static int action_status (struct mansession *s, const struct message *m)
 Manager "status" command to show channels.
static int action_timeout (struct mansession *s, const struct message *m)
static int action_updateconfig (struct mansession *s, const struct message *m)
static int action_userevent (struct mansession *s, const struct message *m)
static int action_waitevent (struct mansession *s, const struct message *m)
static struct eventqentadvance_event (struct eventqent *e)
static AO2_GLOBAL_OBJ_STATIC (event_docs)
 A container of event documentation nodes.
static AO2_GLOBAL_OBJ_STATIC (mgr_sessions)
static int aocmessage_get_unit_entry (const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
static void append_channel_vars (struct ast_str **pbuf, struct ast_channel *chan)
static int append_event (const char *str, int category)
 events are appended to a queue from where they can be dispatched to clients.
int ast_hook_send_action (struct manager_custom_hook *hook, const char *msg)
 access for hooks to send action messages to ami
static int ast_instring (const char *bigstr, const char *smallstr, const char delim)
struct ast_manager_event_blobast_manager_event_blob_create (int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
 Construct a ast_manager_event_blob.
struct stasis_message_routerast_manager_get_message_router (void)
 Get the stasis_message_router for AMI.
struct stasis_topicast_manager_get_topic (void)
 Get the Stasis Message Bus API topic for AMI.
void ast_manager_publish_event (const char *type, int class_type, struct ast_json *obj)
 Publish an event to AMI.
int ast_manager_register2 (const char *action, int auth, int(*func)(struct mansession *s, const struct message *m), struct ast_module *module, 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)
struct ast_strast_manager_str_from_json_object (struct ast_json *blob, key_exclusion_cb exclusion_cb)
 Convert a JSON object into an AMI compatible string.
int ast_manager_unregister (const char *action)
 support functions to register/unregister AMI action handlers,
void ast_manager_unregister_hook (struct manager_custom_hook *hook)
 Delete a custom hook to be called when an event is fired.
int ast_str_append_event_header (struct ast_str **fields_string, const char *header, const char *value)
 append an event header to an ast string
void astman_append (struct mansession *s, const char *fmt,...)
static void astman_append_json (struct mansession *s, const char *str)
int astman_datastore_add (struct mansession *s, struct ast_datastore *datastore)
 Add a datastore to a session.
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)
 Return the first matching variable from an array.
struct ast_variableastman_get_variables (const struct message *m)
 Get a linked list of the Variable: headers.
struct ast_variableastman_get_variables_order (const struct message *m, enum variable_orders order)
 Get a linked list of the Variable: headers with order specified.
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_error_va (struct mansession *s, const struct message *m, const char *fmt,...)
 Send error in manager transaction (with va_args support).
void astman_send_list_complete_end (struct mansession *s)
 End the list complete event.
void astman_send_list_complete_start (struct mansession *s, const struct message *m, const char *event_name, int count)
 Start the list complete event.
void astman_send_listack (struct mansession *s, const struct message *m, char *msg, char *listflag)
 Send ack in manager transaction to begin a list.
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)
 send a response with an optional message, and terminate it with an empty line. m is used only to grab the 'ActionID' field.
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, const struct ast_sockaddr *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. Note that the EVENT_FLAG_ALL authority will always be returned.
static int blackfilter_cmp_fn (void *obj, void *arg, void *data, int flags)
static struct mansession_sessionbuild_mansession (const struct ast_sockaddr *addr)
 Allocate manager session structure and add it to the list of sessions.
static int check_blacklist (const char *cmd)
int check_manager_enabled (void)
 Check if AMI is enabled.
static int check_manager_session_inuse (const char *name)
int check_webmanager_enabled (void)
 Check if AMI/HTTP is enabled.
static void close_mansession_file (struct mansession *s)
static void destroy_fast_originate_helper (struct fast_originate_helper *doomed)
static int do_message (struct mansession *s)
static void event_filter_destructor (void *obj)
static void * fast_originate (void *data)
static struct mansession_sessionfind_session (uint32_t ident, int incinuse)
static struct mansession_sessionfind_session_by_nonce (const char *username, unsigned long nonce, int *stale)
static int function_amiclient (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 ${AMI_CLIENT()} Dialplan function - reads manager client data
static int function_capable_string_allowed_with_auths (const char *evaluating, int writepermlist)
 Checks to see if a string which can be used to evaluate functions should be rejected.
static void generate_status (struct mansession *s, struct ast_channel *chan, char **vars, int varc, int all_variables, char *id_text, int *count)
static int generic_http_callback (struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, const struct ast_sockaddr *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_manager_sessions_cb (void *obj, void *arg, void *data, int flags)
 Get number of logged in sessions for a login 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_manager_show_settings (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager show settings.
static char * handle_mandebug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void handle_parse_error (struct mansession *s, struct message *m, char *error)
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)
 helper function for action_updateconfig
int init_manager (void)
 Called by Asterisk initialization.
static void json_escape (char *out, const char *in)
static void load_channelvars (struct ast_variable *var)
static struct ast_variableman_do_variable_value (struct ast_variable *head, const char *hdr_val)
static enum add_filter_result manager_add_filter (const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters)
 Add an event filter to a manager session.
static void manager_default_msg_cb (void *data, struct stasis_subscription *sub, struct stasis_message *message)
static int manager_displayconnects (struct mansession_session *session)
 Get displayconnects config option.
static void manager_event_blob_dtor (void *obj)
static void manager_free_user (struct ast_manager_user *user)
static void manager_generic_msg_cb (void *data, struct stasis_subscription *sub, struct stasis_message *message)
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 void manager_json_array_with_key (struct ast_json *obj, const char *key, size_t index, struct ast_str **res, key_exclusion_cb exclusion_cb)
static void manager_json_obj_with_key (struct ast_json *obj, const char *key, const char *parent_key, struct ast_str **res, key_exclusion_cb exclusion_cb)
static void manager_json_to_ast_str (struct ast_json *obj, const char *key, struct ast_str **res, key_exclusion_cb exclusion_cb)
static void manager_json_value_str_append (struct ast_json *value, const char *key, struct ast_str **res)
static int manager_modulecheck (struct mansession *s, const struct message *m)
 Manager function to check if module is loaded.
static int manager_moduleload (struct mansession *s, const struct message *m)
static void manager_set_defaults (void)
static void manager_shutdown (void)
static int manager_state_cb (char *context, char *exten, struct ast_state_cb_info *info, void *data)
static int manager_subscriptions_init (void)
 Initialize all Stasis Message Bus API topics and routers used by the various sub-components of AMI.
static int mansession_cmp_fn (void *obj, void *arg, int flags)
static enum ast_transport mansession_get_transport (const struct mansession *s)
static void mansession_lock (struct mansession *s)
 Lock the 'mansession' structure.
static void mansession_unlock (struct mansession *s)
 Unlock the 'mansession' structure.
static int match_filter (struct mansession *s, char *eventdata)
static int mxml_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static void print_event_instance (struct ast_cli_args *a, struct ast_xml_doc_item *instance)
static int process_events (struct mansession *s)
static int process_message (struct mansession *s, const struct message *m)
 Process an AMI message, performing desired action. Return 0 on success, -1 on error that require the session to be destroyed.
static void process_output (struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
static void purge_events (void)
static void purge_old_stuff (void *data)
 cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most
static void purge_sessions (int n_max)
 remove at most n_max stale session from the list.
static int rawman_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
int reload_manager (void)
 Called by Asterisk module functions and the CLI command.
static void report_auth_success (const struct mansession *s)
static void report_failed_acl (const struct mansession *s, const char *username)
static void report_failed_challenge_response (const struct mansession *s, const char *response, const char *expected_response)
static void report_inval_password (const struct mansession *s, const char *username)
static void report_invalid_user (const struct mansession *s, const char *username)
static void report_req_bad_format (const struct mansession *s, const char *action)
static void report_req_not_allowed (const struct mansession *s, const char *action)
static void report_session_limit (const struct mansession *s)
static int send_string (struct mansession *s, char *string)
static void session_destroy (struct mansession_session *s)
static void session_destructor (void *obj)
static void * session_do (void *data)
 The body of the individual manager session. Call get_input() to read one line at a time (or be woken up on new events), collect the lines in a message until found an empty line, and execute the request. In any case, deliver events asynchronously through process_events() (called from here if no line is available, or at the end of process_message(). ).
static int set_eventmask (struct mansession *s, const char *eventmask)
 Rather than braindead on,off this now can also accept a specific int mask value or a ',' delim list of mask strings (the same as manager.conf) -anthm.
static int strings_to_mask (const char *string)
static int subscribe_all (void)
static struct mansession_sessionunref_mansession (struct mansession_session *s)
 Unreference manager session object. If no more references, then go ahead and delete it.
static const char * user_authority_to_str (int authority, struct ast_str **res)
 Convert authority code to a list of options for a user. This will only display those authority codes that have an explicit match on authority.
static int variable_count_cmp_fn (void *obj, void *vstr, int flags)
static int variable_count_hash_fn (const void *vvc, const int flags)
static int whitefilter_cmp_fn (void *obj, void *arg, void *data, int flags)
static void xml_copy_escape (struct ast_str **out, const char *src, int mode)
static void xml_translate (struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
 Convert the input into XML or HTML. The input is supposed to be a sequence of lines of the form Name: value optionally followed by a blob of unformatted text. A blank line is a section separator. Basically, this is a mixture of the format of Manager Interface and CLI commands. The unformatted text is considered as a single value of a field named 'Opaque-data'.
 STASIS_MESSAGE_TYPE_DEFN (ast_manager_get_generic_type)
 Define AMI message types.

Variables

static struct stasis_subscriptionacl_change_sub
static int allowmultiplelogin = 1
static struct ast_http_uri amanageruri
static struct ast_http_uri amanagerxmluri
static struct
ast_tcptls_session_args 
ami_desc
static struct ast_tls_config ami_tls_cfg
static struct
ast_tcptls_session_args 
amis_desc
static struct ast_http_uri arawmanuri
static struct ast_threadstorage astman_append_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_astman_append_buf , .custom_init = NULL , }
static int authlimit
static int authtimeout
static int broken_events_action = 0
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 char * manager_channelvars
static int manager_debug = 0
static int manager_enabled = 0
static struct ast_threadstorage manager_event_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_manager_event_buf , .custom_init = NULL , }
static struct stasis_topicmanager_topic
 A stasis_topic that all topics AMI cares about will be forwarded to.
static struct ast_custom_function managerclient_function
 description of AMI_CLIENT dialplan function
static struct ast_http_uri manageruri
static struct ast_http_uri managerxmluri
static struct permalias perms []
static struct ast_http_uri rawmanuri
static struct stasis_forwardrtp_topic_forwarder
 The stasis_subscription for forwarding the RTP topic to the AMI topic.
static struct stasis_forwardsecurity_topic_forwarder
 The stasis_subscription for forwarding the Security topic to the AMI topic.
static struct
stasis_message_router
stasis_router
 The stasis_message_router for all Stasis Message Bus API messages.
static int subscribed = 0
static int timestampevents
static int unauth_sessions = 0
static struct ast_threadstorage userevent_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_userevent_buf , .custom_init = NULL , }
static int webmanager_enabled = 0
static int webregged = 0


Detailed Description

The Asterisk Management Interface - AMI.

Author:
Mark Spencer <markster@digium.com>
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 FORMAT   " %-25.25s %-15.55s\n"

#define FORMAT2   " %-25.25s %-15d\n"

#define HSMC_FORMAT   " %-*.*s %-.*s\n"

Referenced by handle_showmancmds().

#define HSMCONN_FORMAT1   " %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"

Referenced by handle_showmanconn().

#define HSMCONN_FORMAT2   " %-15.15s %-55.55s %-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 6903 of file manager.c.

06903                    {
06904    FORMAT_RAW,
06905    FORMAT_HTML,
06906    FORMAT_XML,
06907 };


Function Documentation

static int __init_manager ( int  reload,
int  by_external_config 
) [static]

Definition at line 8601 of file manager.c.

References __ast_custom_function_register(), ast_manager_user::a1_hash, ast_manager_user::acl, acl_change_stasis_subscribe(), acl_change_stasis_unsubscribe(), action_aocmessage(), action_atxfer(), action_blind_transfer(), action_challenge(), action_command(), action_coresettings(), action_coreshowchannels(), action_corestatus(), action_createconfig(), action_events(), action_extensionstate(), action_filter(), action_getconfig(), action_getconfigjson(), action_getvar(), action_hangup(), action_listcategories(), action_listcommands(), action_loggerrotate(), action_login(), action_logoff(), action_mailboxcount(), action_mailboxstatus(), action_originate(), action_ping(), action_presencestate(), action_redirect(), action_reload(), action_sendtext(), action_setvar(), action_status(), action_timeout(), action_updateconfig(), action_userevent(), action_waitevent(), ast_manager_user::allowmultiplelogin, amanageruri, amanagerxmluri, ami_desc, ami_tls_cfg, amis_desc, ao2_container_alloc, ao2_global_obj_replace_unref, ao2_ref, ao2_t_callback, ao2_t_global_obj_replace_unref, ao2_t_ref, append_event(), arawmanuri, ARRAY_LEN, ast_append_acl(), ast_calloc, ast_category_browse(), ast_cli_register_multiple(), ast_config_destroy(), ast_config_load2(), ast_copy_string(), ast_debug, ast_extension_state_add(), ast_free, ast_free_acl_list(), ast_http_uri_link(), ast_http_uri_unlink(), AST_LIST_INSERT_TAIL, ast_log, ast_manager_get_generic_type(), ast_manager_register_xml_core, ast_md5_hash(), ast_parse_arg(), ast_register_cleanup(), 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_sockaddr_copy(), ast_sockaddr_isnull(), ast_sockaddr_parse(), ast_sockaddr_port, ast_sockaddr_set_port, ast_sockaddr_stringify_addr(), ast_ssl_setup(), ast_strdup, ast_strlen_zero, ast_tcptls_server_start(), ast_tcptls_server_stop(), ast_tls_read_conf(), ast_true(), ast_variable_browse(), ast_variable_new(), ast_variable_retrieve(), ast_variables_destroy(), ast_manager_user::blackfilters, ast_manager_user::chanvars, cli_manager, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_MANAGER_PORT, DEFAULT_MANAGER_TLS_PORT, ast_manager_user::displayconnects, ast_tls_config::enabled, EVENT_FLAG_AOC, EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, EVENT_FLAG_CONFIG, EVENT_FLAG_ORIGINATE, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, get_manager_by_name_locked(), get_perm(), global_realm, ast_manager_user::keep, ast_variable::lineno, load_channelvars(), ast_tcptls_session_args::local_address, LOG_ERROR, LOG_NOTICE, LOG_WARNING, manager_add_filter(), manager_free_user(), manager_modulecheck(), manager_moduleload(), manager_set_defaults(), manager_shutdown(), manager_state_cb(), manager_topic, managerclient_function, manageruri, managerxmluri, mansession_cmp_fn(), ast_variable::name, ast_variable::next, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, PARSE_ADDR, PARSE_IN_RANGE, PARSE_PORT_IGNORE, PARSE_UINT32, rawmanuri, ast_manager_user::readperm, ast_manager_user::secret, stasis_forward_all(), STASIS_MESSAGE_TYPE_INIT, stasis_topic_create(), subscribe_all(), ast_tcptls_session_args::tls_cfg, ast_manager_user::username, value, ast_variable::value, var, webregged, ast_manager_user::whitefilters, ast_manager_user::writeperm, and ast_manager_user::writetimeout.

Referenced by acl_change_stasis_cb(), init_manager(), and reload_manager().

08602 {
08603    struct ast_config *ucfg = NULL, *cfg = NULL;
08604    const char *val;
08605    char *cat = NULL;
08606    int newhttptimeout = 60;
08607    struct ast_manager_user *user = NULL;
08608    struct ast_variable *var;
08609    struct ast_flags config_flags = { (reload && !by_external_config) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
08610    char a1[256];
08611    char a1_hash[256];
08612    struct ast_sockaddr ami_desc_local_address_tmp;
08613    struct ast_sockaddr amis_desc_local_address_tmp;
08614    int tls_was_enabled = 0;
08615    int acl_subscription_flag = 0;
08616 
08617    if (!reload) {
08618       struct ao2_container *sessions;
08619 #ifdef AST_XML_DOCS
08620       struct ao2_container *temp_event_docs;
08621 #endif
08622       int res;
08623 
08624       ast_register_cleanup(manager_shutdown);
08625 
08626       res = STASIS_MESSAGE_TYPE_INIT(ast_manager_get_generic_type);
08627       if (res != 0) {
08628          return -1;
08629       }
08630       manager_topic = stasis_topic_create("manager_topic");
08631       if (!manager_topic) {
08632          return -1;
08633       }
08634 
08635       /* Register default actions */
08636       ast_manager_register_xml_core("Ping", 0, action_ping);
08637       ast_manager_register_xml_core("Events", 0, action_events);
08638       ast_manager_register_xml_core("Logoff", 0, action_logoff);
08639       ast_manager_register_xml_core("Login", 0, action_login);
08640       ast_manager_register_xml_core("Challenge", 0, action_challenge);
08641       ast_manager_register_xml_core("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
08642       ast_manager_register_xml_core("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
08643       ast_manager_register_xml_core("Setvar", EVENT_FLAG_CALL, action_setvar);
08644       ast_manager_register_xml_core("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
08645       ast_manager_register_xml_core("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
08646       ast_manager_register_xml_core("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
08647       ast_manager_register_xml_core("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
08648       ast_manager_register_xml_core("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
08649       ast_manager_register_xml_core("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
08650       ast_manager_register_xml_core("Redirect", EVENT_FLAG_CALL, action_redirect);
08651       ast_manager_register_xml_core("Atxfer", EVENT_FLAG_CALL, action_atxfer);
08652       ast_manager_register_xml_core("Originate", EVENT_FLAG_ORIGINATE, action_originate);
08653       ast_manager_register_xml_core("Command", EVENT_FLAG_COMMAND, action_command);
08654       ast_manager_register_xml_core("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
08655       ast_manager_register_xml_core("PresenceState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_presencestate);
08656       ast_manager_register_xml_core("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
08657       ast_manager_register_xml_core("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
08658       ast_manager_register_xml_core("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
08659       ast_manager_register_xml_core("ListCommands", 0, action_listcommands);
08660       ast_manager_register_xml_core("SendText", EVENT_FLAG_CALL, action_sendtext);
08661       ast_manager_register_xml_core("UserEvent", EVENT_FLAG_USER, action_userevent);
08662       ast_manager_register_xml_core("WaitEvent", 0, action_waitevent);
08663       ast_manager_register_xml_core("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
08664       ast_manager_register_xml_core("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
08665       ast_manager_register_xml_core("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
08666       ast_manager_register_xml_core("LoggerRotate", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_loggerrotate);
08667       ast_manager_register_xml_core("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
08668       ast_manager_register_xml_core("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
08669       ast_manager_register_xml_core("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
08670       ast_manager_register_xml_core("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
08671       ast_manager_register_xml_core("Filter", EVENT_FLAG_SYSTEM, action_filter);
08672       ast_manager_register_xml_core("BlindTransfer", EVENT_FLAG_CALL, action_blind_transfer);
08673 
08674 #ifdef TEST_FRAMEWORK
08675       test_suite_forwarder = stasis_forward_all(ast_test_suite_topic(), manager_topic);
08676 #endif
08677 
08678       ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
08679       __ast_custom_function_register(&managerclient_function, NULL);
08680       ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
08681 
08682       /* Append placeholder event so master_eventq never runs dry */
08683       if (append_event("Event: Placeholder\r\n\r\n", 0)) {
08684          return -1;
08685       }
08686 
08687 #ifdef AST_XML_DOCS
08688       temp_event_docs = ast_xmldoc_build_documentation("managerEvent");
08689       if (temp_event_docs) {
08690          ao2_t_global_obj_replace_unref(event_docs, temp_event_docs, "Toss old event docs");
08691          ao2_t_ref(temp_event_docs, -1, "Remove creation ref - container holds only ref now");
08692       }
08693 #endif
08694 
08695       /* If you have a NULL hash fn, you only need a single bucket */
08696       sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn);
08697       if (!sessions) {
08698          return -1;
08699       }
08700       ao2_global_obj_replace_unref(mgr_sessions, sessions);
08701       ao2_ref(sessions, -1);
08702 
08703       /* Initialize all settings before first configuration load. */
08704       manager_set_defaults();
08705    }
08706 
08707    cfg = ast_config_load2("manager.conf", "manager", config_flags);
08708    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
08709       return 0;
08710    } else if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
08711       ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid.\n");
08712       return 0;
08713    }
08714 
08715    /* If this wasn't performed due to a forced reload (because those can be created by ACL change events, we need to unsubscribe to ACL change events. */
08716    if (!by_external_config) {
08717       acl_change_stasis_unsubscribe();
08718    }
08719 
08720    if (reload) {
08721       /* Reset all settings before reloading configuration */
08722       tls_was_enabled = ami_tls_cfg.enabled;
08723       manager_set_defaults();
08724    }
08725 
08726    ast_sockaddr_parse(&ami_desc_local_address_tmp, "[::]", 0);
08727    ast_sockaddr_set_port(&ami_desc_local_address_tmp, DEFAULT_MANAGER_PORT);
08728 
08729    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
08730       val = var->value;
08731 
08732       /* read tls config options while preventing unsupported options from being set */
08733       if (strcasecmp(var->name, "tlscafile")
08734          && strcasecmp(var->name, "tlscapath")
08735          && strcasecmp(var->name, "tlscadir")
08736          && strcasecmp(var->name, "tlsverifyclient")
08737          && strcasecmp(var->name, "tlsdontverifyserver")
08738          && strcasecmp(var->name, "tlsclientmethod")
08739          && strcasecmp(var->name, "sslclientmethod")
08740          && !ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
08741          continue;
08742       }
08743 
08744       if (!strcasecmp(var->name, "enabled")) {
08745          manager_enabled = ast_true(val);
08746       } else if (!strcasecmp(var->name, "webenabled")) {
08747          webmanager_enabled = ast_true(val);
08748       } else if (!strcasecmp(var->name, "port")) {
08749          int bindport;
08750          if (ast_parse_arg(val, PARSE_UINT32|PARSE_IN_RANGE, &bindport, 1024, 65535)) {
08751             ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
08752          }
08753          ast_sockaddr_set_port(&ami_desc_local_address_tmp, bindport);
08754       } else if (!strcasecmp(var->name, "bindaddr")) {
08755          /* remember port if it has already been set */
08756          int setport = ast_sockaddr_port(&ami_desc_local_address_tmp);
08757 
08758          if (ast_parse_arg(val, PARSE_ADDR|PARSE_PORT_IGNORE, NULL)) {
08759             ast_log(LOG_WARNING, "Invalid address '%s' specified, default '%s' will be used\n", val,
08760                   ast_sockaddr_stringify_addr(&ami_desc_local_address_tmp));
08761          } else {
08762             ast_sockaddr_parse(&ami_desc_local_address_tmp, val, PARSE_PORT_IGNORE);
08763          }
08764 
08765          if (setport) {
08766             ast_sockaddr_set_port(&ami_desc_local_address_tmp, setport);
08767          }
08768 
08769       } else if (!strcasecmp(var->name, "brokeneventsaction")) {
08770          broken_events_action = ast_true(val);
08771       } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
08772          allowmultiplelogin = ast_true(val);
08773       } else if (!strcasecmp(var->name, "displayconnects")) {
08774          displayconnects = ast_true(val);
08775       } else if (!strcasecmp(var->name, "timestampevents")) {
08776          timestampevents = ast_true(val);
08777       } else if (!strcasecmp(var->name, "debug")) {
08778          manager_debug = ast_true(val);
08779       } else if (!strcasecmp(var->name, "httptimeout")) {
08780          newhttptimeout = atoi(val);
08781       } else if (!strcasecmp(var->name, "authtimeout")) {
08782          int timeout = atoi(var->value);
08783 
08784          if (timeout < 1) {
08785             ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
08786          } else {
08787             authtimeout = timeout;
08788          }
08789       } else if (!strcasecmp(var->name, "authlimit")) {
08790          int limit = atoi(var->value);
08791 
08792          if (limit < 1) {
08793             ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
08794          } else {
08795             authlimit = limit;
08796          }
08797       } else if (!strcasecmp(var->name, "channelvars")) {
08798          load_channelvars(var);
08799       } else {
08800          ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
08801             var->name, val);
08802       }
08803    }
08804 
08805    if (manager_enabled && !subscribed) {
08806       if (subscribe_all() != 0) {
08807          ast_log(LOG_ERROR, "Manager subscription error\n");
08808          return -1;
08809       }
08810    }
08811 
08812    ast_sockaddr_copy(&amis_desc_local_address_tmp, &amis_desc.local_address);
08813 
08814    /* if the amis address has not been set, default is the same as non secure ami */
08815    if (ast_sockaddr_isnull(&amis_desc_local_address_tmp)) {
08816       ast_sockaddr_copy(&amis_desc_local_address_tmp, &ami_desc_local_address_tmp);
08817    }
08818 
08819    /* if the amis address was not set, it will have non-secure ami port set; if
08820       amis address was set, we need to check that a port was set or not, if not
08821       use the default tls port */
08822    if (ast_sockaddr_port(&amis_desc_local_address_tmp) == 0 ||
08823          (ast_sockaddr_port(&ami_desc_local_address_tmp) == ast_sockaddr_port(&amis_desc_local_address_tmp))) {
08824 
08825       ast_sockaddr_set_port(&amis_desc_local_address_tmp, DEFAULT_MANAGER_TLS_PORT);
08826    }
08827 
08828    if (manager_enabled) {
08829       ast_sockaddr_copy(&ami_desc.local_address, &ami_desc_local_address_tmp);
08830       ast_sockaddr_copy(&amis_desc.local_address, &amis_desc_local_address_tmp);
08831    }
08832 
08833    AST_RWLIST_WRLOCK(&users);
08834 
08835    /* First, get users from users.conf */
08836    ucfg = ast_config_load2("users.conf", "manager", config_flags);
08837    if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
08838       const char *hasmanager;
08839       int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
08840 
08841       while ((cat = ast_category_browse(ucfg, cat))) {
08842          if (!strcasecmp(cat, "general")) {
08843             continue;
08844          }
08845 
08846          hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
08847          if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
08848             const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
08849             const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
08850             const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
08851             const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
08852             const char *user_allowmultiplelogin = ast_variable_retrieve(ucfg, cat, "allowmultiplelogin");
08853             const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
08854 
08855             /* Look for an existing entry,
08856              * if none found - create one and add it to the list
08857              */
08858             if (!(user = get_manager_by_name_locked(cat))) {
08859                if (!(user = ast_calloc(1, sizeof(*user)))) {
08860                   break;
08861                }
08862 
08863                /* Copy name over */
08864                ast_copy_string(user->username, cat, sizeof(user->username));
08865                /* Insert into list */
08866                AST_LIST_INSERT_TAIL(&users, user, list);
08867                user->acl = NULL;
08868                user->keep = 1;
08869                user->readperm = -1;
08870                user->writeperm = -1;
08871                /* Default displayconnect from [general] */
08872                user->displayconnects = displayconnects;
08873                /* Default allowmultiplelogin from [general] */
08874                user->allowmultiplelogin = allowmultiplelogin;
08875                user->writetimeout = 100;
08876             }
08877 
08878             if (!user_secret) {
08879                user_secret = ast_variable_retrieve(ucfg, "general", "secret");
08880             }
08881             if (!user_read) {
08882                user_read = ast_variable_retrieve(ucfg, "general", "read");
08883             }
08884             if (!user_write) {
08885                user_write = ast_variable_retrieve(ucfg, "general", "write");
08886             }
08887             if (!user_displayconnects) {
08888                user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
08889             }
08890             if (!user_allowmultiplelogin) {
08891                user_allowmultiplelogin = ast_variable_retrieve(ucfg, "general", "allowmultiplelogin");
08892             }
08893             if (!user_writetimeout) {
08894                user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
08895             }
08896 
08897             if (!ast_strlen_zero(user_secret)) {
08898                ast_free(user->secret);
08899                user->secret = ast_strdup(user_secret);
08900             }
08901 
08902             if (user_read) {
08903                user->readperm = get_perm(user_read);
08904             }
08905             if (user_write) {
08906                user->writeperm = get_perm(user_write);
08907             }
08908             if (user_displayconnects) {
08909                user->displayconnects = ast_true(user_displayconnects);
08910             }
08911             if (user_allowmultiplelogin) {
08912                user->allowmultiplelogin = ast_true(user_allowmultiplelogin);
08913             }
08914             if (user_writetimeout) {
08915                int value = atoi(user_writetimeout);
08916                if (value < 100) {
08917                   ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value);
08918                } else {
08919                   user->writetimeout = value;
08920                }
08921             }
08922          }
08923       }
08924       ast_config_destroy(ucfg);
08925    }
08926 
08927    /* cat is NULL here in any case */
08928 
08929    while ((cat = ast_category_browse(cfg, cat))) {
08930       struct ast_acl_list *oldacl;
08931 
08932       if (!strcasecmp(cat, "general")) {
08933          continue;
08934       }
08935 
08936       /* Look for an existing entry, if none found - create one and add it to the list */
08937       if (!(user = get_manager_by_name_locked(cat))) {
08938          if (!(user = ast_calloc(1, sizeof(*user)))) {
08939             break;
08940          }
08941          /* Copy name over */
08942          ast_copy_string(user->username, cat, sizeof(user->username));
08943 
08944          user->acl = NULL;
08945          user->readperm = 0;
08946          user->writeperm = 0;
08947          /* Default displayconnect from [general] */
08948          user->displayconnects = displayconnects;
08949          /* Default allowmultiplelogin from [general] */
08950          user->allowmultiplelogin = allowmultiplelogin;
08951          user->writetimeout = 100;
08952          user->whitefilters = ao2_container_alloc(1, NULL, NULL);
08953          user->blackfilters = ao2_container_alloc(1, NULL, NULL);
08954          if (!user->whitefilters || !user->blackfilters) {
08955             manager_free_user(user);
08956             break;
08957          }
08958 
08959          /* Insert into list */
08960          AST_RWLIST_INSERT_TAIL(&users, user, list);
08961       } else {
08962          ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
08963          ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
08964       }
08965 
08966       /* Make sure we keep this user and don't destroy it during cleanup */
08967       user->keep = 1;
08968       oldacl = user->acl;
08969       user->acl = NULL;
08970       ast_variables_destroy(user->chanvars);
08971 
08972       var = ast_variable_browse(cfg, cat);
08973       for (; var; var = var->next) {
08974          if (!strcasecmp(var->name, "secret")) {
08975             ast_free(user->secret);
08976             user->secret = ast_strdup(var->value);
08977          } else if (!strcasecmp(var->name, "deny") ||
08978                    !strcasecmp(var->name, "permit") ||
08979                    !strcasecmp(var->name, "acl")) {
08980             ast_append_acl(var->name, var->value, &user->acl, NULL, &acl_subscription_flag);
08981          }  else if (!strcasecmp(var->name, "read") ) {
08982             user->readperm = get_perm(var->value);
08983          }  else if (!strcasecmp(var->name, "write") ) {
08984             user->writeperm = get_perm(var->value);
08985          }  else if (!strcasecmp(var->name, "displayconnects") ) {
08986             user->displayconnects = ast_true(var->value);
08987          }  else if (!strcasecmp(var->name, "allowmultiplelogin") ) {
08988             user->allowmultiplelogin = ast_true(var->value);
08989          } else if (!strcasecmp(var->name, "writetimeout")) {
08990             int value = atoi(var->value);
08991             if (value < 100) {
08992                ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
08993             } else {
08994                user->writetimeout = value;
08995             }
08996          } else if (!strcasecmp(var->name, "setvar")) {
08997             struct ast_variable *tmpvar;
08998             char varbuf[256];
08999             char *varval;
09000             char *varname;
09001 
09002             ast_copy_string(varbuf, var->value, sizeof(varbuf));
09003             varname = varbuf;
09004 
09005             if ((varval = strchr(varname,'='))) {
09006                *varval++ = '\0';
09007                if ((tmpvar = ast_variable_new(varname, varval, ""))) {
09008                   tmpvar->next = user->chanvars;
09009                   user->chanvars = tmpvar;
09010                }
09011             }
09012          } else if (!strcasecmp(var->name, "eventfilter")) {
09013             const char *value = var->value;
09014             manager_add_filter(value, user->whitefilters, user->blackfilters);
09015          } else {
09016             ast_debug(1, "%s is an unknown option.\n", var->name);
09017          }
09018       }
09019 
09020       oldacl = ast_free_acl_list(oldacl);
09021    }
09022    ast_config_destroy(cfg);
09023 
09024    /* Check the flag for named ACL event subscription and if we need to, register a subscription. */
09025    if (acl_subscription_flag && !by_external_config) {
09026       acl_change_stasis_subscribe();
09027    }
09028 
09029    /* Perform cleanup - essentially prune out old users that no longer exist */
09030    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
09031       if (user->keep) { /* valid record. clear flag for the next round */
09032          user->keep = 0;
09033 
09034          /* Calculate A1 for Digest auth */
09035          snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
09036          ast_md5_hash(a1_hash,a1);
09037          ast_free(user->a1_hash);
09038          user->a1_hash = ast_strdup(a1_hash);
09039          continue;
09040       }
09041       /* We do not need to keep this user so take them out of the list */
09042       AST_RWLIST_REMOVE_CURRENT(list);
09043       ast_debug(4, "Pruning user '%s'\n", user->username);
09044       manager_free_user(user);
09045    }
09046    AST_RWLIST_TRAVERSE_SAFE_END;
09047 
09048    AST_RWLIST_UNLOCK(&users);
09049 
09050    if (webmanager_enabled && manager_enabled) {
09051       if (!webregged) {
09052          ast_http_uri_link(&rawmanuri);
09053          ast_http_uri_link(&manageruri);
09054          ast_http_uri_link(&managerxmluri);
09055 
09056          ast_http_uri_link(&arawmanuri);
09057          ast_http_uri_link(&amanageruri);
09058          ast_http_uri_link(&amanagerxmluri);
09059          webregged = 1;
09060       }
09061    } else {
09062       if (webregged) {
09063          ast_http_uri_unlink(&rawmanuri);
09064          ast_http_uri_unlink(&manageruri);
09065          ast_http_uri_unlink(&managerxmluri);
09066 
09067          ast_http_uri_unlink(&arawmanuri);
09068          ast_http_uri_unlink(&amanageruri);
09069          ast_http_uri_unlink(&amanagerxmluri);
09070          webregged = 0;
09071       }
09072    }
09073 
09074    if (newhttptimeout > 0) {
09075       httptimeout = newhttptimeout;
09076    }
09077 
09078    ast_tcptls_server_start(&ami_desc);
09079    if (tls_was_enabled && !ami_tls_cfg.enabled) {
09080       ast_tcptls_server_stop(&amis_desc);
09081    } else if (ast_ssl_setup(amis_desc.tls_cfg)) {
09082       ast_tcptls_server_start(&amis_desc);
09083    }
09084 
09085    return 0;
09086 }

struct ast_manager_event_blob* ast_manager_event_blob_create ( int  event_flags,
const char *  manager_event,
const char *  extra_fields_fmt,
  ... 
) [read]

Construct a ast_manager_event_blob.

Since:
12 The returned object is AO2 managed, so clean up with ao2_cleanup().
Parameters:
event_flags Flags the event should be raised with.
manager_event The event to be raised, should be a string literal.
extra_fields_fmt Format string for extra fields to include. Or NO_EXTRA_FIELDS for no extra fields.
Returns:
New ast_manager_snapshot_event object.

NULL on error.

Definition at line 9177 of file manager.c.

References ao2_alloc, ao2_cleanup, ao2_ref, ast_assert, ast_string_field_init, ast_string_field_ptr_build_va, manager_event_blob_dtor(), NULL, and RAII_VAR.

Referenced by agent_login_to_ami(), agent_logoff_to_ami(), agi_channel_to_ami(), aoc_to_ami(), attended_transfer_to_ami(), blind_transfer_to_ami(), bridge_create(), bridge_destroy(), call_pickup_to_ami(), cc_available_to_ami(), cc_callerrecalling_to_ami(), cc_callerstartmonitoring_to_ami(), cc_callerstopmonitoring_to_ami(), cc_failure_to_ami(), cc_monitorfailed_to_ami(), cc_offertimerstart_to_ami(), cc_recallcomplete_to_ami(), cc_requestacknowledged_to_ami(), cc_requested_to_ami(), channel_new_accountcode(), channel_new_callerid(), channel_new_connected_line(), channel_newexten(), channel_state_change(), dahdichannel_to_ami(), devstate_to_ami(), fake_ami(), local_message_to_ami(), multi_user_event_to_ami(), peerstatus_to_ami(), presence_state_to_ami(), queue_channel_to_ami(), queue_member_to_ami(), queue_multi_channel_to_ami(), rtcp_report_to_ami(), security_event_to_ami_blob(), session_timeout_to_ami(), system_registry_to_ami(), talking_start_to_ami(), talking_stop_to_ami(), and varset_to_ami().

09182 {
09183    RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup);
09184    va_list argp;
09185 
09186    ast_assert(extra_fields_fmt != NULL);
09187    ast_assert(manager_event != NULL);
09188 
09189    ev = ao2_alloc(sizeof(*ev), manager_event_blob_dtor);
09190    if (!ev) {
09191       return NULL;
09192    }
09193 
09194    if (ast_string_field_init(ev, 20)) {
09195       return NULL;
09196    }
09197 
09198    ev->manager_event = manager_event;
09199    ev->event_flags = event_flags;
09200 
09201    va_start(argp, extra_fields_fmt);
09202    ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt,
09203                   argp);
09204    va_end(argp);
09205 
09206    ao2_ref(ev, +1);
09207    return ev;
09208 }

int ast_str_append_event_header ( struct ast_str **  fields_string,
const char *  header,
const char *  value 
)

append an event header to an ast string

Since:
12
Parameters:
fields_string pointer to an ast_string pointer. It may be a pointer to a NULL ast_str pointer, in which case the ast_str will be initialized.
header The header being applied
value the value of the header
Return values:
0 if successful
non-zero on failure

Definition at line 9149 of file manager.c.

References ast_str_append(), and ast_str_create().

Referenced by confbridge_talking_cb(), get_admin_header(), and meetme_stasis_cb().

09151 {
09152    struct ast_str *working_str = *fields_string;
09153 
09154    if (!working_str) {
09155       working_str = ast_str_create(128);
09156       if (!working_str) {
09157          return -1;
09158       }
09159       *fields_string = working_str;
09160    }
09161 
09162    ast_str_append(&working_str, 0,
09163       "%s: %s\r\n",
09164       header, value);
09165 
09166    return 0;
09167 }

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 9110 of file manager.c.

References AST_LIST_INSERT_HEAD, mansession_session::datastores, and mansession::session.

09111 {
09112    AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
09113 
09114    return 0;
09115 }

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 9122 of file manager.c.

References AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, mansession_session::datastores, ast_datastore::info, NULL, mansession::session, and ast_datastore::uid.

09123 {
09124    struct ast_datastore *datastore = NULL;
09125 
09126    if (info == NULL)
09127       return NULL;
09128 
09129    AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
09130       if (datastore->info != info) {
09131          continue;
09132       }
09133 
09134       if (uid == NULL) {
09135          /* matched by type only */
09136          break;
09137       }
09138 
09139       if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
09140          /* Matched by type AND uid */
09141          break;
09142       }
09143    }
09144    AST_LIST_TRAVERSE_SAFE_END;
09145 
09146    return datastore;
09147 }

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 9117 of file manager.c.

References AST_LIST_REMOVE, mansession_session::datastores, and mansession::session.

09118 {
09119    return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
09120 }

int astman_is_authed ( uint32_t  ident  ) 

Determinie if a manager session ident is authenticated.

Definition at line 6992 of file manager.c.

References ao2_unlock, mansession_session::authenticated, find_session(), session, and unref_mansession().

Referenced by http_post_callback(), and static_callback().

06993 {
06994    int authed;
06995    struct mansession_session *session;
06996 
06997    if (!(session = find_session(ident, 0)))
06998       return 0;
06999 
07000    authed = (session->authenticated != 0);
07001 
07002    ao2_unlock(session);
07003    unref_mansession(session);
07004 
07005    return authed;
07006 }

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 7008 of file manager.c.

References ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, mansession_session::managerid, mansession_session::readperm, result, session, and unref_mansession().

07009 {
07010    int result = 0;
07011    struct mansession_session *session;
07012    struct ao2_container *sessions;
07013    struct ao2_iterator i;
07014 
07015    if (ident == 0) {
07016       return 0;
07017    }
07018 
07019    sessions = ao2_global_obj_ref(mgr_sessions);
07020    if (!sessions) {
07021       return 0;
07022    }
07023    i = ao2_iterator_init(sessions, 0);
07024    ao2_ref(sessions, -1);
07025    while ((session = ao2_iterator_next(&i))) {
07026       ao2_lock(session);
07027       if ((session->managerid == ident) && (session->readperm & perm)) {
07028          result = 1;
07029          ao2_unlock(session);
07030          unref_mansession(session);
07031          break;
07032       }
07033       ao2_unlock(session);
07034       unref_mansession(session);
07035    }
07036    ao2_iterator_destroy(&i);
07037 
07038    return result;
07039 }

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 7041 of file manager.c.

References ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, mansession_session::managerid, result, session, unref_mansession(), and mansession_session::writeperm.

Referenced by http_post_callback().

07042 {
07043    int result = 0;
07044    struct mansession_session *session;
07045    struct ao2_container *sessions;
07046    struct ao2_iterator i;
07047 
07048    if (ident == 0) {
07049       return 0;
07050    }
07051 
07052    sessions = ao2_global_obj_ref(mgr_sessions);
07053    if (!sessions) {
07054       return 0;
07055    }
07056    i = ao2_iterator_init(sessions, 0);
07057    ao2_ref(sessions, -1);
07058    while ((session = ao2_iterator_next(&i))) {
07059       ao2_lock(session);
07060       if ((session->managerid == ident) && (session->writeperm & perm)) {
07061          result = 1;
07062          ao2_unlock(session);
07063          unref_mansession(session);
07064          break;
07065       }
07066       ao2_unlock(session);
07067       unref_mansession(session);
07068    }
07069    ao2_iterator_destroy(&i);
07070 
07071    return result;
07072 }

static int auth_http_callback ( struct ast_tcptls_session_instance ser,
enum ast_http_method  method,
enum output_format  format,
const struct ast_sockaddr remote_address,
const char *  uri,
struct ast_variable get_params,
struct ast_variable headers 
) [static]

Definition at line 7584 of file manager.c.

References ast_manager_user::a1_hash, ast_manager_user::acl, mansession_session::addr, ao2_lock, ao2_unlock, ARRAY_LEN, ast_apply_acl(), 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_request_close_on_completion(), ast_http_send(), AST_LIST_HEAD_INIT_NOLOCK, ast_log, ast_malloc, ast_md5_hash(), ast_mutex_destroy, ast_mutex_init, ast_parse_digest(), ast_random(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_sockaddr_stringify_addr(), 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, build_mansession(), close_mansession_file(), ast_http_digest::cnonce, contenttype, d, 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(), 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, NULL, mansession_session::oldnonce, out, process_message(), process_output(), ast_http_digest::qop, mansession_session::readperm, ast_manager_user::readperm, ast_http_digest::response, mansession::session, session, session_destroy(), mansession_session::sessionstart, mansession_session::sessiontimeout, 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, and ast_manager_user::writetimeout.

Referenced by auth_manager_http_callback(), auth_mxml_http_callback(), and auth_rawman_http_callback().

07590 {
07591    struct mansession_session *session = NULL;
07592    struct mansession s = { .session = NULL, .tcptls_session = ser };
07593    struct ast_variable *v, *params = get_params;
07594    char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
07595    struct ast_str *http_header = NULL, *out = NULL;
07596    size_t result_size;
07597    struct message m = { 0 };
07598    unsigned int idx;
07599    size_t hdrlen;
07600 
07601    time_t time_now = time(NULL);
07602    unsigned long nonce = 0, nc;
07603    struct ast_http_digest d = { NULL, };
07604    struct ast_manager_user *user = NULL;
07605    int stale = 0;
07606    char resp_hash[256]="";
07607    /* Cache for user data */
07608    char u_username[80];
07609    int u_readperm;
07610    int u_writeperm;
07611    int u_writetimeout;
07612    int u_displayconnects;
07613 
07614    if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
07615       ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
07616       return 0;
07617    }
07618 
07619    /* Find "Authorization: " header */
07620    for (v = headers; v; v = v->next) {
07621       if (!strcasecmp(v->name, "Authorization")) {
07622          break;
07623       }
07624    }
07625 
07626    if (!v || ast_strlen_zero(v->value)) {
07627       goto out_401; /* Authorization Header not present - send auth request */
07628    }
07629 
07630    /* Digest found - parse */
07631    if (ast_string_field_init(&d, 128)) {
07632       ast_http_request_close_on_completion(ser);
07633       ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
07634       return 0;
07635    }
07636 
07637    if (ast_parse_digest(v->value, &d, 0, 1)) {
07638       /* Error in Digest - send new one */
07639       nonce = 0;
07640       goto out_401;
07641    }
07642    if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
07643       ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
07644       nonce = 0;
07645       goto out_401;
07646    }
07647 
07648    AST_RWLIST_WRLOCK(&users);
07649    user = get_manager_by_name_locked(d.username);
07650    if(!user) {
07651       AST_RWLIST_UNLOCK(&users);
07652       ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
07653       nonce = 0;
07654       goto out_401;
07655    }
07656 
07657    /* --- We have User for this auth, now check ACL */
07658    if (user->acl && !ast_apply_acl(user->acl, remote_address, "Manager User ACL:")) {
07659       AST_RWLIST_UNLOCK(&users);
07660       ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
07661       ast_http_request_close_on_completion(ser);
07662       ast_http_error(ser, 403, "Permission denied", "Permission denied");
07663       return 0;
07664    }
07665 
07666    /* --- We have auth, so check it */
07667 
07668    /* compute the expected response to compare with what we received */
07669    {
07670       char a2[256];
07671       char a2_hash[256];
07672       char resp[256];
07673 
07674       /* XXX Now request method are hardcoded in A2 */
07675       snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
07676       ast_md5_hash(a2_hash, a2);
07677 
07678       if (d.qop) {
07679          /* RFC 2617 */
07680          snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
07681       }  else {
07682          /* RFC 2069 */
07683          snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
07684       }
07685       ast_md5_hash(resp_hash, resp);
07686    }
07687 
07688    if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
07689       /* Something was wrong, so give the client to try with a new challenge */
07690       AST_RWLIST_UNLOCK(&users);
07691       nonce = 0;
07692       goto out_401;
07693    }
07694 
07695    /*
07696     * User are pass Digest authentication.
07697     * Now, cache the user data and unlock user list.
07698     */
07699    ast_copy_string(u_username, user->username, sizeof(u_username));
07700    u_readperm = user->readperm;
07701    u_writeperm = user->writeperm;
07702    u_displayconnects = user->displayconnects;
07703    u_writetimeout = user->writetimeout;
07704    AST_RWLIST_UNLOCK(&users);
07705 
07706    if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
07707       /*
07708        * Create new session.
07709        * While it is not in the list we don't need any locking
07710        */
07711       if (!(session = build_mansession(remote_address))) {
07712          ast_http_request_close_on_completion(ser);
07713          ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
07714          return 0;
07715       }
07716       ao2_lock(session);
07717 
07718       ast_copy_string(session->username, u_username, sizeof(session->username));
07719       session->managerid = nonce;
07720       session->last_ev = grab_last();
07721       AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
07722 
07723       session->readperm = u_readperm;
07724       session->writeperm = u_writeperm;
07725       session->writetimeout = u_writetimeout;
07726 
07727       if (u_displayconnects) {
07728          ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
07729       }
07730       session->noncetime = session->sessionstart = time_now;
07731       session->authenticated = 1;
07732    } else if (stale) {
07733       /*
07734        * Session found, but nonce is stale.
07735        *
07736        * This could be because an old request (w/old nonce) arrived.
07737        *
07738        * This may be as the result of http proxy usage (separate delay or
07739        * multipath) or in a situation where a page was refreshed too quickly
07740        * (seen in Firefox).
07741        *
07742        * In this situation, we repeat the 401 auth with the current nonce
07743        * value.
07744        */
07745       nonce = session->managerid;
07746       ao2_unlock(session);
07747       stale = 1;
07748       goto out_401;
07749    } else {
07750       sscanf(d.nc, "%30lx", &nc);
07751       if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
07752          /*
07753           * Nonce time expired (> 2 minutes) or something wrong with nonce
07754           * counter.
07755           *
07756           * Create new nonce key and resend Digest auth request. Old nonce
07757           * is saved for stale checking...
07758           */
07759          session->nc = 0; /* Reset nonce counter */
07760          session->oldnonce = session->managerid;
07761          nonce = session->managerid = ast_random();
07762          session->noncetime = time_now;
07763          ao2_unlock(session);
07764          stale = 1;
07765          goto out_401;
07766       } else {
07767          session->nc = nc; /* All OK, save nonce counter */
07768       }
07769    }
07770 
07771 
07772    /* Reset session timeout. */
07773    session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
07774    ao2_unlock(session);
07775 
07776    ast_mutex_init(&s.lock);
07777    s.session = session;
07778    s.fd = mkstemp(template);  /* create a temporary file for command output */
07779    unlink(template);
07780    if (s.fd <= -1) {
07781       ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)");
07782       goto auth_callback_out;
07783    }
07784    s.f = fdopen(s.fd, "w+");
07785    if (!s.f) {
07786       ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
07787       ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)");
07788       close(s.fd);
07789       goto auth_callback_out;
07790    }
07791 
07792    if (method == AST_HTTP_POST) {
07793       params = ast_http_get_post_vars(ser, headers);
07794       if (!params) {
07795          switch (errno) {
07796          case EFBIG:
07797             ast_http_error(ser, 413, "Request Entity Too Large", "Body too large");
07798             close_mansession_file(&s);
07799             goto auth_callback_out;
07800          case ENOMEM:
07801             ast_http_request_close_on_completion(ser);
07802             ast_http_error(ser, 500, "Server Error", "Out of memory");
07803             close_mansession_file(&s);
07804             goto auth_callback_out;
07805          case EIO:
07806             ast_http_error(ser, 400, "Bad Request", "Error parsing request body");
07807             close_mansession_file(&s);
07808             goto auth_callback_out;
07809          }
07810       }
07811    }
07812 
07813    for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
07814       hdrlen = strlen(v->name) + strlen(v->value) + 3;
07815       m.headers[m.hdrcount] = ast_malloc(hdrlen);
07816       if (!m.headers[m.hdrcount]) {
07817          /* Allocation failure */
07818          continue;
07819       }
07820       snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
07821       ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
07822       ++m.hdrcount;
07823    }
07824 
07825    if (process_message(&s, &m)) {
07826       if (u_displayconnects) {
07827          ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
07828       }
07829 
07830       session->needdestroy = 1;
07831    }
07832 
07833    /* Free request headers. */
07834    for (idx = 0; idx < m.hdrcount; ++idx) {
07835       ast_free((void *) m.headers[idx]);
07836       m.headers[idx] = NULL;
07837    }
07838 
07839    result_size = ftell(s.f); /* Calculate approx. size of result */
07840 
07841    http_header = ast_str_create(80);
07842    out = ast_str_create(result_size * 2 + 512);
07843    if (http_header == NULL || out == NULL) {
07844       ast_http_request_close_on_completion(ser);
07845       ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)");
07846       close_mansession_file(&s);
07847       goto auth_callback_out;
07848    }
07849 
07850    ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]);
07851 
07852    if (format == FORMAT_XML) {
07853       ast_str_append(&out, 0, "<ajax-response>\n");
07854    } else if (format == FORMAT_HTML) {
07855       ast_str_append(&out, 0,
07856       "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
07857       "<html><head>\r\n"
07858       "<title>Asterisk&trade; Manager Interface</title>\r\n"
07859       "</head><body style=\"background-color: #ffffff;\">\r\n"
07860       "<form method=\"POST\">\r\n"
07861       "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
07862       "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
07863       "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
07864       "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
07865    }
07866 
07867    process_output(&s, &out, params, format);
07868 
07869    if (format == FORMAT_XML) {
07870       ast_str_append(&out, 0, "</ajax-response>\n");
07871    } else if (format == FORMAT_HTML) {
07872       ast_str_append(&out, 0, "</table></form></body></html>\r\n");
07873    }
07874 
07875    ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
07876    http_header = NULL;
07877    out = NULL;
07878 
07879 auth_callback_out:
07880    ast_mutex_destroy(&s.lock);
07881 
07882    /* Clear resources and unlock manager session */
07883    if (method == AST_HTTP_POST && params) {
07884       ast_variables_destroy(params);
07885    }
07886 
07887    ast_free(http_header);
07888    ast_free(out);
07889 
07890    ao2_lock(session);
07891    if (session->f) {
07892       fclose(session->f);
07893    }
07894    session->f = NULL;
07895    session->fd = -1;
07896    ao2_unlock(session);
07897 
07898    if (session->needdestroy) {
07899       ast_debug(1, "Need destroy, doing it now!\n");
07900       session_destroy(session);
07901    }
07902    ast_string_field_free_memory(&d);
07903    return 0;
07904 
07905 out_401:
07906    if (!nonce) {
07907       nonce = ast_random();
07908    }
07909 
07910    ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
07911    ast_string_field_free_memory(&d);
07912    return 0;
07913 }

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 7974 of file manager.c.

References ast_sockaddr_copy(), auth_http_callback(), FORMAT_HTML, ast_tcptls_session_instance::remote_address, and retval.

07975 {
07976    int retval;
07977    struct ast_sockaddr ser_remote_address_tmp;
07978 
07979    ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
07980    retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
07981    ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
07982    return retval;
07983 }

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 7985 of file manager.c.

References ast_sockaddr_copy(), auth_http_callback(), FORMAT_XML, ast_tcptls_session_instance::remote_address, and retval.

07986 {
07987    int retval;
07988    struct ast_sockaddr ser_remote_address_tmp;
07989 
07990    ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
07991    retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
07992    ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
07993    return retval;
07994 }

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 7996 of file manager.c.

References ast_sockaddr_copy(), auth_http_callback(), FORMAT_RAW, ast_tcptls_session_instance::remote_address, and retval.

07997 {
07998    int retval;
07999    struct ast_sockaddr ser_remote_address_tmp;
08000 
08001    ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
08002    retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
08003    ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
08004    return retval;
08005 }

static void close_mansession_file ( struct mansession s  )  [static]

Definition at line 7304 of file manager.c.

References ast_log, errno, mansession::f, mansession::fd, LOG_ERROR, and NULL.

Referenced by auth_http_callback(), generic_http_callback(), and process_output().

07305 {
07306    if (s->f) {
07307       if (fclose(s->f)) {
07308          ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
07309       }
07310       s->f = NULL;
07311       s->fd = -1;
07312    } else if (s->fd != -1) {
07313       /*
07314        * Issuing shutdown() is necessary here to avoid a race
07315        * condition where the last data written may not appear
07316        * in the TCP stream.  See ASTERISK-23548
07317        */
07318       shutdown(s->fd, SHUT_RDWR);
07319       if (close(s->fd)) {
07320          ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
07321       }
07322       s->fd = -1;
07323    } else {
07324       ast_log(LOG_ERROR, "Attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n");
07325    }
07326 }

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 6920 of file manager.c.

References ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_atomic_fetchadd_int(), mansession_session::inuse, mansession_session::managerid, mansession_session::needdestroy, NULL, session, and unref_mansession().

Referenced by astman_is_authed(), and generic_http_callback().

06921 {
06922    struct ao2_container *sessions;
06923    struct mansession_session *session;
06924    struct ao2_iterator i;
06925 
06926    if (ident == 0) {
06927       return NULL;
06928    }
06929 
06930    sessions = ao2_global_obj_ref(mgr_sessions);
06931    if (!sessions) {
06932       return NULL;
06933    }
06934    i = ao2_iterator_init(sessions, 0);
06935    ao2_ref(sessions, -1);
06936    while ((session = ao2_iterator_next(&i))) {
06937       ao2_lock(session);
06938       if (session->managerid == ident && !session->needdestroy) {
06939          ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
06940          break;
06941       }
06942       ao2_unlock(session);
06943       unref_mansession(session);
06944    }
06945    ao2_iterator_destroy(&i);
06946 
06947    return session;
06948 }

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 6959 of file manager.c.

References ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, mansession_session::managerid, NULL, mansession_session::oldnonce, session, unref_mansession(), and mansession_session::username.

Referenced by auth_http_callback().

06960 {
06961    struct mansession_session *session;
06962    struct ao2_container *sessions;
06963    struct ao2_iterator i;
06964 
06965    if (nonce == 0 || username == NULL || stale == NULL) {
06966       return NULL;
06967    }
06968 
06969    sessions = ao2_global_obj_ref(mgr_sessions);
06970    if (!sessions) {
06971       return NULL;
06972    }
06973    i = ao2_iterator_init(sessions, 0);
06974    ao2_ref(sessions, -1);
06975    while ((session = ao2_iterator_next(&i))) {
06976       ao2_lock(session);
06977       if (!strcasecmp(session->username, username) && session->managerid == nonce) {
06978          *stale = 0;
06979          break;
06980       } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
06981          *stale = 1;
06982          break;
06983       }
06984       ao2_unlock(session);
06985       unref_mansession(session);
06986    }
06987    ao2_iterator_destroy(&i);
06988 
06989    return session;
06990 }

static int function_amiclient ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

${AMI_CLIENT()} Dialplan function - reads manager client data

Definition at line 8050 of file manager.c.

References ao2_callback_data, ao2_global_obj_ref, ao2_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_strip(), ast_strlen_zero, get_manager_by_name_locked(), get_manager_sessions_cb(), LOG_ERROR, LOG_WARNING, name, and NULL.

08051 {
08052    struct ast_manager_user *user = NULL;
08053 
08054    AST_DECLARE_APP_ARGS(args,
08055       AST_APP_ARG(name);
08056       AST_APP_ARG(param);
08057    );
08058 
08059 
08060    if (ast_strlen_zero(data) ) {
08061       ast_log(LOG_WARNING, "AMI_CLIENT() requires two arguments: AMI_CLIENT(<name>[,<arg>])\n");
08062       return -1;
08063    }
08064    AST_STANDARD_APP_ARGS(args, data);
08065    args.name = ast_strip(args.name);
08066    args.param = ast_strip(args.param);
08067 
08068    AST_RWLIST_RDLOCK(&users);
08069    if (!(user = get_manager_by_name_locked(args.name))) {
08070       AST_RWLIST_UNLOCK(&users);
08071       ast_log(LOG_ERROR, "There's no manager user called : \"%s\"\n", args.name);
08072       return -1;
08073    }
08074    AST_RWLIST_UNLOCK(&users);
08075 
08076    if (!strcasecmp(args.param, "sessions")) {
08077       int no_sessions = 0;
08078       struct ao2_container *sessions;
08079 
08080       sessions = ao2_global_obj_ref(mgr_sessions);
08081       if (sessions) {
08082          ao2_callback_data(sessions, 0, get_manager_sessions_cb, /*login name*/ data, &no_sessions);
08083          ao2_ref(sessions, -1);
08084       }
08085       snprintf(buf, len, "%d", no_sessions);
08086    } else {
08087       ast_log(LOG_ERROR, "Invalid arguments provided to function AMI_CLIENT: %s\n", args.param);
08088       return -1;
08089 
08090    }
08091 
08092    return 0;
08093 }

static int generic_http_callback ( struct ast_tcptls_session_instance ser,
enum ast_http_method  method,
enum output_format  format,
const struct ast_sockaddr 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 7358 of file manager.c.

References mansession_session::addr, ao2_lock, ao2_unlock, ARRAY_LEN, ast_debug, ast_free, ast_http_error(), AST_HTTP_GET, ast_http_get_post_vars(), AST_HTTP_HEAD, ast_http_manid_from_vars(), AST_HTTP_POST, ast_http_request_close_on_completion(), ast_http_send(), AST_LIST_HEAD_INIT_NOLOCK, ast_log, ast_malloc, ast_mutex_destroy, ast_mutex_init, AST_PTHREADT_NULL, ast_random(), ast_sockaddr_stringify_addr(), ast_str_append(), ast_str_create(), ast_variables_destroy(), ast_verb, mansession_session::authenticated, build_mansession(), close_mansession_file(), contenttype, errno, mansession_session::f, mansession::f, mansession::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, NULL, out, process_message(), process_output(), ROW_FMT, mansession_session::send_events, mansession::session, session, session_destroy(), mansession_session::sessiontimeout, TEST_STRING, unref_mansession(), mansession_session::username, ast_variable::value, and mansession_session::waiting_thread.

Referenced by manager_http_callback(), mxml_http_callback(), and rawman_http_callback().

07364 {
07365    struct mansession s = { .session = NULL, .tcptls_session = ser };
07366    struct mansession_session *session = NULL;
07367    uint32_t ident;
07368    int blastaway = 0;
07369    struct ast_variable *v;
07370    struct ast_variable *params = get_params;
07371    char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
07372    struct ast_str *http_header = NULL, *out = NULL;
07373    struct message m = { 0 };
07374    unsigned int idx;
07375    size_t hdrlen;
07376 
07377    if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
07378       ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
07379       return 0;
07380    }
07381 
07382    ident = ast_http_manid_from_vars(headers);
07383 
07384    if (!(session = find_session(ident, 1))) {
07385 
07386       /**/
07387       /* Create new session.
07388        * While it is not in the list we don't need any locking
07389        */
07390       if (!(session = build_mansession(remote_address))) {
07391          ast_http_request_close_on_completion(ser);
07392          ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
07393          return 0;
07394       }
07395       ao2_lock(session);
07396       session->send_events = 0;
07397       session->inuse = 1;
07398       /*!
07399        * \note There is approximately a 1 in 1.8E19 chance that the following
07400        * calculation will produce 0, which is an invalid ID, but due to the
07401        * properties of the rand() function (and the constantcy of s), that
07402        * won't happen twice in a row.
07403        */
07404       while ((session->managerid = ast_random() ^ (unsigned long) session) == 0) {
07405       }
07406       session->last_ev = grab_last();
07407       AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
07408    }
07409    ao2_unlock(session);
07410 
07411    http_header = ast_str_create(128);
07412    out = ast_str_create(2048);
07413 
07414    ast_mutex_init(&s.lock);
07415 
07416    if (http_header == NULL || out == NULL) {
07417       ast_http_request_close_on_completion(ser);
07418       ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)");
07419       goto generic_callback_out;
07420    }
07421 
07422    s.session = session;
07423    s.fd = mkstemp(template);  /* create a temporary file for command output */
07424    unlink(template);
07425    if (s.fd <= -1) {
07426       ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)");
07427       goto generic_callback_out;
07428    }
07429    s.f = fdopen(s.fd, "w+");
07430    if (!s.f) {
07431       ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
07432       ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)");
07433       close(s.fd);
07434       goto generic_callback_out;
07435    }
07436 
07437    if (method == AST_HTTP_POST) {
07438       params = ast_http_get_post_vars(ser, headers);
07439       if (!params) {
07440          switch (errno) {
07441          case EFBIG:
07442             ast_http_error(ser, 413, "Request Entity Too Large", "Body too large");
07443             close_mansession_file(&s);
07444             goto generic_callback_out;
07445          case ENOMEM:
07446             ast_http_request_close_on_completion(ser);
07447             ast_http_error(ser, 500, "Server Error", "Out of memory");
07448             close_mansession_file(&s);
07449             goto generic_callback_out;
07450          case EIO:
07451             ast_http_error(ser, 400, "Bad Request", "Error parsing request body");
07452             close_mansession_file(&s);
07453             goto generic_callback_out;
07454          }
07455       }
07456    }
07457 
07458    for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
07459       hdrlen = strlen(v->name) + strlen(v->value) + 3;
07460       m.headers[m.hdrcount] = ast_malloc(hdrlen);
07461       if (!m.headers[m.hdrcount]) {
07462          /* Allocation failure */
07463          continue;
07464       }
07465       snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
07466       ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
07467       ++m.hdrcount;
07468    }
07469 
07470    if (process_message(&s, &m)) {
07471       if (session->authenticated) {
07472          if (manager_displayconnects(session)) {
07473             ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
07474          }
07475       } else {
07476          if (displayconnects) {
07477             ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_sockaddr_stringify_addr(&session->addr));
07478          }
07479       }
07480       session->needdestroy = 1;
07481    }
07482 
07483    /* Free request headers. */
07484    for (idx = 0; idx < m.hdrcount; ++idx) {
07485       ast_free((void *) m.headers[idx]);
07486       m.headers[idx] = NULL;
07487    }
07488 
07489    ast_str_append(&http_header, 0,
07490       "Content-type: text/%s\r\n"
07491       "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
07492       "Pragma: SuppressEvents\r\n",
07493       contenttype[format],
07494       session->managerid, httptimeout);
07495 
07496    if (format == FORMAT_XML) {
07497       ast_str_append(&out, 0, "<ajax-response>\n");
07498    } else if (format == FORMAT_HTML) {
07499       /*
07500        * When handling AMI-over-HTTP in HTML format, we provide a simple form for
07501        * debugging purposes. This HTML code should not be here, we
07502        * should read from some config file...
07503        */
07504 
07505 #define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
07506 #define TEST_STRING \
07507    "<form action=\"manager\" method=\"post\">\n\
07508    Action: <select name=\"action\">\n\
07509       <option value=\"\">-----&gt;</option>\n\
07510       <option value=\"login\">login</option>\n\
07511       <option value=\"command\">Command</option>\n\
07512       <option value=\"waitevent\">waitevent</option>\n\
07513       <option value=\"listcommands\">listcommands</option>\n\
07514    </select>\n\
07515    or <input name=\"action\"><br/>\n\
07516    CLI Command <input name=\"command\"><br>\n\
07517    user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
07518    <input type=\"submit\">\n</form>\n"
07519 
07520       ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
07521       ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
07522       ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
07523       ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
07524    }
07525 
07526    process_output(&s, &out, params, format);
07527 
07528    if (format == FORMAT_XML) {
07529       ast_str_append(&out, 0, "</ajax-response>\n");
07530    } else if (format == FORMAT_HTML) {
07531       ast_str_append(&out, 0, "</table></body>\r\n");
07532    }
07533 
07534    ao2_lock(session);
07535    /* Reset HTTP timeout.  If we're not authenticated, keep it extremely short */
07536    session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
07537 
07538    if (session->needdestroy) {
07539       if (session->inuse == 1) {
07540          ast_debug(1, "Need destroy, doing it now!\n");
07541          blastaway = 1;
07542       } else {
07543          ast_debug(1, "Need destroy, but can't do it yet!\n");
07544          if (session->waiting_thread != AST_PTHREADT_NULL) {
07545             pthread_kill(session->waiting_thread, SIGURG);
07546          }
07547          session->inuse--;
07548       }
07549    } else {
07550       session->inuse--;
07551    }
07552    ao2_unlock(session);
07553 
07554    ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
07555    http_header = NULL;
07556    out = NULL;
07557 
07558 generic_callback_out:
07559    ast_mutex_destroy(&s.lock);
07560 
07561    /* Clear resource */
07562 
07563    if (method == AST_HTTP_POST && params) {
07564       ast_variables_destroy(params);
07565    }
07566    ast_free(http_header);
07567    ast_free(out);
07568 
07569    if (session) {
07570       if (blastaway) {
07571          session_destroy(session);
07572       } else {
07573          if (session->f) {
07574             fclose(session->f);
07575             session->f = NULL;
07576          }
07577          unref_mansession(session);
07578       }
07579    }
07580 
07581    return 0;
07582 }

static int get_manager_sessions_cb ( void *  obj,
void *  arg,
void *  data,
int  flags 
) [static]

Get number of logged in sessions for a login name.

Definition at line 8035 of file manager.c.

References session, and mansession_session::username.

Referenced by function_amiclient().

08036 {
08037    struct mansession_session *session = obj;
08038    const char *login = (char *)arg;
08039    int *no_sessions = data;
08040 
08041    if (strcasecmp(session->username, login) == 0) {
08042       (*no_sessions)++;
08043    }
08044 
08045    return 0;
08046 }

static char* handle_manager_show_settings ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command manager show settings.

Definition at line 8137 of file manager.c.

References ami_desc, ami_tls_cfg, amis_desc, ast_cli_args::argc, ast_cli(), AST_CLI_YESNO, ast_sockaddr_stringify(), ast_tls_config::certfile, ast_tls_config::cipher, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_tls_config::enabled, ast_cli_args::fd, FORMAT, FORMAT2, ast_tcptls_session_args::local_address, NULL, ast_tls_config::pvtfile, S_OR, and ast_cli_entry::usage.

08138 {
08139    switch (cmd) {
08140    case CLI_INIT:
08141       e->command = "manager show settings";
08142       e->usage =
08143          "Usage: manager show settings\n"
08144          "       Provides detailed list of the configuration of the Manager.\n";
08145       return NULL;
08146    case CLI_GENERATE:
08147       return NULL;
08148    }
08149 #define FORMAT "  %-25.25s  %-15.55s\n"
08150 #define FORMAT2 "  %-25.25s  %-15d\n"
08151    if (a->argc != 3) {
08152       return CLI_SHOWUSAGE;
08153    }
08154    ast_cli(a->fd, "\nGlobal Settings:\n");
08155    ast_cli(a->fd, "----------------\n");
08156    ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
08157    ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
08158    ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
08159    ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
08160    ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
08161    ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
08162    ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
08163    ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
08164    ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
08165    ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
08166    ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
08167    ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
08168    ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
08169    ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
08170 #undef FORMAT
08171 #undef FORMAT2
08172 
08173    return CLI_SUCCESS;
08174 }

int init_manager ( void   ) 

Called by Asterisk initialization.

Definition at line 9100 of file manager.c.

References __init_manager().

Referenced by main().

09101 {
09102    return __init_manager(0, 0);
09103 }

static void load_channelvars ( struct ast_variable var  )  [static]

Definition at line 8386 of file manager.c.

References args, AST_APP_ARG, ast_channel_set_manager_vars(), AST_DECLARE_APP_ARGS, ast_free, AST_STANDARD_APP_ARGS, ast_strdup, ast_strdupa, MAX_VARS, NULL, parse(), and ast_variable::value.

Referenced by __init_manager().

08387 {
08388         char *parse = NULL;
08389         AST_DECLARE_APP_ARGS(args,
08390                 AST_APP_ARG(vars)[MAX_VARS];
08391         );
08392 
08393    ast_free(manager_channelvars);
08394    manager_channelvars = ast_strdup(var->value);
08395 
08396    /* parse the setting */
08397    parse = ast_strdupa(manager_channelvars);
08398    AST_STANDARD_APP_ARGS(args, parse);
08399 
08400    ast_channel_set_manager_vars(args.argc, args.vars);
08401 }

static void manager_event_blob_dtor ( void *  obj  )  [static]

Definition at line 9169 of file manager.c.

References ast_string_field_free_memory.

Referenced by ast_manager_event_blob_create().

09170 {
09171    struct ast_manager_event_blob *ev = obj;
09172    ast_string_field_free_memory(ev);
09173 }

static void manager_free_user ( struct ast_manager_user user  )  [static]

Definition at line 8407 of file manager.c.

References ast_manager_user::a1_hash, ast_manager_user::acl, ao2_t_ref, ast_free, ast_free_acl_list(), ast_variables_destroy(), ast_manager_user::blackfilters, ast_manager_user::chanvars, ast_manager_user::secret, and ast_manager_user::whitefilters.

Referenced by __init_manager(), and manager_shutdown().

08408 {
08409    ast_free(user->a1_hash);
08410    ast_free(user->secret);
08411    if (user->whitefilters) {
08412       ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
08413    }
08414    if (user->blackfilters) {
08415       ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
08416    }
08417    user->acl = ast_free_acl_list(user->acl);
08418    ast_variables_destroy(user->chanvars);
08419    ast_free(user);
08420 }

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 7915 of file manager.c.

References ast_sockaddr_copy(), FORMAT_HTML, generic_http_callback(), ast_tcptls_session_instance::remote_address, and retval.

07916 {
07917    int retval;
07918    struct ast_sockaddr ser_remote_address_tmp;
07919 
07920    ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
07921    retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
07922    ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
07923    return retval;
07924 }

static void manager_set_defaults ( void   )  [static]

static void manager_shutdown ( void   )  [static]

Definition at line 8426 of file manager.c.

References acl_change_stasis_unsubscribe(), ami_desc, ami_tls_cfg, amis_desc, ao2_cleanup, ao2_global_obj_release, ao2_t_global_obj_release, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_free, AST_LIST_REMOVE_HEAD, ast_manager_get_generic_type(), ast_manager_unregister(), ast_tcptls_server_stop(), ast_tls_config::certfile, ast_tls_config::cipher, cli_manager, EVENT_FLAG_SHUTDOWN, ast_manager_user::list, manager_event, manager_free_user(), manager_topic, managerclient_function, NULL, ast_tls_config::pvtfile, rtp_topic_forwarder, security_topic_forwarder, stasis_forward_cancel(), stasis_message_router_unsubscribe_and_join(), STASIS_MESSAGE_TYPE_CLEANUP, and stasis_router.

Referenced by __init_manager().

08427 {
08428    struct ast_manager_user *user;
08429 
08430    /* This event is not actually transmitted, but causes all TCP sessions to be closed */
08431    manager_event(EVENT_FLAG_SHUTDOWN, "CloseSession", "CloseSession: true\r\n");
08432 
08433    ast_manager_unregister("Ping");
08434    ast_manager_unregister("Events");
08435    ast_manager_unregister("Logoff");
08436    ast_manager_unregister("Login");
08437    ast_manager_unregister("Challenge");
08438    ast_manager_unregister("Hangup");
08439    ast_manager_unregister("Status");
08440    ast_manager_unregister("Setvar");
08441    ast_manager_unregister("Getvar");
08442    ast_manager_unregister("GetConfig");
08443    ast_manager_unregister("GetConfigJSON");
08444    ast_manager_unregister("UpdateConfig");
08445    ast_manager_unregister("CreateConfig");
08446    ast_manager_unregister("ListCategories");
08447    ast_manager_unregister("Redirect");
08448    ast_manager_unregister("Atxfer");
08449    ast_manager_unregister("Originate");
08450    ast_manager_unregister("Command");
08451    ast_manager_unregister("ExtensionState");
08452    ast_manager_unregister("PresenceState");
08453    ast_manager_unregister("AbsoluteTimeout");
08454    ast_manager_unregister("MailboxStatus");
08455    ast_manager_unregister("MailboxCount");
08456    ast_manager_unregister("ListCommands");
08457    ast_manager_unregister("SendText");
08458    ast_manager_unregister("UserEvent");
08459    ast_manager_unregister("WaitEvent");
08460    ast_manager_unregister("CoreSettings");
08461    ast_manager_unregister("CoreStatus");
08462    ast_manager_unregister("Reload");
08463    ast_manager_unregister("LoggerRotate");
08464    ast_manager_unregister("CoreShowChannels");
08465    ast_manager_unregister("ModuleLoad");
08466    ast_manager_unregister("ModuleCheck");
08467    ast_manager_unregister("AOCMessage");
08468    ast_manager_unregister("Filter");
08469    ast_manager_unregister("BlindTransfer");
08470    ast_custom_function_unregister(&managerclient_function);
08471    ast_cli_unregister_multiple(cli_manager, ARRAY_LEN(cli_manager));
08472 
08473 #ifdef AST_XML_DOCS
08474    ao2_t_global_obj_release(event_docs, "Dispose of event_docs");
08475 #endif
08476 
08477 #ifdef TEST_FRAMEWORK
08478    stasis_forward_cancel(test_suite_forwarder);
08479    test_suite_forwarder = NULL;
08480 #endif
08481 
08482    if (stasis_router) {
08483       stasis_message_router_unsubscribe_and_join(stasis_router);
08484       stasis_router = NULL;
08485    }
08486    stasis_forward_cancel(rtp_topic_forwarder);
08487    rtp_topic_forwarder = NULL;
08488    stasis_forward_cancel(security_topic_forwarder);
08489    security_topic_forwarder = NULL;
08490    ao2_cleanup(manager_topic);
08491    manager_topic = NULL;
08492    STASIS_MESSAGE_TYPE_CLEANUP(ast_manager_get_generic_type);
08493 
08494    ast_tcptls_server_stop(&ami_desc);
08495    ast_tcptls_server_stop(&amis_desc);
08496 
08497    ast_free(ami_tls_cfg.certfile);
08498    ami_tls_cfg.certfile = NULL;
08499    ast_free(ami_tls_cfg.pvtfile);
08500    ami_tls_cfg.pvtfile = NULL;
08501    ast_free(ami_tls_cfg.cipher);
08502    ami_tls_cfg.cipher = NULL;
08503 
08504    ao2_global_obj_release(mgr_sessions);
08505 
08506    while ((user = AST_LIST_REMOVE_HEAD(&users, list))) {
08507       manager_free_user(user);
08508    }
08509    acl_change_stasis_unsubscribe();
08510 }

static int manager_subscriptions_init ( void   )  [static]

Initialize all Stasis Message Bus API topics and routers used by the various sub-components of AMI.

Definition at line 8516 of file manager.c.

References ast_manager_get_generic_type(), ast_rtp_topic(), ast_security_topic(), manager_default_msg_cb(), manager_generic_msg_cb(), manager_topic, NULL, rtp_topic_forwarder, security_topic_forwarder, stasis_forward_all(), stasis_message_router_add(), stasis_message_router_create(), stasis_message_router_set_default(), and stasis_router.

Referenced by subscribe_all().

08517 {
08518    int res = 0;
08519 
08520    rtp_topic_forwarder = stasis_forward_all(ast_rtp_topic(), manager_topic);
08521    if (!rtp_topic_forwarder) {
08522       return -1;
08523    }
08524 
08525    security_topic_forwarder = stasis_forward_all(ast_security_topic(), manager_topic);
08526    if (!security_topic_forwarder) {
08527       return -1;
08528    }
08529 
08530    stasis_router = stasis_message_router_create(manager_topic);
08531    if (!stasis_router) {
08532       return -1;
08533    }
08534 
08535    res |= stasis_message_router_set_default(stasis_router,
08536       manager_default_msg_cb, NULL);
08537 
08538    res |= stasis_message_router_add(stasis_router,
08539       ast_manager_get_generic_type(), manager_generic_msg_cb, NULL);
08540 
08541    if (res != 0) {
08542       return -1;
08543    }
08544    return 0;
08545 }

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 7926 of file manager.c.

References ast_sockaddr_copy(), FORMAT_XML, generic_http_callback(), ast_tcptls_session_instance::remote_address, and retval.

07927 {
07928    int retval;
07929    struct ast_sockaddr ser_remote_address_tmp;
07930 
07931    ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
07932    retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
07933    ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
07934    return retval;
07935 }

static void process_output ( struct mansession s,
struct ast_str **  out,
struct ast_variable params,
enum output_format  format 
) [static]

Definition at line 7328 of file manager.c.

References ast_log, ast_str_append(), buf, close_mansession_file(), mansession::f, mansession::fd, FORMAT_HTML, FORMAT_XML, LOG_WARNING, NULL, and xml_translate().

Referenced by auth_http_callback(), and generic_http_callback().

07329 {
07330    char *buf;
07331    size_t l;
07332 
07333    if (!s->f)
07334       return;
07335 
07336    /* Ensure buffer is NULL-terminated */
07337    fprintf(s->f, "%c", 0);
07338    fflush(s->f);
07339 
07340    if ((l = ftell(s->f)) > 0) {
07341       if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) {
07342          ast_log(LOG_WARNING, "mmap failed.  Manager output was not processed\n");
07343       } else {
07344          if (format == FORMAT_XML || format == FORMAT_HTML) {
07345             xml_translate(out, buf, params, format);
07346          } else {
07347             ast_str_append(out, 0, "%s", buf);
07348          }
07349          munmap(buf, l);
07350       }
07351    } else if (format == FORMAT_XML || format == FORMAT_HTML) {
07352       xml_translate(out, "", params, format);
07353    }
07354 
07355    close_mansession_file(s);
07356 }

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 8108 of file manager.c.

References purge_events(), and purge_sessions().

08109 {
08110    purge_sessions(1);
08111    purge_events();
08112 }

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 7937 of file manager.c.

References ast_sockaddr_copy(), FORMAT_RAW, generic_http_callback(), ast_tcptls_session_instance::remote_address, and retval.

07938 {
07939    int retval;
07940    struct ast_sockaddr ser_remote_address_tmp;
07941 
07942    ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
07943    retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
07944    ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
07945    return retval;
07946 }

int reload_manager ( void   ) 

Called by Asterisk module functions and the CLI command.

Definition at line 9105 of file manager.c.

References __init_manager().

Referenced by handle_manager_reload().

09106 {
09107    return __init_manager(1, 0);
09108 }

static int subscribe_all ( void   )  [static]

Definition at line 8547 of file manager.c.

References ast_log, AST_LOG_ERROR, manager_bridging_init(), manager_channels_init(), manager_endpoints_init(), manager_mwi_init(), manager_subscriptions_init(), and manager_system_init().

Referenced by __init_manager().

08548 {
08549    if (manager_subscriptions_init()) {
08550       ast_log(AST_LOG_ERROR, "Failed to initialize manager subscriptions\n");
08551       return -1;
08552    }
08553    if (manager_system_init()) {
08554       ast_log(AST_LOG_ERROR, "Failed to initialize manager system handling\n");
08555       return -1;
08556    }
08557    if (manager_channels_init()) {
08558       ast_log(AST_LOG_ERROR, "Failed to initialize manager channel handling\n");
08559       return -1;
08560    }
08561    if (manager_mwi_init()) {
08562       ast_log(AST_LOG_ERROR, "Failed to initialize manager MWI handling\n");
08563       return -1;
08564    }
08565    if (manager_bridging_init()) {
08566       return -1;
08567    }
08568    if (manager_endpoints_init()) {
08569       ast_log(AST_LOG_ERROR, "Failed to initialize manager endpoints handling\n");
08570       return -1;
08571    }
08572 
08573    subscribed = 1;
08574    return 0;
08575 }

static int variable_count_cmp_fn ( void *  obj,
void *  vstr,
int  flags 
) [static]

Definition at line 7148 of file manager.c.

References CMP_MATCH, CMP_STOP, str, and variable_count::varname.

Referenced by xml_translate().

07149 {
07150    /* Due to the simplicity of struct variable_count, it makes no difference
07151     * if you pass in objects or strings, the same operation applies. This is
07152     * due to the fact that the hash occurs on the first element, which means
07153     * the address of both the struct and the string are exactly the same. */
07154    struct variable_count *vc = obj;
07155    char *str = vstr;
07156    return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
07157 }

static int variable_count_hash_fn ( const void *  vvc,
const int  flags 
) [static]

Definition at line 7141 of file manager.c.

References ast_str_hash(), and variable_count::varname.

Referenced by xml_translate().

07142 {
07143    const struct variable_count *vc = vvc;
07144 
07145    return ast_str_hash(vc->varname);
07146 }

static void xml_copy_escape ( struct ast_str **  out,
const char *  src,
int  mode 
) [static]

Definition at line 7079 of file manager.c.

References ast_str_append(), and buf.

Referenced by xml_translate().

07080 {
07081    /* store in a local buffer to avoid calling ast_str_append too often */
07082    char buf[256];
07083    char *dst = buf;
07084    int space = sizeof(buf);
07085    /* repeat until done and nothing to flush */
07086    for ( ; *src || dst != buf ; src++) {
07087       if (*src == '\0' || space < 10) {   /* flush */
07088          *dst++ = '\0';
07089          ast_str_append(out, 0, "%s", buf);
07090          dst = buf;
07091          space = sizeof(buf);
07092          if (*src == '\0') {
07093             break;
07094          }
07095       }
07096 
07097       if ( (mode & 2) && !isalnum(*src)) {
07098          *dst++ = '_';
07099          space--;
07100          continue;
07101       }
07102       switch (*src) {
07103       case '<':
07104          strcpy(dst, "&lt;");
07105          dst += 4;
07106          space -= 4;
07107          break;
07108       case '>':
07109          strcpy(dst, "&gt;");
07110          dst += 4;
07111          space -= 4;
07112          break;
07113       case '\"':
07114          strcpy(dst, "&quot;");
07115          dst += 6;
07116          space -= 6;
07117          break;
07118       case '\'':
07119          strcpy(dst, "&apos;");
07120          dst += 6;
07121          space -= 6;
07122          break;
07123       case '&':
07124          strcpy(dst, "&amp;");
07125          dst += 5;
07126          space -= 5;
07127          break;
07128 
07129       default:
07130          *dst++ = mode ? tolower(*src) : *src;
07131          space--;
07132       }
07133    }
07134 }

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 7187 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, NULL, strsep(), ast_variable::value, var, variable_count_cmp_fn(), variable_count_hash_fn(), variable_count::varname, and xml_copy_escape().

Referenced by process_output().

07188 {
07189    struct ast_variable *v;
07190    const char *dest = NULL;
07191    char *var, *val;
07192    const char *objtype = NULL;
07193    int in_data = 0;  /* parsing data */
07194    int inobj = 0;
07195    int xml = (format == FORMAT_XML);
07196    struct variable_count *vc = NULL;
07197    struct ao2_container *vco = NULL;
07198 
07199    if (xml) {
07200       /* dest and objtype need only for XML format */
07201       for (v = get_vars; v; v = v->next) {
07202          if (!strcasecmp(v->name, "ajaxdest")) {
07203             dest = v->value;
07204          } else if (!strcasecmp(v->name, "ajaxobjtype")) {
07205             objtype = v->value;
07206          }
07207       }
07208       if (ast_strlen_zero(dest)) {
07209          dest = "unknown";
07210       }
07211       if (ast_strlen_zero(objtype)) {
07212          objtype = "generic";
07213       }
07214    }
07215 
07216    /* we want to stop when we find an empty line */
07217    while (in && *in) {
07218       val = strsep(&in, "\r\n"); /* mark start and end of line */
07219       if (in && *in == '\n') {   /* remove trailing \n if any */
07220          in++;
07221       }
07222       ast_trim_blanks(val);
07223       ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
07224       if (ast_strlen_zero(val)) {
07225          /* empty line */
07226          if (in_data) {
07227             /* close data in Opaque mode */
07228             ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
07229             in_data = 0;
07230          }
07231 
07232          if (inobj) {
07233             /* close block */
07234             ast_str_append(out, 0, xml ? " /></response>\n" :
07235                "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
07236             inobj = 0;
07237             ao2_ref(vco, -1);
07238             vco = NULL;
07239          }
07240          continue;
07241       }
07242 
07243       if (!inobj) {
07244          /* start new block */
07245          if (xml) {
07246             ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
07247          }
07248          vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
07249          inobj = 1;
07250       }
07251 
07252       if (in_data) {
07253          /* Process data field in Opaque mode. This is a
07254           * followup, so we re-add line feeds. */
07255          ast_str_append(out, 0, xml ? "\n" : "<br>\n");
07256          xml_copy_escape(out, val, 0);   /* data field */
07257          continue;
07258       }
07259 
07260       /* We expect "Name: value" line here */
07261       var = strsep(&val, ":");
07262       if (val) {
07263          /* found the field name */
07264          val = ast_skip_blanks(val);
07265          ast_trim_blanks(var);
07266       } else {
07267          /* field name not found, switch to opaque mode */
07268          val = var;
07269          var = "Opaque-data";
07270          in_data = 1;
07271       }
07272 
07273 
07274       ast_str_append(out, 0, xml ? " " : "<tr><td>");
07275       if ((vc = ao2_find(vco, var, 0))) {
07276          vc->count++;
07277       } else {
07278          /* Create a new entry for this one */
07279          vc = ao2_alloc(sizeof(*vc), NULL);
07280          vc->varname = var;
07281          vc->count = 1;
07282          ao2_link(vco, vc);
07283       }
07284 
07285       xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
07286       if (vc->count > 1) {
07287          ast_str_append(out, 0, "-%d", vc->count);
07288       }
07289       ao2_ref(vc, -1);
07290       ast_str_append(out, 0, xml ? "='" : "</td><td>");
07291       xml_copy_escape(out, val, 0); /* data field */
07292       if (!in_data || !*in) {
07293          ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
07294       }
07295    }
07296 
07297    if (inobj) {
07298       ast_str_append(out, 0, xml ? " /></response>\n" :
07299          "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
07300       ao2_ref(vco, -1);
07301    }
07302 }


Variable Documentation

struct ast_http_uri amanageruri [static]

Definition at line 8016 of file manager.c.

Referenced by __init_manager().

struct ast_http_uri amanagerxmluri [static]

Definition at line 8025 of file manager.c.

Referenced by __init_manager().

struct ast_tls_config ami_tls_cfg [static]

struct ast_http_uri arawmanuri [static]

Definition at line 8007 of file manager.c.

Referenced by __init_manager().

struct ast_cli_entry cli_manager[] [static]

Definition at line 8362 of file manager.c.

Referenced by __init_manager(), and manager_shutdown().

const char* const contenttype[] [static]

Initial value:

 {
   [FORMAT_RAW] = "plain",
   [FORMAT_HTML] = "html",
   [FORMAT_XML] =  "xml",
}

Definition at line 6909 of file manager.c.

Referenced by auth_http_callback(), and generic_http_callback().

Initial value:

 {
   .name = "AMI_CLIENT",
   .read = function_amiclient,
   .read_max = 12,
}
description of AMI_CLIENT dialplan function

Definition at line 8097 of file manager.c.

Referenced by __init_manager(), and manager_shutdown().

struct ast_http_uri manageruri [static]

Definition at line 7956 of file manager.c.

Referenced by __init_manager().

struct ast_http_uri managerxmluri [static]

Definition at line 7964 of file manager.c.

Referenced by __init_manager().

struct ast_http_uri rawmanuri [static]

Definition at line 7948 of file manager.c.

Referenced by __init_manager().

int webregged = 0 [static]

Definition at line 8103 of file manager.c.

Referenced by __init_manager().

const char* words[AST_MAX_CMD_LEN]

Definition at line 1403 of file manager.c.

Referenced by check_blacklist().


Generated on Thu Apr 16 06:31:56 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6