Fri Aug 17 00:17:43 2018

Asterisk developer's documentation


manager.c File Reference

The Asterisk Management Interface - AMI. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/paths.h"
#include <ctype.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <regex.h>
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/manager.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/callerid.h"
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/md5.h"
#include "asterisk/acl.h"
#include "asterisk/utils.h"
#include "asterisk/tcptls.h"
#include "asterisk/http.h"
#include "asterisk/ast_version.h"
#include "asterisk/threadstorage.h"
#include "asterisk/linkedlists.h"
#include "asterisk/term.h"
#include "asterisk/astobj2.h"
#include "asterisk/features.h"
#include "asterisk/security_events.h"
#include "asterisk/aoc.h"
#include "asterisk/stringfields.h"

Go to the source code of this file.

Data Structures

struct  actions
 list of actions registered More...
struct  all_events
struct  ast_manager_user
 user descriptor, as read from the config file. More...
struct  channelvars
struct  eventqent
struct  fast_originate_helper
 helper function for originate More...
struct  manager_channel_variable
struct  manager_hooks
 list of hooks registered More...
struct  mansession
struct  mansession_datastores
struct  mansession_session
struct  permalias
struct  users
 list of users found in the config file More...
struct  variable_count

Defines

#define ASTMAN_APPEND_BUF_INITSIZE   256
 initial allocated size for the astman_append_buf
#define DEFAULT_REALM   "asterisk"
#define FORMAT   " %-25.25s %-15.15s\n"
#define FORMAT2   " %-25.25s %-15d\n"
#define GET_HEADER_FIRST_MATCH   0
#define GET_HEADER_LAST_MATCH   1
#define GET_HEADER_SKIP_EMPTY   2
#define HSMC_FORMAT   " %-15.15s %-15.15s %-55.55s\n"
#define HSMCONN_FORMAT1   " %-15.15s %-15.15s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
#define HSMCONN_FORMAT2   " %-15.15s %-15.15s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
#define MANAGER_EVENT_BUF_INITSIZE   256
#define MAX_BLACKLIST_CMD_LEN   2
 Descriptor for a manager session, either on the AMI socket or over HTTP.
#define MSG_MOREDATA   ((char *)astman_send_response)
 send a response with an optional message, and terminate it with an empty line. m is used only to grab the 'ActionID' field.
#define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
#define TEST_STRING   "<form action=\"manager\" method=\"post\">\n\ Action: <select name=\"action\">\n\ <option value=\"\">-----&gt;</option>\n\ <option value=\"login\">login</option>\n\ <option value=\"command\">Command</option>\n\ <option value=\"waitevent\">waitevent</option>\n\ <option value=\"listcommands\">listcommands</option>\n\ </select>\n\ or <input name=\"action\"><br/>\n\ CLI Command <input name=\"command\"><br>\n\ user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\ <input type=\"submit\">\n</form>\n"

Enumerations

enum  error_type {
  UNKNOWN_ACTION = 1, UNKNOWN_CATEGORY, UNSPECIFIED_CATEGORY, UNSPECIFIED_ARGUMENT,
  FAILURE_ALLOCATION, FAILURE_NEWCAT, FAILURE_DELCAT, FAILURE_EMPTYCAT,
  FAILURE_UPDATE, FAILURE_DELETE, FAILURE_APPEND
}
enum  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 __init_astman_append_buf (void)
 thread local buffer for astman_append
static int __init_manager (int reload)
static void __init_manager_event_buf (void)
static void __init_manager_event_funcbuf (void)
static void __init_userevent_buf (void)
static int action_aocmessage (struct mansession *s, const struct message *m)
static int action_atxfer (struct mansession *s, const struct message *m)
static int action_challenge (struct mansession *s, const struct message *m)
static int action_command (struct mansession *s, const struct message *m)
 Manager command "command" - execute CLI command.
static int action_coresettings (struct mansession *s, const struct message *m)
 Show PBX core settings information.
static int action_coreshowchannels (struct mansession *s, const struct message *m)
 Manager command "CoreShowChannels" - List currently defined channels and some information about them.
static int action_corestatus (struct mansession *s, const struct message *m)
 Show PBX core status information.
static int action_createconfig (struct mansession *s, const struct message *m)
static void action_destroy (void *obj)
static int action_events (struct mansession *s, const struct message *m)
static int action_extensionstate (struct mansession *s, const struct message *m)
static struct manager_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_login (struct mansession *s, const struct message *m)
static int action_logoff (struct mansession *s, const struct message *m)
static int action_mailboxcount (struct mansession *s, const struct message *m)
static int action_mailboxstatus (struct mansession *s, const struct message *m)
static int action_originate (struct mansession *s, const struct message *m)
static int action_ping (struct mansession *s, const struct message *m)
static int action_redirect (struct mansession *s, const struct message *m)
 action_redirect: The redirect manager command
static int action_reload (struct mansession *s, const struct message *m)
 Send a reload event.
static int action_sendtext (struct mansession *s, const struct message *m)
static int action_setvar (struct mansession *s, const struct message *m)
static int action_status (struct mansession *s, const struct message *m)
 Manager "status" command to show channels.
