Tue Aug 20 16:35:06 2013

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.
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 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_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 block_sockets
static int broken_events_action
static struct ast_cli_entry cli_manager []
struct {
   const char *   words [AST_MAX_CMD_LEN]
command_blacklist []
static const char *const contenttype []
static const int DEFAULT_AUTHLIMIT = 50
static const int DEFAULT_AUTHTIMEOUT = 30
static const int DEFAULT_BLOCKSOCKETS = 0
static const int DEFAULT_BROKENEVENTSACTION = 0
static const int DEFAULT_DISPLAYCONNECTS = 1
static const int DEFAULT_ENABLED = 0
static const int DEFAULT_HTTPTIMEOUT = 60
static const int DEFAULT_MANAGERDEBUG = 0
static const int DEFAULT_TIMESTAMPEVENTS = 0
static const int DEFAULT_WEBENABLED = 0
static int displayconnects
static char global_realm [MAXHOSTNAMELEN]
static int httptimeout
static char * manager_channelvars
static int manager_debug = 0
static int manager_enabled = 0
static struct ast_threadstorage manager_event_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_manager_event_buf , .custom_init = NULL , }
static struct ast_threadstorage manager_event_funcbuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_manager_event_funcbuf , .custom_init = NULL , }
static struct ast_http_uri manageruri
static struct ast_http_uri managerxmluri
static struct permalias perms []
static struct ast_http_uri rawmanuri
static int registered = 0
static struct ao2_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 5511 of file manager.c.

05511                    {
05512    FORMAT_RAW,
05513    FORMAT_HTML,
05514    FORMAT_XML,
05515 };


Function Documentation

static int __init_manager ( int  reload  )  [static]

Definition at line 6785 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_CERTFILE, ast_cli_register_multiple(), ast_config_AST_SYSTEM_NAME, ast_config_destroy(), ast_config_load2(), ast_copy_string(), ast_debug, ast_extension_state_add(), ast_free, ast_free_ha(), ast_http_uri_link(), ast_http_uri_unlink(), AST_LIST_INSERT_TAIL, ast_log(), ast_manager_register_xml, ast_md5_hash(), ast_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_setnull(), 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, block_sockets, ast_tls_config::certfile, ast_tls_config::cipher, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_MANAGER_PORT, DEFAULT_MANAGER_TLS_PORT, DEFAULT_REALM, 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, free_channelvars(), 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_shutdown(), manager_state_cb(), mansession_cmp_fn(), ast_variable::name, ast_variable::next, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, ast_tls_config::pvtfile, ast_manager_user::readperm, S_OR, 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().

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

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

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

07243 {
07244    AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
07245 
07246    return 0;
07247 }

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 7254 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.

07255 {
07256    struct ast_datastore *datastore = NULL;
07257 
07258    if (info == NULL)
07259       return NULL;
07260 
07261    AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
07262       if (datastore->info != info) {
07263          continue;
07264       }
07265 
07266       if (uid == NULL) {
07267          /* matched by type only */
07268          break;
07269       }
07270 
07271       if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
07272          /* Matched by type AND uid */
07273          break;
07274       }
07275    }
07276    AST_LIST_TRAVERSE_SAFE_END;
07277 
07278    return datastore;
07279 }

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

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

07250 {
07251    return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
07252 }

int astman_is_authed ( uint32_t  ident  ) 

Determinie if a manager session ident is authenticated.

Definition at line 5587 of file manager.c.

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

Referenced by http_post_callback(), and static_callback().

05588 {
05589    int authed;
05590    struct mansession_session *session;
05591 
05592    if (!(session = find_session(ident, 0)))
05593       return 0;
05594 
05595    authed = (session->authenticated != 0);
05596 
05597    ao2_unlock(session);
05598    unref_mansession(session);
05599 
05600    return authed;
05601 }

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 5603 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().

05604 {
05605    int result = 0;
05606    struct mansession_session *session;
05607    struct ao2_iterator i;
05608 
05609    if (ident == 0) {
05610       return 0;
05611    }
05612 
05613    i = ao2_iterator_init(sessions, 0);
05614    while ((session = ao2_iterator_next(&i))) {
05615       ao2_lock(session);
05616       if ((session->managerid == ident) && (session->readperm & perm)) {
05617          result = 1;
05618          ao2_unlock(session);
05619          unref_mansession(session);
05620          break;
05621       }
05622       ao2_unlock(session);
05623       unref_mansession(session);
05624    }
05625    ao2_iterator_destroy(&i);
05626    return result;
05627 }

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 5629 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().

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

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 6143 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().

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

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 6515 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.

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

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 6526 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.

