Thu Apr 3 08:22:11 2014

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"
Include dependency graph for manager.c:

Go to the source code of this file.

Data Structures

struct  actions
 list of actions registered More...
struct  all_events
struct  ast_manager_user
 user descriptor, as read from the config file. More...
struct  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 5516 of file manager.c.

05516                    {
05517    FORMAT_RAW,
05518    FORMAT_HTML,
05519    FORMAT_XML,
05520 };


Function Documentation

static int __init_manager ( int  reload  )  [static]

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

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

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

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

07248 {
07249    AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
07250 
07251    return 0;
07252 }

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

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

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

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

07255 {
07256    return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
07257 }

int astman_is_authed ( uint32_t  ident  ) 

Determinie if a manager session ident is authenticated.

Definition at line 5592 of file manager.c.

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

Referenced by http_post_callback(), and static_callback().

05593 {
05594    int authed;
05595    struct mansession_session *session;
05596 
05597    if (!(session = find_session(ident, 0)))
05598       return 0;
05599 
05600    authed = (session->authenticated != 0);
05601 
05602    ao2_unlock(session);
05603    unref_mansession(session);
05604 
05605    return authed;
05606 }

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

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

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

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

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

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

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

06521 {
06522    int retval;
06523    struct sockaddr_in ser_remote_address_tmp;
06524 
06525    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06526    retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06527    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06528    return retval;
06529 }

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

06532 {
06533    int retval;
06534    struct sockaddr_in ser_remote_address_tmp;
06535 
06536    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06537    retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06538    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06539    return retval;
06540 }

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

06543 {
06544    int retval;
06545    struct sockaddr_in ser_remote_address_tmp;
06546 
06547    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06548    retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06549    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06550    return retval;
06551 }

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

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

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

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

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

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

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

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

int init_manager ( void   ) 

Called by Asterisk initialization.

Definition at line 7237 of file manager.c.

References __init_manager().

Referenced by main().

07238 {
07239    return __init_manager(0);
07240 }

static void load_channelvars ( struct ast_variable var  )  [static]

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

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

static void manager_free_user ( struct ast_manager_user user  )  [static]

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

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

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

06462 {
06463    int retval;
06464    struct sockaddr_in ser_remote_address_tmp;
06465 
06466    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06467    retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06468    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06469    return retval;
06470 }

static void manager_shutdown ( void   )  [static]

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

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

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

06473 {
06474    int retval;
06475    struct sockaddr_in ser_remote_address_tmp;
06476 
06477    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06478    retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06479    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06480    return retval;
06481 }

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

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

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

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

References purge_events(), and purge_sessions().

06587 {
06588    purge_sessions(1);
06589    purge_events();
06590 }

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

06484 {
06485    int retval;
06486    struct sockaddr_in ser_remote_address_tmp;
06487 
06488    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06489    retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06490    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06491    return retval;
06492 }

int reload_manager ( void   ) 

Called by Asterisk module functions and the CLI command.

Definition at line 7242 of file manager.c.

References __init_manager().

Referenced by handle_manager_reload().

07243 {
07244    return __init_manager(1);
07245 }

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

Definition at line 5734 of file manager.c.

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

Referenced by xml_translate().

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

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

Definition at line 5727 of file manager.c.

References ast_str_hash(), and variable_count::varname.

Referenced by xml_translate().

05728 {
05729    const struct variable_count *vc = vvc;
05730 
05731    return ast_str_hash(vc->varname);
05732 }

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

Definition at line 5665 of file manager.c.

References ast_str_append().

Referenced by xml_translate().

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

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

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


Variable Documentation

struct ast_http_uri amanageruri [static]

Definition at line 6562 of file manager.c.

struct ast_http_uri amanagerxmluri [static]

Definition at line 6571 of file manager.c.

Definition at line 6593 of file manager.c.

struct ast_tls_config ami_tls_cfg [static]

Definition at line 6592 of file manager.c.

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

Definition at line 6604 of file manager.c.

struct ast_http_uri arawmanuri [static]

Definition at line 6553 of file manager.c.

struct ast_cli_entry cli_manager[] [static]

Definition at line 6655 of file manager.c.

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

Definition at line 5522 of file manager.c.

struct ast_http_uri manageruri [static]

Definition at line 6502 of file manager.c.

struct ast_http_uri managerxmluri [static]

Definition at line 6510 of file manager.c.

struct ast_http_uri rawmanuri [static]

Definition at line 6494 of file manager.c.

int registered = 0 [static]

Definition at line 6580 of file manager.c.

int webregged = 0 [static]

Definition at line 6581 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 3 Apr 2014 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1