static int action_timeout (struct mansession *s, const struct message *m)
static int action_updateconfig (struct mansession *s, const struct message *m)
static int action_userevent (struct mansession *s, const struct message *m)
static int action_waitevent (struct mansession *s, const struct message *m)
static struct eventqentadvance_event (struct eventqent *e)
static int aocmessage_get_unit_entry (const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
static void append_channel_vars (struct ast_str **pbuf, struct ast_channel *chan)
static int append_event (const char *str, int category)
int ast_hook_send_action (struct manager_custom_hook *hook, const char *msg)
 Registered hooks can call this function to invoke actions and they will receive responses through registered callback.
static int ast_instring (const char *bigstr, const char *smallstr, const char delim)
int ast_manager_register2 (const char *action, int auth, int(*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
 register a new command with manager, including online help. This is the preferred way to register a manager command
void ast_manager_register_hook (struct manager_custom_hook *hook)
 Add a custom hook to be called when an event is fired.
static int ast_manager_register_struct (struct manager_action *act)
int ast_manager_unregister (char *action)
 Unregister a registered manager command.
void ast_manager_unregister_hook (struct manager_custom_hook *hook)
 Delete a custom hook to be called when an event is fired.
void astman_append (struct mansession *s, const char *fmt,...)
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_listack (struct mansession *s, const struct message *m, char *msg, char *listflag)
 Send ack in manager list transaction.
void astman_send_response (struct mansession *s, const struct message *m, char *resp, char *msg)
 Send response in manager transaction.
static void astman_send_response_full (struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
static void astman_start_ack (struct mansession *s, const struct message *m)
int astman_verify_session_readpermissions (uint32_t ident, int perm)
 Verify a session's read permissions against a permission mask.
int astman_verify_session_writepermissions (uint32_t ident, int perm)
 Verify a session's write permissions against a permission mask.
static int auth_http_callback (struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, struct sockaddr_in *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_manager_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_mxml_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_rawman_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int authenticate (struct mansession *s, const struct message *m)
static const char * authority_to_str (int authority, struct ast_str **res)
 Convert authority code to a list of options. 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 (struct sockaddr_in sin)
 Allocate manager session structure and add it to the list of sessions.
static int check_blacklist (const char *cmd)
int check_manager_enabled (void)
 Check if AMI is enabled.
static int check_manager_session_inuse (const char *name)
int check_webmanager_enabled (void)
 Check if AMI/HTTP is enabled.
static void 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 void free_channelvars (void)
static int function_capable_string_allowed_with_auths (const char *evaluating, int writepermlist)
 Checks to see if a string which can be used to evaluate functions should be rejected.
static int generic_http_callback (struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, struct sockaddr_in *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
static int get_input (struct mansession *s, char *output)
static struct ast_manager_userget_manager_by_name_locked (const char *name)
static int get_perm (const char *instr)
static struct eventqentgrab_last (void)
static char * handle_manager_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager reload.
static char * handle_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)
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 int manager_displayconnects (struct mansession_session *session)
 Get displayconnects config option.
static void manager_free_user (struct ast_manager_user *user)
static int manager_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int manager_modulecheck (struct mansession *s, const struct message *m)
static int manager_moduleload (struct mansession *s, const struct message *m)
static void manager_set_defaults (void)
static void manager_shutdown (void)
static int manager_state_cb (char *context, char *exten, int state, void *data)
static int mansession_cmp_fn (void *obj, void *arg, int flags)
static struct sockaddr_in * mansession_encode_sin_local (const struct mansession *s, struct sockaddr_in *sin_local)
static enum
ast_security_event_transport_type 
mansession_get_transport (const struct mansession *s)
static void mansession_lock (struct mansession *s)
 Lock the 'mansession' structure.
static void mansession_unlock (struct mansession *s)
 Unlock the 'mansession' structure.
static int match_filter (struct mansession *s, char *eventdata)
static int mxml_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int process_events (struct mansession *s)
static int process_message (struct mansession *s, const struct message *m)
static void process_output (struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
static void purge_events (void)
static void purge_old_stuff (void *data)
 cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most
static void purge_sessions (int n_max)
 remove at most n_max stale session from the list.
static int rawman_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
int reload_manager (void)
 Called by Asterisk module functions and the CLI command.
static void report_auth_success (const struct mansession *s)
static void report_failed_acl (const struct mansession *s, const char *username)
static void report_failed_challenge_response (const struct mansession *s, const char *response, const char *expected_response)
static void report_inval_password (const struct mansession *s, const char *username)
static void report_invalid_user (const struct mansession *s, const char *username)
static void report_req_bad_format (const struct mansession *s, const char *action)
static void report_req_not_allowed (const struct mansession *s, const char *action)
static void report_session_limit (const struct mansession *s)
static int send_string (struct mansession *s, char *string)
static void session_destroy (struct mansession_session *s)
static void session_destructor (void *obj)
static void * session_do (void *data)
 The body of the individual manager session. Call get_input() to read one line at a time (or be woken up on new events), collect the lines in a message until found an empty line, and execute the request. In any case, deliver events asynchronously through process_events() (called from here if no line is available, or at the end of process_message(). ).
static int set_eventmask (struct mansession *s, const char *eventmask)
 Rather than braindead on,off this now can also accept a specific int mask value or a ',' delim list of mask strings (the same as manager.conf) -anthm.
static int strings_to_mask (const char *string)
static struct mansession_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'.

Variables

static int allowmultiplelogin = 1
static struct ast_http_uri amanageruri
static struct ast_http_uri amanagerxmluri
static struct
ast_tcptls_session_args 
ami_desc
static struct ast_tls_config ami_tls_cfg
static struct
ast_tcptls_session_args 
amis_desc
static struct ast_http_uri arawmanuri
static struct ast_threadstorage astman_append_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_astman_append_buf , .custom_init = NULL , }
static int authlimit
static int authtimeout
static int broken_events_action
static struct ast_cli_entry cli_manager []
struct {
   const char *   words [AST_MAX_CMD_LEN]
command_blacklist []
static const char *const contenttype []
static const int DEFAULT_AUTHLIMIT = 50
static const int DEFAULT_AUTHTIMEOUT = 30
static const int DEFAULT_BROKENEVENTSACTION = 0
static const int DEFAULT_DISPLAYCONNECTS = 1
static const int DEFAULT_ENABLED = 0
static const int DEFAULT_HTTPTIMEOUT = 60
static const int DEFAULT_MANAGERDEBUG = 0
static const int DEFAULT_TIMESTAMPEVENTS = 0
static const int DEFAULT_WEBENABLED = 0
static int displayconnects
static char global_realm [MAXHOSTNAMELEN]
static int httptimeout
static char * manager_channelvars
static int manager_debug = 0
static int manager_enabled = 0
static struct ast_threadstorage manager_event_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_manager_event_buf , .custom_init = NULL , }
static struct ast_threadstorage manager_event_funcbuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_manager_event_funcbuf , .custom_init = NULL , }
static struct ast_http_uri manageruri
static struct ast_http_uri managerxmluri
static struct permalias perms []
static struct ast_http_uri rawmanuri
static struct ao2_containersessions = NULL
static int timestampevents
static int unauth_sessions = 0
static struct ast_threadstorage userevent_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_userevent_buf , .custom_init = NULL , }
static int webmanager_enabled = 0
static int webregged = 0

Detailed Description

The Asterisk Management Interface - AMI.

Author:
Mark Spencer <markster@digium.com>
ExtRef:
OpenSSL http://www.openssl.org - for AMI/SSL

At the moment this file contains a number of functions, namely:

manager.conf

Definition in file manager.c.


Define Documentation

#define FORMAT   " %-25.25s %-15.15s\n"
#define FORMAT2   " %-25.25s %-15d\n"
#define HSMC_FORMAT   " %-15.15s %-15.15s %-55.55s\n"

Referenced by handle_showmancmds().

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

Referenced by handle_showmanconn().

#define HSMCONN_FORMAT2   " %-15.15s %-15.15s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"

Referenced by handle_showmanconn().

#define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"

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

05542                    {
05543    FORMAT_RAW,
05544    FORMAT_HTML,
05545    FORMAT_XML,
05546 };


Function Documentation

static int __init_manager ( int  reload  )  [static]

Definition at line 6840 of file manager.c.

References ast_manager_user::a1_hash, action_aocmessage(), action_atxfer(), action_challenge(), action_command(), action_coresettings(), action_coreshowchannels(), action_corestatus(), action_createconfig(), action_events(), action_extensionstate(), action_getconfig(), action_getconfigjson(), action_getvar(), action_hangup(), action_listcategories(), action_listcommands(), action_login(), action_logoff(), action_mailboxcount(), action_mailboxstatus(), action_originate(), action_ping(), action_redirect(), action_reload(), action_sendtext(), action_setvar(), action_status(), action_timeout(), action_updateconfig(), action_userevent(), action_waitevent(), ami_tls_cfg, ao2_container_alloc, ao2_t_alloc, ao2_t_callback, ao2_t_link, ao2_t_ref, append_event(), ARRAY_LEN, ast_append_ha(), 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_ha(), ast_http_uri_link(), ast_http_uri_unlink(), AST_LIST_INSERT_TAIL, ast_log(), ast_manager_register_xml, ast_md5_hash(), ast_register_atexit(), 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_from_sin, ast_sockaddr_to_sin, 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_retrieve(), ast_manager_user::blackfilters, 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_filter_destructor(), 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::ha, ast_manager_user::keep, ast_variable::lineno, load_channelvars(), ast_tcptls_session_args::local_address, LOG_NOTICE, LOG_WARNING, manager_event, manager_free_user(), manager_modulecheck(), manager_moduleload(), manager_set_defaults(), manager_shutdown(), manager_state_cb(), mansession_cmp_fn(), ast_variable::name, ast_variable::next, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, ast_manager_user::readperm, ast_manager_user::secret, sessions, ast_tcptls_session_args::tls_cfg, ast_manager_user::username, value, ast_variable::value, var, ast_manager_user::whitefilters, ast_manager_user::writeperm, and ast_manager_user::writetimeout.

Referenced by init_manager(), and reload_manager().

06841 {
06842    struct ast_config *ucfg = NULL, *cfg = NULL;
06843    const char *val;
06844    char *cat = NULL;
06845    int newhttptimeout = DEFAULT_HTTPTIMEOUT;
06846    struct ast_manager_user *user = NULL;
06847    struct ast_variable *var;
06848    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06849    char a1[256];
06850    char a1_hash[256];
06851    struct sockaddr_in ami_desc_local_address_tmp = { 0, };
06852    struct sockaddr_in amis_desc_local_address_tmp = { 0, };
06853    int tls_was_enabled = 0;
06854 
06855    if (!reload) {
06856       ast_register_atexit(manager_shutdown);
06857 
06858       /* Register default actions */
06859       ast_manager_register_xml("Ping", 0, action_ping);
06860       ast_manager_register_xml("Events", 0, action_events);
06861       ast_manager_register_xml("Logoff", 0, action_logoff);
06862       ast_manager_register_xml("Login", 0, action_login);
06863       ast_manager_register_xml("Challenge", 0, action_challenge);
06864       ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
06865       ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
06866       ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar);
06867       ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
06868       ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
06869       ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
06870       ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
06871       ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
06872       ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
06873       ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect);
06874       ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer);
06875       ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate);
06876       ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command);
06877       ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
06878       ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
06879       ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
06880       ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
06881       ast_manager_register_xml("ListCommands", 0, action_listcommands);
06882       ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext);
06883       ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent);
06884       ast_manager_register_xml("WaitEvent", 0, action_waitevent);
06885       ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
06886       ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
06887       ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
06888       ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
06889       ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
06890       ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
06891       ast_manager_register_xml("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
06892 
06893       ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
06894       ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
06895 
06896       /* Append placeholder event so master_eventq never runs dry */
06897       if (append_event("Event: Placeholder\r\n\r\n", 0)) {
06898          return -1;
06899       }
06900 
06901       /* If you have a NULL hash fn, you only need a single bucket */
06902       sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn);
06903       if (!sessions) {
06904          return -1;
06905       }
06906 
06907       /* Initialize all settings before first configuration load. */
06908       manager_set_defaults();
06909    }
06910 
06911    cfg = ast_config_load2("manager.conf", "manager", config_flags);
06912    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06913       return 0;
06914    } else if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
06915       ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid.\n");
06916       return 0;
06917    }
06918 
06919    if (reload) {
06920       /* Reset all settings before reloading configuration */
06921       tls_was_enabled = ami_tls_cfg.enabled;
06922       manager_set_defaults();
06923    }
06924 
06925    ami_desc_local_address_tmp.sin_family = AF_INET;
06926    amis_desc_local_address_tmp.sin_family = AF_INET;
06927 
06928    ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT);
06929 
06930    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
06931       val = var->value;
06932 
06933       /* read tls config options while preventing unsupported options from being set */
06934       if (strcasecmp(var->name, "tlscafile")
06935          && strcasecmp(var->name, "tlscapath")
06936          && strcasecmp(var->name, "tlscadir")
06937          && strcasecmp(var->name, "tlsverifyclient")
06938          && strcasecmp(var->name, "tlsdontverifyserver")
06939          && strcasecmp(var->name, "tlsclientmethod")
06940          && strcasecmp(var->name, "sslclientmethod")
06941          && !ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
06942          continue;
06943       }
06944 
06945       if (!strcasecmp(var->name, "enabled")) {
06946          manager_enabled = ast_true(val);
06947       } else if (!strcasecmp(var->name, "webenabled")) {
06948          webmanager_enabled = ast_true(val);
06949       } else if (!strcasecmp(var->name, "port")) {
06950          ami_desc_local_address_tmp.sin_port = htons(atoi(val));
06951       } else if (!strcasecmp(var->name, "bindaddr")) {
06952          if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) {
06953             ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
06954             memset(&ami_desc_local_address_tmp.sin_addr, 0,
06955                    sizeof(ami_desc_local_address_tmp.sin_addr));
06956          }
06957       } else if (!strcasecmp(var->name, "brokeneventsaction")) {
06958          broken_events_action = ast_true(val);
06959       } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
06960          allowmultiplelogin = ast_true(val);
06961       } else if (!strcasecmp(var->name, "displayconnects")) {
06962          displayconnects = ast_true(val);
06963       } else if (!strcasecmp(var->name, "timestampevents")) {
06964          timestampevents = ast_true(val);
06965       } else if (!strcasecmp(var->name, "debug")) {
06966          manager_debug = ast_true(val);
06967       } else if (!strcasecmp(var->name, "httptimeout")) {
06968          newhttptimeout = atoi(val);
06969       } else if (!strcasecmp(var->name, "authtimeout")) {
06970          int timeout = atoi(var->value);
06971 
06972          if (timeout < 1) {
06973             ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
06974          } else {
06975             authtimeout = timeout;
06976          }
06977       } else if (!strcasecmp(var->name, "authlimit")) {
06978          int limit = atoi(var->value);
06979 
06980          if (limit < 1) {
06981             ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
06982          } else {
06983             authlimit = limit;
06984          }
06985       } else if (!strcasecmp(var->name, "channelvars")) {
06986          load_channelvars(var);
06987       } else {
06988          ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
06989             var->name, val);
06990       }
06991    }
06992 
06993    ast_sockaddr_to_sin(&amis_desc.local_address, &amis_desc_local_address_tmp);
06994 
06995    /* if the amis address has not been set, default is the same as non secure ami */
06996    if (!amis_desc_local_address_tmp.sin_addr.s_addr) {
06997       amis_desc_local_address_tmp.sin_addr =
06998           ami_desc_local_address_tmp.sin_addr;
06999    }
07000 
07001    if (!amis_desc_local_address_tmp.sin_port) {
07002       amis_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_TLS_PORT);
07003    }
07004 
07005    if (manager_enabled) {
07006       ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp);
07007       ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp);
07008    }
07009 
07010    AST_RWLIST_WRLOCK(&users);
07011 
07012    /* First, get users from users.conf */
07013    ucfg = ast_config_load2("users.conf", "manager", config_flags);
07014    if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
07015       const char *hasmanager;
07016       int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
07017 
07018       while ((cat = ast_category_browse(ucfg, cat))) {
07019          if (!strcasecmp(cat, "general")) {
07020             continue;
07021          }
07022 
07023          hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
07024          if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
07025             const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
07026             const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
07027             const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
07028             const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
07029             const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
07030 
07031             /* Look for an existing entry,
07032              * if none found - create one and add it to the list
07033              */
07034             if (!(user = get_manager_by_name_locked(cat))) {
07035                if (!(user = ast_calloc(1, sizeof(*user)))) {
07036                   break;
07037                }
07038 
07039                /* Copy name over */
07040                ast_copy_string(user->username, cat, sizeof(user->username));
07041                /* Insert into list */
07042                AST_LIST_INSERT_TAIL(&users, user, list);
07043                user->ha = NULL;
07044                user->keep = 1;
07045                user->readperm = -1;
07046                user->writeperm = -1;
07047                /* Default displayconnect from [general] */
07048                user->displayconnects = displayconnects;
07049                user->writetimeout = 100;
07050             }
07051 
07052             if (!user_secret) {
07053                user_secret = ast_variable_retrieve(ucfg, "general", "secret");
07054             }
07055             if (!user_read) {
07056                user_read = ast_variable_retrieve(ucfg, "general", "read");
07057             }
07058             if (!user_write) {
07059                user_write = ast_variable_retrieve(ucfg, "general", "write");
07060             }
07061             if (!user_displayconnects) {
07062                user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
07063             }
07064             if (!user_writetimeout) {
07065                user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
07066             }
07067 
07068             if (!ast_strlen_zero(user_secret)) {
07069                ast_free(user->secret);
07070                user->secret = ast_strdup(user_secret);
07071             }
07072 
07073             if (user_read) {
07074                user->readperm = get_perm(user_read);
07075             }
07076             if (user_write) {
07077                user->writeperm = get_perm(user_write);
07078             }
07079             if (user_displayconnects) {
07080                user->displayconnects = ast_true(user_displayconnects);
07081             }
07082             if (user_writetimeout) {
07083                int value = atoi(user_writetimeout);
07084                if (value < 100) {
07085                   ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value);
07086                } else {
07087                   user->writetimeout = value;
07088                }
07089             }
07090          }
07091       }
07092       ast_config_destroy(ucfg);
07093    }
07094 
07095    /* cat is NULL here in any case */
07096 
07097    while ((cat = ast_category_browse(cfg, cat))) {
07098       struct ast_ha *oldha;
07099 
07100       if (!strcasecmp(cat, "general")) {
07101          continue;
07102       }
07103 
07104       /* Look for an existing entry, if none found - create one and add it to the list */
07105       if (!(user = get_manager_by_name_locked(cat))) {
07106          if (!(user = ast_calloc(1, sizeof(*user)))) {
07107             break;
07108          }
07109          /* Copy name over */
07110          ast_copy_string(user->username, cat, sizeof(user->username));
07111 
07112          user->ha = NULL;
07113          user->readperm = 0;
07114          user->writeperm = 0;
07115          /* Default displayconnect from [general] */
07116          user->displayconnects = displayconnects;
07117          user->writetimeout = 100;
07118          user->whitefilters = ao2_container_alloc(1, NULL, NULL);
07119          user->blackfilters = ao2_container_alloc(1, NULL, NULL);
07120          if (!user->whitefilters || !user->blackfilters) {
07121             manager_free_user(user);
07122             break;
07123          }
07124 
07125          /* Insert into list */
07126          AST_RWLIST_INSERT_TAIL(&users, user, list);
07127       } else {
07128          ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
07129          ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
07130       }
07131 
07132       /* Make sure we keep this user and don't destroy it during cleanup */
07133       user->keep = 1;
07134       oldha = user->ha;
07135       user->ha = NULL;
07136 
07137       var = ast_variable_browse(cfg, cat);
07138       for (; var; var = var->next) {
07139          if (!strcasecmp(var->name, "secret")) {
07140             ast_free(user->secret);
07141             user->secret = ast_strdup(var->value);
07142          } else if (!strcasecmp(var->name, "deny") ||
07143                    !strcasecmp(var->name, "permit")) {
07144             user->ha = ast_append_ha(var->name, var->value, user->ha, NULL);
07145          }  else if (!strcasecmp(var->name, "read") ) {
07146             user->readperm = get_perm(var->value);
07147          }  else if (!strcasecmp(var->name, "write") ) {
07148             user->writeperm = get_perm(var->value);
07149          }  else if (!strcasecmp(var->name, "displayconnects") ) {
07150             user->displayconnects = ast_true(var->value);
07151          } else if (!strcasecmp(var->name, "writetimeout")) {
07152             int value = atoi(var->value);
07153             if (value < 100) {
07154                ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
07155             } else {
07156                user->writetimeout = value;
07157             }
07158          } else if (!strcasecmp(var->name, "eventfilter")) {
07159             const char *value = var->value;
07160             regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
07161             if (new_filter) {
07162                int is_blackfilter;
07163                if (value[0] == '!') {
07164                   is_blackfilter = 1;
07165                   value++;
07166                } else {
07167                   is_blackfilter = 0;
07168                }
07169                if (regcomp(new_filter, value, 0)) { /* XXX: the only place we use non-REG_EXTENDED */
07170                   ao2_t_ref(new_filter, -1, "failed to make regex");
07171                } else {
07172                   if (is_blackfilter) {
07173                      ao2_t_link(user->blackfilters, new_filter, "link new filter into black user container");
07174                   } else {
07175                      ao2_t_link(user->whitefilters, new_filter, "link new filter into white user container");
07176                   }
07177                }
07178             }
07179          } else {
07180             ast_debug(1, "%s is an unknown option.\n", var->name);
07181          }
07182       }
07183       ast_free_ha(oldha);
07184    }
07185    ast_config_destroy(cfg);
07186 
07187    /* Perform cleanup - essentially prune out old users that no longer exist */
07188    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
07189       if (user->keep) { /* valid record. clear flag for the next round */
07190          user->keep = 0;
07191 
07192          /* Calculate A1 for Digest auth */
07193          snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
07194          ast_md5_hash(a1_hash,a1);
07195          ast_free(user->a1_hash);
07196          user->a1_hash = ast_strdup(a1_hash);
07197          continue;
07198       }
07199       /* We do not need to keep this user so take them out of the list */
07200       AST_RWLIST_REMOVE_CURRENT(list);
07201       ast_debug(4, "Pruning user '%s'\n", user->username);
07202       manager_free_user(user);
07203    }
07204    AST_RWLIST_TRAVERSE_SAFE_END;
07205 
07206    AST_RWLIST_UNLOCK(&users);
07207 
07208    if (webmanager_enabled && manager_enabled) {
07209       if (!webregged) {
07210          ast_http_uri_link(&rawmanuri);
07211          ast_http_uri_link(&manageruri);
07212          ast_http_uri_link(&managerxmluri);
07213 
07214          ast_http_uri_link(&arawmanuri);
07215          ast_http_uri_link(&amanageruri);
07216          ast_http_uri_link(&amanagerxmluri);
07217          webregged = 1;
07218       }
07219    } else {
07220       if (webregged) {
07221          ast_http_uri_unlink(&rawmanuri);
07222          ast_http_uri_unlink(&manageruri);
07223          ast_http_uri_unlink(&managerxmluri);
07224 
07225          ast_http_uri_unlink(&arawmanuri);
07226          ast_http_uri_unlink(&amanageruri);
07227          ast_http_uri_unlink(&amanagerxmluri);
07228          webregged = 0;
07229       }
07230    }
07231 
07232    if (newhttptimeout > 0) {
07233       httptimeout = newhttptimeout;
07234    }
07235 
07236    manager_event(EVENT_FLAG_SYSTEM, "Reload",
07237       "Module: Manager\r\n"
07238       "Status: %s\r\n"
07239       "Message: Manager reload Requested\r\n",
07240       manager_enabled ? "Enabled" : "Disabled");
07241 
07242    ast_tcptls_server_start(&ami_desc);
07243    if (tls_was_enabled && !ami_tls_cfg.enabled) {
07244       ast_tcptls_server_stop(&amis_desc);
07245    } else if (ast_ssl_setup(amis_desc.tls_cfg)) {
07246       ast_tcptls_server_start(&amis_desc);
07247    }
07248 
07249    return 0;
07250 }

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

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