06527 {
06528    int retval;
06529    struct sockaddr_in ser_remote_address_tmp;
06530 
06531    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06532    retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06533    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06534    return retval;
06535 }

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 6537 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.

06538 {
06539    int retval;
06540    struct sockaddr_in ser_remote_address_tmp;
06541 
06542    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06543    retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06544    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06545    return retval;
06546 }

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 5528 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().

05529 {
05530    struct mansession_session *session;
05531    struct ao2_iterator i;
05532 
05533    if (ident == 0) {
05534       return NULL;
05535    }
05536 
05537    i = ao2_iterator_init(sessions, 0);
05538    while ((session = ao2_iterator_next(&i))) {
05539       ao2_lock(session);
05540       if (session->managerid == ident && !session->needdestroy) {
05541          ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
05542          break;
05543       }
05544       ao2_unlock(session);
05545       unref_mansession(session);
05546    }
05547    ao2_iterator_destroy(&i);
05548 
05549    return session;
05550 }

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 5561 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().

05562 {
05563    struct mansession_session *session;
05564    struct ao2_iterator i;
05565 
05566    if (nonce == 0 || username == NULL || stale == NULL) {
05567       return NULL;
05568    }
05569 
05570    i = ao2_iterator_init(sessions, 0);
05571    while ((session = ao2_iterator_next(&i))) {
05572       ao2_lock(session);
05573       if (!strcasecmp(session->username, username) && session->managerid == nonce) {
05574          *stale = 0;
05575          break;
05576       } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
05577          *stale = 1;
05578          break;
05579       }
05580       ao2_unlock(session);
05581       unref_mansession(session);
05582    }
05583    ao2_iterator_destroy(&i);
05584    return session;
05585 }

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 5928 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().

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

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

References ami_tls_cfg, ast_cli_args::argc, ast_cli(), AST_CLI_YESNO, ast_sockaddr_stringify(), block_sockets, ast_tls_config::certfile, ast_tls_config::cipher, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, 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.

06611 {
06612    switch (cmd) {
06613    case CLI_INIT:
06614       e->command = "manager show settings";
06615       e->usage =
06616          "Usage: manager show settings\n"
06617          "       Provides detailed list of the configuration of the Manager.\n";
06618       return NULL;
06619    case CLI_GENERATE:
06620       return NULL;
06621    }
06622 #define FORMAT "  %-25.25s  %-15.15s\n"
06623 #define FORMAT2 "  %-25.25s  %-15d\n"
06624    if (a->argc != 3) {
06625       return CLI_SHOWUSAGE;
06626    }
06627    ast_cli(a->fd, "\nGlobal Settings:\n");
06628    ast_cli(a->fd, "----------------\n");
06629    ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
06630    ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
06631    ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
06632    ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
06633    ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
06634    ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
06635    ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
06636    ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
06637    ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
06638    ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
06639    ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
06640    ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
06641    ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
06642    ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
06643    ast_cli(a->fd, FORMAT, "Block sockets:", AST_CLI_YESNO(block_sockets));
06644 #undef FORMAT
06645 #undef FORMAT2
06646 
06647    return CLI_SUCCESS;
06648 }

int init_manager ( void   ) 

Called by Asterisk initialization.

Definition at line 7232 of file manager.c.

References __init_manager().

Referenced by main().

07233 {
07234    return __init_manager(0);
07235 }

static void load_channelvars ( struct ast_variable var  )  [static]

Definition at line 6670 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().

06671 {
06672    struct manager_channel_variable *mcv;
06673    char *remaining = ast_strdupa(var->value);
06674    char *next;
06675 
06676    ast_free(manager_channelvars);
06677    manager_channelvars = ast_strdup(var->value);
06678 
06679    /*
06680     * XXX TODO: To allow dialplan functions to have more than one
06681     * parameter requires eliminating the '|' as a separator so we
06682     * could use AST_STANDARD_APP_ARGS() to separate items.
06683     */
06684    free_channelvars();
06685    AST_RWLIST_WRLOCK(&channelvars);
06686    while ((next = strsep(&remaining, ",|"))) {
06687       if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
06688          break;
06689       }
06690       strcpy(mcv->name, next); /* SAFE */
06691       if (strchr(next, '(')) {
06692          mcv->isfunc = 1;
06693       }
06694       AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
06695    }
06696    AST_RWLIST_UNLOCK(&channelvars);
06697 }