07274 {
07275    AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
07276 
07277    return 0;
07278 }

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

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

07286 {
07287    struct ast_datastore *datastore = NULL;
07288 
07289    if (info == NULL)
07290       return NULL;
07291 
07292    AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
07293       if (datastore->info != info) {
07294          continue;
07295       }
07296 
07297       if (uid == NULL) {
07298          /* matched by type only */
07299          break;
07300       }
07301 
07302       if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
07303          /* Matched by type AND uid */
07304          break;
07305       }
07306    }
07307    AST_LIST_TRAVERSE_SAFE_END;
07308 
07309    return datastore;
07310 }

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

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

07281 {
07282    return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
07283 }

int astman_is_authed ( uint32_t  ident  ) 

Determinie if a manager session ident is authenticated.

Definition at line 5618 of file manager.c.

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

Referenced by http_post_callback(), and static_callback().

05619 {
05620    int authed;
05621    struct mansession_session *session;
05622 
05623    if (!(session = find_session(ident, 0)))
05624       return 0;
05625 
05626    authed = (session->authenticated != 0);
05627 
05628    ao2_unlock(session);
05629    unref_mansession(session);
05630 
05631    return authed;
05632 }

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, mansession_session::managerid, mansession_session::readperm, sessions, and unref_mansession().

05635 {
05636    int result = 0;
05637    struct mansession_session *session;
05638    struct ao2_iterator i;
05639 
05640    if (ident == 0) {
05641       return 0;
05642    }
05643 
05644    i = ao2_iterator_init(sessions, 0);
05645    while ((session = ao2_iterator_next(&i))) {
05646       ao2_lock(session);
05647       if ((session->managerid == ident) && (session->readperm & perm)) {
05648          result = 1;
05649          ao2_unlock(session);
05650          unref_mansession(session);
05651          break;
05652       }
05653       ao2_unlock(session);
05654       unref_mansession(session);
05655    }
05656    ao2_iterator_destroy(&i);
05657    return result;
05658 }

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, mansession_session::managerid, sessions, unref_mansession(), and mansession_session::writeperm.

Referenced by http_post_callback().

05661 {
05662    int result = 0;
05663    struct mansession_session *session;
05664    struct ao2_iterator i;
05665 
05666    if (ident == 0) {
05667       return 0;
05668    }
05669 
05670    i = ao2_iterator_init(sessions, 0);
05671    while ((session = ao2_iterator_next(&i))) {
05672       ao2_lock(session);
05673       if ((session->managerid == ident) && (session->writeperm & perm)) {
05674          result = 1;
05675          ao2_unlock(session);
05676          unref_mansession(session);
05677          break;
05678       }
05679       ao2_unlock(session);
05680       unref_mansession(session);
05681    }
05682    ao2_iterator_destroy(&i);
05683    return result;
05684 }

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

Definition at line 6181 of file manager.c.