static void manager_free_user ( struct ast_manager_user user  )  [static]

Definition at line 6700 of file manager.c.

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

Referenced by __init_manager(), and manager_shutdown().

06701 {
06702    if (user->a1_hash) {
06703       ast_free(user->a1_hash);
06704    }
06705    if (user->secret) {
06706       ast_free(user->secret);
06707    }
06708    ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
06709    ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
06710    ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
06711    ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
06712    ast_free_ha(user->ha);
06713    ast_free(user);
06714 }

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 6456 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.

06457 {
06458    int retval;
06459    struct sockaddr_in ser_remote_address_tmp;
06460 
06461    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06462    retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06463    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06464    return retval;
06465 }

static void manager_shutdown ( void   )  [static]

Definition at line 6717 of file manager.c.

References ami_tls_cfg, ao2_ref, 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(), ast_tls_config::pvtfile, and sessions.

Referenced by __init_manager().

06718 {
06719    struct ast_manager_user *user;
06720 
06721    if (registered) {
06722       ast_manager_unregister("Ping");
06723       ast_manager_unregister("Events");
06724       ast_manager_unregister("Logoff");
06725       ast_manager_unregister("Login");
06726       ast_manager_unregister("Challenge");
06727       ast_manager_unregister("Hangup");
06728       ast_manager_unregister("Status");
06729       ast_manager_unregister("Setvar");
06730       ast_manager_unregister("Getvar");
06731       ast_manager_unregister("GetConfig");
06732       ast_manager_unregister("GetConfigJSON");
06733       ast_manager_unregister("UpdateConfig");
06734       ast_manager_unregister("CreateConfig");
06735       ast_manager_unregister("ListCategories");
06736       ast_manager_unregister("Redirect");
06737       ast_manager_unregister("Atxfer");
06738       ast_manager_unregister("Originate");
06739       ast_manager_unregister("Command");
06740       ast_manager_unregister("ExtensionState");
06741       ast_manager_unregister("AbsoluteTimeout");
06742       ast_manager_unregister("MailboxStatus");
06743       ast_manager_unregister("MailboxCount");
06744       ast_manager_unregister("ListCommands");
06745       ast_manager_unregister("SendText");
06746       ast_manager_unregister("UserEvent");
06747       ast_manager_unregister("WaitEvent");
06748       ast_manager_unregister("CoreSettings");
06749       ast_manager_unregister("CoreStatus");
06750       ast_manager_unregister("Reload");
06751       ast_manager_unregister("CoreShowChannels");
06752       ast_manager_unregister("ModuleLoad");
06753       ast_manager_unregister("ModuleCheck");
06754       ast_manager_unregister("AOCMessage");
06755       ast_manager_unregister("Filter");
06756       ast_cli_unregister_multiple(cli_manager, ARRAY_LEN(cli_manager));
06757    }
06758 
06759    ast_tcptls_server_stop(&ami_desc);
06760    ast_tcptls_server_stop(&amis_desc);
06761 
06762    if (ami_tls_cfg.certfile) {
06763       ast_free(ami_tls_cfg.certfile);
06764       ami_tls_cfg.certfile = NULL;
06765    }
06766    if (ami_tls_cfg.pvtfile) {
06767       ast_free(ami_tls_cfg.pvtfile);
06768       ami_tls_cfg.pvtfile = NULL;
06769    }
06770    if (ami_tls_cfg.cipher) {
06771       ast_free(ami_tls_cfg.cipher);
06772       ami_tls_cfg.cipher = NULL;
06773    }
06774 
06775    if (sessions) {
06776       ao2_ref(sessions, -1);
06777       sessions = NULL;
06778    }
06779 
06780    while ((user = AST_LIST_REMOVE_HEAD(&users, list))) {
06781       manager_free_user(user);
06782    }
06783 }

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 6467 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.

06468 {
06469    int retval;
06470    struct sockaddr_in ser_remote_address_tmp;
06471 
06472    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06473    retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06474    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06475    return retval;
06476 }

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

Definition at line 5885 of file manager.c.

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

Referenced by auth_http_callback(), and generic_http_callback().