References ast_manager_user::a1_hash, ao2_lock, ao2_unlock, ARRAY_LEN, ast_apply_ha(), ast_copy_string(), ast_debug, ast_free, ast_get_http_method(), ast_http_auth(), ast_http_error(), AST_HTTP_GET, ast_http_get_post_vars(), AST_HTTP_HEAD, AST_HTTP_POST, ast_http_send(), ast_inet_ntoa(), AST_LIST_HEAD_INIT_NOLOCK, ast_log(), ast_malloc, ast_md5_hash(), ast_mutex_destroy, ast_mutex_init, ast_parse_digest(), ast_random(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_sockaddr_from_sin, 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(), ast_http_digest::cnonce, mansession_session::datastores, ast_manager_user::displayconnects, errno, mansession_session::f, mansession::f, mansession_session::fd, mansession::fd, find_session_by_nonce(), FORMAT_HTML, FORMAT_XML, get_manager_by_name_locked(), global_realm, grab_last(), ast_manager_user::ha, message::hdrcount, message::headers, mansession_session::last_ev, mansession::lock, LOG_NOTICE, LOG_WARNING, mansession_session::managerid, ast_variable::name, mansession_session::nc, ast_http_digest::nc, mansession_session::needdestroy, ast_variable::next, ast_http_digest::nonce, mansession_session::noncetime, mansession_session::oldnonce, process_message(), process_output(), ast_http_digest::qop, mansession_session::readperm, ast_manager_user::readperm, ast_http_digest::response, mansession::session, session_destroy(), mansession_session::sessionstart, mansession_session::sessiontimeout, mansession_session::sin, ast_http_digest::uri, mansession_session::username, ast_manager_user::username, ast_http_digest::username, ast_variable::value, mansession_session::writeperm, ast_manager_user::writeperm, mansession_session::writetimeout, and ast_manager_user::writetimeout.

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

06187 {
06188    struct mansession_session *session = NULL;
06189    struct mansession s = { .session = NULL, .tcptls_session = ser };
06190    struct ast_variable *v, *params = get_params;
06191    char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
06192    struct ast_str *http_header = NULL, *out = NULL;
06193    size_t result_size = 512;
06194    struct message m = { 0 };
06195    unsigned int idx;
06196    size_t hdrlen;
06197 
06198    time_t time_now = time(NULL);
06199    unsigned long nonce = 0, nc;
06200    struct ast_http_digest d = { NULL, };
06201    struct ast_manager_user *user = NULL;
06202    int stale = 0;
06203    char resp_hash[256]="";
06204    /* Cache for user data */
06205    char u_username[80];
06206    int u_readperm;
06207    int u_writeperm;
06208    int u_writetimeout;
06209    int u_displayconnects;
06210    struct ast_sockaddr addr;
06211 
06212    if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
06213       ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
06214       return -1;
06215    }
06216 
06217    /* Find "Authorization: " header */
06218    for (v = headers; v; v = v->next) {
06219       if (!strcasecmp(v->name, "Authorization")) {
06220          break;
06221       }
06222    }
06223 
06224    if (!v || ast_strlen_zero(v->value)) {
06225       goto out_401; /* Authorization Header not present - send auth request */
06226    }
06227 
06228    /* Digest found - parse */
06229    if (ast_string_field_init(&d, 128)) {
06230       ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
06231       return -1;
06232    }
06233 
06234    if (ast_parse_digest(v->value, &d, 0, 1)) {
06235       /* Error in Digest - send new one */
06236       nonce = 0;
06237       goto out_401;
06238    }
06239    if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
06240       ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
06241       nonce = 0;
06242       goto out_401;
06243    }
06244 
06245    AST_RWLIST_WRLOCK(&users);
06246    user = get_manager_by_name_locked(d.username);
06247    if(!user) {
06248       AST_RWLIST_UNLOCK(&users);
06249       ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
06250       nonce = 0;
06251       goto out_401;
06252    }
06253 
06254    ast_sockaddr_from_sin(&addr, remote_address);
06255    /* --- We have User for this auth, now check ACL */
06256    if (user->ha && !ast_apply_ha(user->ha, &addr)) {
06257       AST_RWLIST_UNLOCK(&users);
06258       ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
06259       ast_http_error(ser, 403, "Permission denied", "Permission denied\n");
06260       return -1;
06261    }
06262 
06263    /* --- We have auth, so check it */
06264 
06265    /* compute the expected response to compare with what we received */
06266    {
06267       char a2[256];
06268       char a2_hash[256];
06269       char resp[256];
06270 
06271       /* XXX Now request method are hardcoded in A2 */
06272       snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
06273       ast_md5_hash(a2_hash, a2);
06274 
06275       if (d.qop) {
06276          /* RFC 2617 */
06277          snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
06278       }  else {
06279          /* RFC 2069 */
06280          snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
06281       }
06282       ast_md5_hash(resp_hash, resp);
06283    }
06284 
06285    if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
06286       /* Something was wrong, so give the client to try with a new challenge */
06287       AST_RWLIST_UNLOCK(&users);
06288       nonce = 0;
06289       goto out_401;
06290    }
06291 
06292    /*
06293     * User are pass Digest authentication.
06294     * Now, cache the user data and unlock user list.
06295     */
06296    ast_copy_string(u_username, user->username, sizeof(u_username));
06297    u_readperm = user->readperm;
06298    u_writeperm = user->writeperm;
06299    u_displayconnects = user->displayconnects;
06300    u_writetimeout = user->writetimeout;
06301    AST_RWLIST_UNLOCK(&users);
06302 
06303    if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
06304       /*
06305        * Create new session.
06306        * While it is not in the list we don't need any locking
06307        */
06308       if (!(session = build_mansession(*remote_address))) {
06309          ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
06310          return -1;
06311       }
06312       ao2_lock(session);
06313 
06314       ast_copy_string(session->username, u_username, sizeof(session->username));
06315       session->managerid = nonce;
06316       session->last_ev = grab_last();
06317       AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
06318 
06319       session->readperm = u_readperm;
06320       session->writeperm = u_writeperm;
06321       session->writetimeout = u_writetimeout;
06322 
06323       if (u_displayconnects) {
06324          ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
06325       }
06326       session->noncetime = session->sessionstart = time_now;
06327       session->authenticated = 1;
06328    } else if (stale) {
06329       /*
06330        * Session found, but nonce is stale.
06331        *
06332        * This could be because an old request (w/old nonce) arrived.
06333        *
06334        * This may be as the result of http proxy usage (separate delay or
06335        * multipath) or in a situation where a page was refreshed too quickly
06336        * (seen in Firefox).
06337        *
06338        * In this situation, we repeat the 401 auth with the current nonce
06339        * value.
06340        */
06341       nonce = session->managerid;
06342       ao2_unlock(session);
06343       stale = 1;
06344       goto out_401;
06345    } else {
06346       sscanf(d.nc, "%30lx", &nc);
06347       if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
06348          /*
06349           * Nonce time expired (> 2 minutes) or something wrong with nonce
06350           * counter.
06351           *
06352           * Create new nonce key and resend Digest auth request. Old nonce
06353           * is saved for stale checking...
06354           */
06355          session->nc = 0; /* Reset nonce counter */
06356          session->oldnonce = session->managerid;
06357          nonce = session->managerid = ast_random();
06358          session->noncetime = time_now;
06359          ao2_unlock(session);
06360          stale = 1;
06361          goto out_401;
06362       } else {
06363          session->nc = nc; /* All OK, save nonce counter */
06364       }
06365    }
06366 
06367 
06368    /* Reset session timeout. */
06369    session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
06370    ao2_unlock(session);
06371 
06372    ast_mutex_init(&s.lock);
06373    s.session = session;
06374    s.fd = mkstemp(template);  /* create a temporary file for command output */
06375    unlink(template);
06376    if (s.fd <= -1) {
06377       ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
06378       goto auth_callback_out;
06379    }
06380    s.f = fdopen(s.fd, "w+");
06381    if (!s.f) {
06382       ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
06383       ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
06384       close(s.fd);
06385       goto auth_callback_out;
06386    }
06387 
06388    if (method == AST_HTTP_POST) {
06389       params = ast_http_get_post_vars(ser, headers);
06390    }
06391 
06392    for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
06393       hdrlen = strlen(v->name) + strlen(v->value) + 3;
06394       m.headers[m.hdrcount] = ast_malloc(hdrlen);
06395       if (!m.headers[m.hdrcount]) {
06396          /* Allocation failure */
06397          continue;
06398       }
06399       snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
06400       ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
06401       ++m.hdrcount;
06402    }
06403 
06404    if (process_message(&s, &m)) {
06405       if (u_displayconnects) {
06406          ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
06407       }
06408 
06409       session->needdestroy = 1;
06410    }
06411 
06412    /* Free request headers. */
06413    for (idx = 0; idx < m.hdrcount; ++idx) {
06414       ast_free((void *) m.headers[idx]);
06415       m.headers[idx] = NULL;
06416    }
06417 
06418    if (s.f) {
06419       result_size = ftell(s.f); /* Calculate approx. size of result */
06420    }
06421 
06422    http_header = ast_str_create(80);
06423    out = ast_str_create(result_size * 2 + 512);
06424 
06425    if (http_header == NULL || out == NULL) {
06426       ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
06427       goto auth_callback_out;
06428    }
06429 
06430    ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]);
06431 
06432    if (format == FORMAT_XML) {
06433       ast_str_append(&out, 0, "<ajax-response>\n");
06434    } else if (format == FORMAT_HTML) {
06435       ast_str_append(&out, 0,
06436       "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
06437       "<html><head>\r\n"
06438       "<title>Asterisk&trade; Manager Interface</title>\r\n"
06439       "</head><body style=\"background-color: #ffffff;\">\r\n"
06440       "<form method=\"POST\">\r\n"
06441       "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
06442       "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
06443       "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
06444       "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
06445    }
06446 
06447    process_output(&s, &out, params, format);
06448 
06449    if (format == FORMAT_XML) {
06450       ast_str_append(&out, 0, "</ajax-response>\n");
06451    } else if (format == FORMAT_HTML) {
06452       ast_str_append(&out, 0, "</table></form></body></html>\r\n");
06453    }
06454 
06455    ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
06456    http_header = out = NULL;
06457 
06458 auth_callback_out:
06459    ast_mutex_destroy(&s.lock);
06460 
06461    /* Clear resources and unlock manager session */
06462    if (method == AST_HTTP_POST && params) {
06463       ast_variables_destroy(params);
06464    }
06465 
06466    ast_free(http_header);
06467    ast_free(out);
06468 
06469    ao2_lock(session);
06470    if (session->f) {
06471       fclose(session->f);
06472    }
06473    session->f = NULL;
06474    session->fd = -1;
06475    ao2_unlock(session);
06476 
06477    if (session->needdestroy) {
06478       ast_debug(1, "Need destroy, doing it now!\n");
06479       session_destroy(session);
06480    }
06481    ast_string_field_free_memory(&d);
06482    return 0;
06483 
06484 out_401:
06485    if (!nonce) {
06486       nonce = ast_random();
06487    }
06488 
06489    ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
06490    ast_string_field_free_memory(&d);
06491    return 0;
06492 }

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

References ast_sockaddr_from_sin, ast_sockaddr_to_sin, auth_http_callback(), FORMAT_HTML, and ast_tcptls_session_instance::remote_address.

06554 {
06555    int retval;
06556    struct sockaddr_in ser_remote_address_tmp;
06557 
06558    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06559    retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06560    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06561    return retval;
06562 }

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

References ast_sockaddr_from_sin, ast_sockaddr_to_sin, auth_http_callback(), FORMAT_XML, and ast_tcptls_session_instance::remote_address.