05886 {
05887    char *buf;
05888    size_t l;
05889 
05890    if (!s->f)
05891       return;
05892 
05893    /* Ensure buffer is NULL-terminated */
05894    fprintf(s->f, "%c", 0);
05895    fflush(s->f);
05896 
05897    if ((l = ftell(s->f)) > 0) {
05898       if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) {
05899          ast_log(LOG_WARNING, "mmap failed.  Manager output was not processed\n");
05900       } else {
05901          if (format == FORMAT_XML || format == FORMAT_HTML) {
05902             xml_translate(out, buf, params, format);
05903          } else {
05904             ast_str_append(out, 0, "%s", buf);
05905          }
05906          munmap(buf, l);
05907       }
05908    } else if (format == FORMAT_XML || format == FORMAT_HTML) {
05909       xml_translate(out, "", params, format);
05910    }
05911 
05912    if (s->f) {
05913       if (fclose(s->f)) {
05914          ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
05915       }
05916       s->f = NULL;
05917       s->fd = -1;
05918    } else if (s->fd != -1) {
05919       if (close(s->fd)) {
05920          ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
05921       }
05922       s->fd = -1;
05923    } else {
05924       ast_log(LOG_ERROR, "process output attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n");
05925    }
05926 }

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

References purge_events(), and purge_sessions().

06582 {
06583    purge_sessions(1);
06584    purge_events();
06585 }

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 6478 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.

06479 {
06480    int retval;
06481    struct sockaddr_in ser_remote_address_tmp;
06482 
06483    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06484    retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06485    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06486    return retval;
06487 }

int reload_manager ( void   ) 

Called by Asterisk module functions and the CLI command.

Definition at line 7237 of file manager.c.

References __init_manager().

Referenced by handle_manager_reload().

07238 {
07239    return __init_manager(1);
07240 }

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

Definition at line 5729 of file manager.c.

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

Referenced by xml_translate().

05730 {
05731    /* Due to the simplicity of struct variable_count, it makes no difference
05732     * if you pass in objects or strings, the same operation applies. This is
05733     * due to the fact that the hash occurs on the first element, which means
05734     * the address of both the struct and the string are exactly the same. */
05735    struct variable_count *vc = obj;
05736    char *str = vstr;
05737    return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
05738 }

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

Definition at line 5722 of file manager.c.

References ast_str_hash(), and variable_count::varname.

Referenced by xml_translate().

05723 {
05724    const struct variable_count *vc = vvc;
05725 
05726    return ast_str_hash(vc->varname);
05727 }

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

Definition at line 5660 of file manager.c.

References ast_str_append().

Referenced by xml_translate().

05661 {
05662    /* store in a local buffer to avoid calling ast_str_append too often */
05663    char buf[256];
05664    char *dst = buf;
05665    int space = sizeof(buf);
05666    /* repeat until done and nothing to flush */
05667    for ( ; *src || dst != buf ; src++) {
05668       if (*src == '\0' || space < 10) {   /* flush */
05669          *dst++ = '\0';
05670          ast_str_append(out, 0, "%s", buf);
05671          dst = buf;
05672          space = sizeof(buf);
05673          if (*src == '\0') {
05674             break;
05675          }
05676       }
05677 
05678       if ( (mode & 2) && !isalnum(*src)) {
05679          *dst++ = '_';
05680          space--;
05681          continue;
05682       }
05683       switch (*src) {
05684       case '<':
05685          strcpy(dst, "&lt;");
05686          dst += 4;
05687          space -= 4;
05688          break;
05689       case '>':
05690          strcpy(dst, "&gt;");
05691          dst += 4;
05692          space -= 4;
05693          break;
05694       case '\"':
05695          strcpy(dst, "&quot;");
05696          dst += 6;
05697          space -= 6;
05698          break;
05699       case '\'':
05700          strcpy(dst, "&apos;");
05701          dst += 6;
05702          space -= 6;
05703          break;
05704       case '&':
05705          strcpy(dst, "&amp;");
05706          dst += 5;
05707          space -= 5;
05708          break;
05709 
05710       default:
05711          *dst++ = mode ? tolower(*src) : *src;
05712          space--;
05713       }
05714    }
05715 }

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 5768 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().