06565 {
06566    int retval;
06567    struct sockaddr_in ser_remote_address_tmp;
06568 
06569    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06570    retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06571    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06572    return retval;
06573 }

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

References ast_sockaddr_from_sin, ast_sockaddr_to_sin, auth_http_callback(), FORMAT_RAW, and ast_tcptls_session_instance::remote_address.

06576 {
06577    int retval;
06578    struct sockaddr_in ser_remote_address_tmp;
06579 
06580    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06581    retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06582    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06583    return retval;
06584 }

static void close_mansession_file ( struct mansession s  )  [static]

Definition at line 5916 of file manager.c.

References ast_log(), errno, mansession::f, mansession::fd, and LOG_ERROR.

Referenced by process_output().

05917 {
05918    if (s->f) {
05919       if (fclose(s->f)) {
05920          ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
05921       }
05922       s->f = NULL;
05923       s->fd = -1;
05924    } else if (s->fd != -1) {
05925       /*
05926        * Issuing shutdown() is necessary here to avoid a race
05927        * condition where the last data written may not appear
05928        * in the TCP stream.  See ASTERISK-23548
05929        */
05930       shutdown(s->fd, SHUT_RDWR);
05931       if (close(s->fd)) {
05932          ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
05933       }
05934       s->fd = -1;
05935    } else {
05936       ast_log(LOG_ERROR, "Attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n");
05937    }
05938 }

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, ast_atomic_fetchadd_int(), mansession_session::inuse, mansession_session::managerid, mansession_session::needdestroy, sessions, and unref_mansession().

Referenced by astman_is_authed(), and generic_http_callback().

05560 {
05561    struct mansession_session *session;
05562    struct ao2_iterator i;
05563 
05564    if (ident == 0) {
05565       return NULL;
05566    }
05567 
05568    i = ao2_iterator_init(sessions, 0);
05569    while ((session = ao2_iterator_next(&i))) {
05570       ao2_lock(session);
05571       if (session->managerid == ident && !session->needdestroy) {
05572          ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
05573          break;
05574       }
05575       ao2_unlock(session);
05576       unref_mansession(session);
05577    }
05578    ao2_iterator_destroy(&i);
05579 
05580    return session;
05581 }

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, mansession_session::managerid, mansession_session::oldnonce, sessions, unref_mansession(), and mansession_session::username.

Referenced by auth_http_callback().

05593 {
05594    struct mansession_session *session;
05595    struct ao2_iterator i;
05596 
05597    if (nonce == 0 || username == NULL || stale == NULL) {
05598       return NULL;
05599    }
05600 
05601    i = ao2_iterator_init(sessions, 0);
05602    while ((session = ao2_iterator_next(&i))) {
05603       ao2_lock(session);
05604       if (!strcasecmp(session->username, username) && session->managerid == nonce) {
05605          *stale = 0;
05606          break;
05607       } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
05608          *stale = 1;
05609          break;
05610       }
05611       ao2_unlock(session);
05612       unref_mansession(session);
05613    }
05614    ao2_iterator_destroy(&i);
05615    return session;
05616 }

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

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

Definition at line 5970 of file manager.c.

References ao2_lock, ao2_unlock, ARRAY_LEN, ast_debug, ast_free, ast_http_error(), AST_HTTP_GET, ast_http_get_cookies(), ast_http_get_post_vars(), AST_HTTP_HEAD, AST_HTTP_POST, ast_http_send(), ast_inet_ntoa(), AST_LIST_HEAD_INIT_NOLOCK, ast_log(), ast_malloc, ast_mutex_destroy, ast_mutex_init, AST_PTHREADT_NULL, ast_random(), ast_str_append(), ast_str_create(), ast_variables_destroy(), ast_verb, mansession_session::authenticated, build_mansession(), errno, mansession_session::f, mansession::f, mansession::fd, mansession_session::fd, find_session(), FORMAT_HTML, FORMAT_XML, grab_last(), message::hdrcount, message::headers, mansession_session::inuse, mansession::lock, LOG_WARNING, manager_displayconnects(), mansession_session::managerid, ast_variable::name, mansession_session::needdestroy, ast_variable::next, process_message(), process_output(), ROW_FMT, mansession_session::send_events, mansession::session, session_destroy(), mansession_session::sessiontimeout, mansession_session::sin, TEST_STRING, mansession_session::username, ast_variable::value, and mansession_session::waiting_thread.

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

05976 {
05977    struct mansession s = { .session = NULL, .tcptls_session = ser };
05978    struct mansession_session *session = NULL;
05979    uint32_t ident = 0;
05980    int blastaway = 0;
05981    struct ast_variable *v, *cookies, *params = get_params;
05982    char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
05983    struct ast_str *http_header = NULL, *out = NULL;
05984    struct message m = { 0 };
05985    unsigned int idx;
05986    size_t hdrlen;
05987 
05988    if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
05989       ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
05990       return -1;
05991    }
05992 
05993    cookies = ast_http_get_cookies(headers);
05994    for (v = cookies; v; v = v->next) {
05995       if (!strcasecmp(v->name, "mansession_id")) {
05996          sscanf(v->value, "%30x", &ident);
05997          break;
05998       }
05999    }
06000    if (cookies) {
06001       ast_variables_destroy(cookies);
06002    }
06003 
06004    if (!(session = find_session(ident, 1))) {
06005 
06006       /**/
06007       /* Create new session.
06008        * While it is not in the list we don't need any locking
06009        */
06010       if (!(session = build_mansession(*remote_address))) {
06011          ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
06012          return -1;
06013       }
06014       ao2_lock(session);
06015       session->sin = *remote_address;
06016       session->fd = -1;
06017       session->waiting_thread = AST_PTHREADT_NULL;
06018       session->send_events = 0;
06019       session->inuse = 1;
06020       /*!\note There is approximately a 1 in 1.8E19 chance that the following
06021        * calculation will produce 0, which is an invalid ID, but due to the
06022        * properties of the rand() function (and the constantcy of s), that
06023        * won't happen twice in a row.
06024        */
06025       while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
06026       session->last_ev = grab_last();
06027       AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
06028    }
06029    ao2_unlock(session);
06030 
06031    http_header = ast_str_create(128);
06032    out = ast_str_create(2048);
06033 
06034    ast_mutex_init(&s.lock);
06035 
06036    if (http_header == NULL || out == NULL) {
06037       ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
06038       goto generic_callback_out;
06039    }
06040 
06041    s.session = session;
06042    s.fd = mkstemp(template);  /* create a temporary file for command output */
06043    unlink(template);
06044    if (s.fd <= -1) {
06045       ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
06046       goto generic_callback_out;
06047    }
06048    s.f = fdopen(s.fd, "w+");
06049    if (!s.f) {
06050       ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
06051       ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
06052       close(s.fd);
06053       goto generic_callback_out;
06054    }
06055 
06056    if (method == AST_HTTP_POST) {
06057       params = ast_http_get_post_vars(ser, headers);
06058    }
06059 
06060    for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
06061       hdrlen = strlen(v->name) + strlen(v->value) + 3;
06062       m.headers[m.hdrcount] = ast_malloc(hdrlen);
06063       if (!m.headers[m.hdrcount]) {
06064          /* Allocation failure */
06065          continue;
06066       }
06067       snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
06068       ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
06069       ++m.hdrcount;
06070    }
06071 
06072    if (process_message(&s, &m)) {
06073       if (session->authenticated) {
06074          if (manager_displayconnects(session)) {
06075             ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
06076          }
06077       } else {
06078          if (displayconnects) {
06079             ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
06080          }
06081       }
06082       session->needdestroy = 1;
06083    }
06084 
06085    /* Free request headers. */
06086    for (idx = 0; idx < m.hdrcount; ++idx) {
06087       ast_free((void *) m.headers[idx]);
06088       m.headers[idx] = NULL;
06089    }
06090 
06091    ast_str_append(&http_header, 0,
06092       "Content-type: text/%s\r\n"
06093       "Cache-Control: no-cache;\r\n"
06094       "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
06095       "Pragma: SuppressEvents\r\n",
06096       contenttype[format],
06097       session->managerid, httptimeout);
06098 
06099    if (format == FORMAT_XML) {
06100       ast_str_append(&out, 0, "<ajax-response>\n");
06101    } else if (format == FORMAT_HTML) {
06102       /*
06103        * When handling AMI-over-HTTP in HTML format, we provide a simple form for
06104        * debugging purposes. This HTML code should not be here, we
06105        * should read from some config file...
06106        */
06107 
06108 #define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
06109 #define TEST_STRING \
06110    "<form action=\"manager\" method=\"post\">\n\
06111    Action: <select name=\"action\">\n\
06112       <option value=\"\">-----&gt;</option>\n\
06113       <option value=\"login\">login</option>\n\
06114       <option value=\"command\">Command</option>\n\
06115       <option value=\"waitevent\">waitevent</option>\n\
06116       <option value=\"listcommands\">listcommands</option>\n\
06117    </select>\n\
06118    or <input name=\"action\"><br/>\n\
06119    CLI Command <input name=\"command\"><br>\n\
06120    user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
06121    <input type=\"submit\">\n</form>\n"
06122 
06123       ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
06124       ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
06125       ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
06126       ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
06127    }
06128 
06129    process_output(&s, &out, params, format);
06130 
06131    if (format == FORMAT_XML) {
06132       ast_str_append(&out, 0, "</ajax-response>\n");
06133    } else if (format == FORMAT_HTML) {
06134       ast_str_append(&out, 0, "</table></body>\r\n");
06135    }
06136 
06137    ao2_lock(session);
06138    /* Reset HTTP timeout.  If we're not authenticated, keep it extremely short */
06139    session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
06140 
06141    if (session->needdestroy) {
06142       if (session->inuse == 1) {
06143          ast_debug(1, "Need destroy, doing it now!\n");
06144          blastaway = 1;
06145       } else {
06146          ast_debug(1, "Need destroy, but can't do it yet!\n");
06147          if (session->waiting_thread != AST_PTHREADT_NULL) {
06148             pthread_kill(session->waiting_thread, SIGURG);
06149          }
06150          session->inuse--;
06151       }
06152    } else {
06153       session->inuse--;
06154    }
06155    ao2_unlock(session);
06156 
06157    ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
06158    http_header = out = NULL;
06159 
06160 generic_callback_out:
06161    ast_mutex_destroy(&s.lock);
06162 
06163    /* Clear resource */
06164 
06165    if (method == AST_HTTP_POST && params) {
06166       ast_variables_destroy(params);
06167    }
06168    ast_free(http_header);
06169    ast_free(out);
06170 
06171    if (session && blastaway) {
06172       session_destroy(session);
06173    } else if (session && session->f) {
06174       fclose(session->f);
06175       session->f = NULL;
06176    }
06177 
06178    return 0;
06179 }

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

References ami_tls_cfg, 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, ast_tls_config::pvtfile, S_OR, and ast_cli_entry::usage.

06648 {
06649    switch (cmd) {
06650    case CLI_INIT:
06651       e->command = "manager show settings";
06652       e->usage =
06653          "Usage: manager show settings\n"
06654          "       Provides detailed list of the configuration of the Manager.\n";
06655       return NULL;
06656    case CLI_GENERATE:
06657       return NULL;
06658    }
06659 #define FORMAT "  %-25.25s  %-15.15s\n"
06660 #define FORMAT2 "  %-25.25s  %-15d\n"
06661    if (a->argc != 3) {
06662       return CLI_SHOWUSAGE;
06663    }
06664    ast_cli(a->fd, "\nGlobal Settings:\n");
06665    ast_cli(a->fd, "----------------\n");
06666    ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
06667    ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
06668    ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
06669    ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
06670    ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
06671    ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
06672    ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
06673    ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
06674    ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
06675    ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
06676    ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
06677    ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
06678    ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
06679    ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
06680 #undef FORMAT
06681 #undef FORMAT2
06682 
06683    return CLI_SUCCESS;
06684 }

int init_manager ( void   ) 

Called by Asterisk initialization.

Definition at line 7263 of file manager.c.

References __init_manager().

Referenced by main().

07264 {
07265    return __init_manager(0);
07266 }

static void load_channelvars ( struct ast_variable var  )  [static]

Definition at line 6706 of file manager.c.

References ast_calloc, ast_free, AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_strdupa, free_channelvars(), manager_channel_variable::isfunc, manager_channel_variable::name, eventqent::next, and ast_variable::value.

Referenced by __init_manager().

06707 {
06708    struct manager_channel_variable *mcv;
06709    char *remaining = ast_strdupa(var->value);
06710    char *next;
06711 
06712    ast_free(manager_channelvars);
06713    manager_channelvars = ast_strdup(var->value);
06714 
06715    /*
06716     * XXX TODO: To allow dialplan functions to have more than one
06717     * parameter requires eliminating the '|' as a separator so we
06718     * could use AST_STANDARD_APP_ARGS() to separate items.
06719     */
06720    free_channelvars();
06721    AST_RWLIST_WRLOCK(&channelvars);
06722    while ((next = strsep(&remaining, ",|"))) {
06723       if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
06724          break;
06725       }
06726       strcpy(mcv->name, next); /* SAFE */
06727       if (strchr(next, '(')) {
06728          mcv->isfunc = 1;
06729       }
06730       AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
06731    }
06732    AST_RWLIST_UNLOCK(&channelvars);
06733 }

static void manager_free_user ( struct ast_manager_user user  )  [static]

Definition at line 6736 of file manager.c.

References ast_manager_user::a1_hash, ao2_t_ref, ast_free, ast_free_ha(), ast_manager_user::blackfilters, ast_manager_user::ha, ast_manager_user::secret, and ast_manager_user::whitefilters.

Referenced by __init_manager(), and manager_shutdown().

06737 {
06738    ast_free(user->a1_hash);
06739    ast_free(user->secret);
06740    if (user->whitefilters) {
06741       ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
06742    }
06743    if (user->blackfilters) {
06744       ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
06745    }
06746    ast_free_ha(user->ha);
06747    ast_free(user);
06748 }

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

References ast_sockaddr_from_sin, ast_sockaddr_to_sin, FORMAT_HTML, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

06495 {
06496    int retval;
06497    struct sockaddr_in ser_remote_address_tmp;
06498 
06499    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06500    retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06501    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06502    return retval;
06503 }

static void manager_set_defaults ( void   )  [static]
static void manager_shutdown ( void   )  [static]

Definition at line 6751 of file manager.c.

References ami_tls_cfg, ARRAY_LEN, ast_cli_unregister_multiple(), ast_free, AST_LIST_REMOVE_HEAD, ast_manager_unregister(), ast_tcptls_server_stop(), ast_tls_config::certfile, ast_tls_config::cipher, ast_manager_user::list, manager_free_user(), and ast_tls_config::pvtfile.

Referenced by __init_manager().

06752 {
06753    struct ast_manager_user *user;
06754 
06755    ast_manager_unregister("Ping");
06756    ast_manager_unregister("Events");
06757    ast_manager_unregister("Logoff");
06758    ast_manager_unregister("Login");
06759    ast_manager_unregister("Challenge");
06760    ast_manager_unregister("Hangup");
06761    ast_manager_unregister("Status");
06762    ast_manager_unregister("Setvar");
06763    ast_manager_unregister("Getvar");
06764    ast_manager_unregister("GetConfig");
06765    ast_manager_unregister("GetConfigJSON");
06766    ast_manager_unregister("UpdateConfig");
06767    ast_manager_unregister("CreateConfig");
06768    ast_manager_unregister("ListCategories");
06769    ast_manager_unregister("Redirect");
06770    ast_manager_unregister("Atxfer");
06771    ast_manager_unregister("Originate");
06772    ast_manager_unregister("Command");
06773    ast_manager_unregister("ExtensionState");
06774    ast_manager_unregister("AbsoluteTimeout");
06775    ast_manager_unregister("MailboxStatus");
06776    ast_manager_unregister("MailboxCount");
06777    ast_manager_unregister("ListCommands");
06778    ast_manager_unregister("SendText");
06779    ast_manager_unregister("UserEvent");
06780    ast_manager_unregister("WaitEvent");
06781    ast_manager_unregister("CoreSettings");
06782    ast_manager_unregister("CoreStatus");
06783    ast_manager_unregister("Reload");
06784    ast_manager_unregister("CoreShowChannels");
06785    ast_manager_unregister("ModuleLoad");
06786    ast_manager_unregister("ModuleCheck");
06787    ast_manager_unregister("AOCMessage");
06788    ast_manager_unregister("Filter");
06789    ast_cli_unregister_multiple(cli_manager, ARRAY_LEN(cli_manager));
06790 
06791    ast_tcptls_server_stop(&ami_desc);
06792    ast_tcptls_server_stop(&amis_desc);
06793 
06794    ast_free(ami_tls_cfg.certfile);
06795    ami_tls_cfg.certfile = NULL;
06796    ast_free(ami_tls_cfg.pvtfile);
06797    ami_tls_cfg.pvtfile = NULL;
06798    ast_free(ami_tls_cfg.cipher);
06799    ami_tls_cfg.cipher = NULL;
06800 
06801    /*
06802     * We cannot destroy the global sessions container.
06803     * References to it have no protection against shutdown.
06804     */
06805 
06806    while ((user = AST_LIST_REMOVE_HEAD(&users, list))) {
06807       manager_free_user(user);
06808    }
06809 }

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

References ast_sockaddr_from_sin, ast_sockaddr_to_sin, FORMAT_XML, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

06506 {
06507    int retval;
06508    struct sockaddr_in ser_remote_address_tmp;
06509 
06510    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06511    retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06512    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06513    return retval;
06514 }

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