05769 {
05770    struct ast_variable *v;
05771    const char *dest = NULL;
05772    char *var, *val;
05773    const char *objtype = NULL;
05774    int in_data = 0;  /* parsing data */
05775    int inobj = 0;
05776    int xml = (format == FORMAT_XML);
05777    struct variable_count *vc = NULL;
05778    struct ao2_container *vco = NULL;
05779 
05780    if (xml) {
05781       /* dest and objtype need only for XML format */
05782       for (v = get_vars; v; v = v->next) {
05783          if (!strcasecmp(v->name, "ajaxdest")) {
05784             dest = v->value;
05785          } else if (!strcasecmp(v->name, "ajaxobjtype")) {
05786             objtype = v->value;
05787          }
05788       }
05789       if (ast_strlen_zero(dest)) {
05790          dest = "unknown";
05791       }
05792       if (ast_strlen_zero(objtype)) {
05793          objtype = "generic";
05794       }
05795    }
05796 
05797    /* we want to stop when we find an empty line */
05798    while (in && *in) {
05799       val = strsep(&in, "\r\n"); /* mark start and end of line */
05800       if (in && *in == '\n') {   /* remove trailing \n if any */
05801          in++;
05802       }
05803       ast_trim_blanks(val);
05804       ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
05805       if (ast_strlen_zero(val)) {
05806          /* empty line */
05807          if (in_data) {
05808             /* close data in Opaque mode */
05809             ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05810             in_data = 0;
05811          }
05812 
05813          if (inobj) {
05814             /* close block */
05815             ast_str_append(out, 0, xml ? " /></response>\n" :
05816                "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05817             inobj = 0;
05818             ao2_ref(vco, -1);
05819             vco = NULL;
05820          }
05821          continue;
05822       }
05823 
05824       if (!inobj) {
05825          /* start new block */
05826          if (xml) {
05827             ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
05828          }
05829          vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
05830          inobj = 1;
05831       }
05832 
05833       if (in_data) {
05834          /* Process data field in Opaque mode. This is a
05835           * followup, so we re-add line feeds. */
05836          ast_str_append(out, 0, xml ? "\n" : "<br>\n");
05837          xml_copy_escape(out, val, 0);   /* data field */
05838          continue;
05839       }
05840 
05841       /* We expect "Name: value" line here */
05842       var = strsep(&val, ":");
05843       if (val) {
05844          /* found the field name */
05845          val = ast_skip_blanks(val);
05846          ast_trim_blanks(var);
05847       } else {
05848          /* field name not found, switch to opaque mode */
05849          val = var;
05850          var = "Opaque-data";
05851          in_data = 1;
05852       }
05853 
05854 
05855       ast_str_append(out, 0, xml ? " " : "<tr><td>");
05856       if ((vc = ao2_find(vco, var, 0))) {
05857          vc->count++;
05858       } else {
05859          /* Create a new entry for this one */
05860          vc = ao2_alloc(sizeof(*vc), NULL);
05861          vc->varname = var;
05862          vc->count = 1;
05863          ao2_link(vco, vc);
05864       }
05865 
05866       xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
05867       if (vc->count > 1) {
05868          ast_str_append(out, 0, "-%d", vc->count);
05869       }
05870       ao2_ref(vc, -1);
05871       ast_str_append(out, 0, xml ? "='" : "</td><td>");
05872       xml_copy_escape(out, val, 0); /* data field */
05873       if (!in_data || !*in) {
05874          ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05875       }
05876    }
05877 
05878    if (inobj) {
05879       ast_str_append(out, 0, xml ? " /></response>\n" :
05880          "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05881       ao2_ref(vco, -1);
05882    }
05883 }


Variable Documentation

struct ast_http_uri amanageruri [static]

Definition at line 6557 of file manager.c.

struct ast_http_uri amanagerxmluri [static]

Definition at line 6566 of file manager.c.

Definition at line 6588 of file manager.c.

struct ast_tls_config ami_tls_cfg [static]

Definition at line 6587 of file manager.c.

Referenced by __init_manager(), handle_manager_show_settings(), and manager_shutdown().

Definition at line 6599 of file manager.c.

struct ast_http_uri arawmanuri [static]

Definition at line 6548 of file manager.c.

struct ast_cli_entry cli_manager[] [static]

Definition at line 6650 of file manager.c.

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

Definition at line 5517 of file manager.c.

struct ast_http_uri manageruri [static]

Definition at line 6497 of file manager.c.

struct ast_http_uri managerxmluri [static]

Definition at line 6505 of file manager.c.

struct ast_http_uri rawmanuri [static]

Definition at line 6489 of file manager.c.

int registered = 0 [static]

Definition at line 6575 of file manager.c.

int webregged = 0 [static]

Definition at line 6576 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 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1