Definition at line 5940 of file manager.c.

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

Referenced by auth_http_callback(), and generic_http_callback().

05941 {
05942    char *buf;
05943    size_t l;
05944 
05945    if (!s->f)
05946       return;
05947 
05948    /* Ensure buffer is NULL-terminated */
05949    fprintf(s->f, "%c", 0);
05950    fflush(s->f);
05951 
05952    if ((l = ftell(s->f)) > 0) {
05953       if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) {
05954          ast_log(LOG_WARNING, "mmap failed.  Manager output was not processed\n");
05955       } else {
05956          if (format == FORMAT_XML || format == FORMAT_HTML) {
05957             xml_translate(out, buf, params, format);
05958          } else {
05959             ast_str_append(out, 0, "%s", buf);
05960          }
05961          munmap(buf, l);
05962       }
05963    } else if (format == FORMAT_XML || format == FORMAT_HTML) {
05964       xml_translate(out, "", params, format);
05965    }
05966 
05967    close_mansession_file(s);
05968 }

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

References purge_events(), and purge_sessions().

06619 {
06620    purge_sessions(1);
06621    purge_events();
06622 }

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

References ast_sockaddr_from_sin, ast_sockaddr_to_sin, FORMAT_RAW, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

06517 {
06518    int retval;
06519    struct sockaddr_in ser_remote_address_tmp;
06520 
06521    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06522    retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06523    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06524    return retval;
06525 }

int reload_manager ( void   ) 

Called by Asterisk module functions and the CLI command.

Definition at line 7268 of file manager.c.

References __init_manager().

Referenced by handle_manager_reload().

07269 {
07270    return __init_manager(1);
07271 }

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

Definition at line 5760 of file manager.c.

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

Referenced by xml_translate().

05761 {
05762    /* Due to the simplicity of struct variable_count, it makes no difference
05763     * if you pass in objects or strings, the same operation applies. This is
05764     * due to the fact that the hash occurs on the first element, which means
05765     * the address of both the struct and the string are exactly the same. */
05766    struct variable_count *vc = obj;
05767    char *str = vstr;
05768    return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
05769 }

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

Definition at line 5753 of file manager.c.

References ast_str_hash(), and variable_count::varname.

Referenced by xml_translate().

05754 {
05755    const struct variable_count *vc = vvc;
05756 
05757    return ast_str_hash(vc->varname);
05758 }

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

Definition at line 5691 of file manager.c.

References ast_str_append().

Referenced by xml_translate().

05692 {
05693    /* store in a local buffer to avoid calling ast_str_append too often */
05694    char buf[256];
05695    char *dst = buf;
05696    int space = sizeof(buf);
05697    /* repeat until done and nothing to flush */
05698    for ( ; *src || dst != buf ; src++) {
05699       if (*src == '\0' || space < 10) {   /* flush */
05700          *dst++ = '\0';
05701          ast_str_append(out, 0, "%s", buf);
05702          dst = buf;
05703          space = sizeof(buf);
05704          if (*src == '\0') {
05705             break;
05706          }
05707       }
05708 
05709       if ( (mode & 2) && !isalnum(*src)) {
05710          *dst++ = '_';
05711          space--;
05712          continue;
05713       }
05714       switch (*src) {
05715       case '<':
05716          strcpy(dst, "&lt;");
05717          dst += 4;
05718          space -= 4;
05719          break;
05720       case '>':
05721          strcpy(dst, "&gt;");
05722          dst += 4;
05723          space -= 4;
05724          break;
05725       case '\"':
05726          strcpy(dst, "&quot;");
05727          dst += 6;
05728          space -= 6;
05729          break;
05730       case '\'':
05731          strcpy(dst, "&apos;");
05732          dst += 6;
05733          space -= 6;
05734          break;
05735       case '&':
05736          strcpy(dst, "&amp;");
05737          dst += 5;
05738          space -= 5;
05739          break;
05740 
05741       default:
05742          *dst++ = mode ? tolower(*src) : *src;
05743          space--;
05744       }
05745    }
05746 }

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

Referenced by process_output().

05800 {
05801    struct ast_variable *v;
05802    const char *dest = NULL;
05803    char *var, *val;
05804    const char *objtype = NULL;
05805    int in_data = 0;  /* parsing data */
05806    int inobj = 0;
05807    int xml = (format == FORMAT_XML);
05808    struct variable_count *vc = NULL;
05809    struct ao2_container *vco = NULL;
05810 
05811    if (xml) {
05812       /* dest and objtype need only for XML format */
05813       for (v = get_vars; v; v = v->next) {
05814          if (!strcasecmp(v->name, "ajaxdest")) {
05815             dest = v->value;
05816          } else if (!strcasecmp(v->name, "ajaxobjtype")) {
05817             objtype = v->value;
05818          }
05819       }
05820       if (ast_strlen_zero(dest)) {
05821          dest = "unknown";
05822       }
05823       if (ast_strlen_zero(objtype)) {
05824          objtype = "generic";
05825       }
05826    }
05827 
05828    /* we want to stop when we find an empty line */
05829    while (in && *in) {
05830       val = strsep(&in, "\r\n"); /* mark start and end of line */
05831       if (in && *in == '\n') {   /* remove trailing \n if any */
05832          in++;
05833       }
05834       ast_trim_blanks(val);
05835       ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
05836       if (ast_strlen_zero(val)) {
05837          /* empty line */
05838          if (in_data) {
05839             /* close data in Opaque mode */
05840             ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05841             in_data = 0;
05842          }
05843 
05844          if (inobj) {
05845             /* close block */
05846             ast_str_append(out, 0, xml ? " /></response>\n" :
05847                "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05848             inobj = 0;
05849             ao2_ref(vco, -1);
05850             vco = NULL;
05851          }
05852          continue;
05853       }
05854 
05855       if (!inobj) {
05856          /* start new block */
05857          if (xml) {
05858             ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
05859          }
05860          vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
05861          inobj = 1;
05862       }
05863 
05864       if (in_data) {
05865          /* Process data field in Opaque mode. This is a
05866           * followup, so we re-add line feeds. */
05867          ast_str_append(out, 0, xml ? "\n" : "<br>\n");
05868          xml_copy_escape(out, val, 0);   /* data field */
05869          continue;
05870       }
05871 
05872       /* We expect "Name: value" line here */
05873       var = strsep(&val, ":");
05874       if (val) {
05875          /* found the field name */
05876          val = ast_skip_blanks(val);
05877          ast_trim_blanks(var);
05878       } else {
05879          /* field name not found, switch to opaque mode */
05880          val = var;
05881          var = "Opaque-data";
05882          in_data = 1;
05883       }
05884 
05885 
05886       ast_str_append(out, 0, xml ? " " : "<tr><td>");
05887       if ((vc = ao2_find(vco, var, 0))) {
05888          vc->count++;
05889       } else {
05890          /* Create a new entry for this one */
05891          vc = ao2_alloc(sizeof(*vc), NULL);
05892          vc->varname = var;
05893          vc->count = 1;
05894          ao2_link(vco, vc);
05895       }
05896 
05897       xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
05898       if (vc->count > 1) {
05899          ast_str_append(out, 0, "-%d", vc->count);
05900       }
05901       ao2_ref(vc, -1);
05902       ast_str_append(out, 0, xml ? "='" : "</td><td>");
05903       xml_copy_escape(out, val, 0); /* data field */
05904       if (!in_data || !*in) {
05905          ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05906       }
05907    }
05908 
05909    if (inobj) {
05910       ast_str_append(out, 0, xml ? " /></response>\n" :
05911          "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05912       ao2_ref(vco, -1);
05913    }
05914 }


Variable Documentation

struct ast_http_uri amanageruri [static]

Definition at line 6595 of file manager.c.

struct ast_http_uri amanagerxmluri [static]

Definition at line 6604 of file manager.c.

Definition at line 6625 of file manager.c.

struct ast_tls_config ami_tls_cfg [static]

Definition at line 6636 of file manager.c.

struct ast_http_uri arawmanuri [static]

Definition at line 6586 of file manager.c.

struct ast_cli_entry cli_manager[] [static]

Definition at line 6686 of file manager.c.

const char* const contenttype[] [static]
Initial value:
 {
   [FORMAT_RAW] = "plain",
   [FORMAT_HTML] = "html",
   [FORMAT_XML] =  "xml",
}

Definition at line 5548 of file manager.c.

struct ast_http_uri manageruri [static]

Definition at line 6535 of file manager.c.

struct ast_http_uri managerxmluri [static]

Definition at line 6543 of file manager.c.

struct ast_http_uri rawmanuri [static]

Definition at line 6527 of file manager.c.

int webregged = 0 [static]

Definition at line 6613 of file manager.c.

const char* words[AST_MAX_CMD_LEN]

Definition at line 929 of file manager.c.

Referenced by check_blacklist().


Generated on 17 Aug 2018 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1