Sat Mar 10 01:55:30 2012

Asterisk developer's documentation


manager.c File Reference

The Asterisk Management Interface - AMI. More...

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

Go to the source code of this file.

Data Structures

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

Defines

#define ASTMAN_APPEND_BUF_INITSIZE   256
 initial allocated size for the astman_append_buf
#define DEFAULT_REALM   "asterisk"
#define 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  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 manager command with the manager interface.
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.
ast_datastoreastman_datastore_find (struct mansession *s, const struct ast_datastore_info *info, const char *uid)
 Find a datastore on a session.
int astman_datastore_remove (struct mansession *s, struct ast_datastore *datastore)
 Remove a datastore from a session.
const char * astman_get_header (const struct message *m, char *var)
 Get header from mananger transaction.
ast_variableastman_get_variables (const struct message *m)
 Get a linked list of the Variable: headers.
int astman_is_authed (uint32_t ident)
 Determinie if a manager session ident is authenticated.
void astman_send_ack (struct mansession *s, const struct message *m, char *msg)
 Send ack in manager transaction.
void astman_send_error (struct mansession *s, const struct message *m, char *error)
 Send error in manager transaction.
void astman_send_listack (struct mansession *s, const struct message *m, char *msg, char *listflag)
 Send ack in manager list transaction.
void astman_send_response (struct mansession *s, const struct message *m, char *resp, char *msg)
 Send response in manager transaction.
static void astman_send_response_full (struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
static void astman_start_ack (struct mansession *s, const struct message *m)
int astman_verify_session_readpermissions (uint32_t ident, int perm)
 Verify a session's read permissions against a permission mask.
int astman_verify_session_writepermissions (uint32_t ident, int perm)
 Verify a session's write permissions against a permission mask.
static int auth_http_callback (struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, struct sockaddr_in *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_manager_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_mxml_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_rawman_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int authenticate (struct mansession *s, const struct message *m)
static const char * authority_to_str (int authority, struct ast_str **res)
 Convert authority code to a list of options.
static 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 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 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 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 int manager_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int manager_modulecheck (struct mansession *s, const struct message *m)
static int manager_moduleload (struct mansession *s, const struct message *m)
static int manager_state_cb (char *context, char *exten, int state, void *data)
static int mansession_cmp_fn (void *obj, void *arg, int flags)
static struct sockaddr_in * mansession_encode_sin_local (const struct mansession *s, struct sockaddr_in *sin_local)
static enum ast_security_event_transport_type mansession_get_transport (const struct mansession *s)
static void mansession_lock (struct mansession *s)
 Lock the 'mansession' structure.
static void mansession_unlock (struct mansession *s)
 Unlock the 'mansession' structure.
static int 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 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"

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


Enumeration Type Documentation

enum output_format

END Doxygen group

Enumerator:
FORMAT_RAW 
FORMAT_HTML 
FORMAT_XML 

Definition at line 5286 of file manager.c.

05286                    {
05287    FORMAT_RAW,
05288    FORMAT_HTML,
05289    FORMAT_XML,
05290 };


Function Documentation

static int __init_manager ( int  reload  )  [static]

Definition at line 6464 of file manager.c.

References 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_desc, ami_tls_cfg, amis_desc, append_event(), ARRAY_LEN, AST_CERTFILE, ast_cli_register_multiple(), ast_config_AST_SYSTEM_NAME, ast_config_load2(), ast_copy_string(), ast_extension_state_add(), ast_free, ast_log(), ast_manager_register_xml, ast_strdup, ast_tls_read_conf(), ast_true(), ast_variable_browse(), authlimit, authtimeout, block_sockets, broken_events_action, ast_tls_config::certfile, ast_tls_config::cipher, cli_manager, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_AUTHLIMIT, DEFAULT_AUTHTIMEOUT, DEFAULT_BLOCKSOCKETS, DEFAULT_BROKENEVENTSACTION, DEFAULT_DISPLAYCONNECTS, DEFAULT_ENABLED, DEFAULT_HTTPTIMEOUT, DEFAULT_MANAGER_PORT, DEFAULT_MANAGERDEBUG, DEFAULT_REALM, DEFAULT_TIMESTAMPEVENTS, DEFAULT_WEBENABLED, displayconnects, ast_tls_config::enabled, EVENT_FLAG_AOC, EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, EVENT_FLAG_CONFIG, EVENT_FLAG_ORIGINATE, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, free_channelvars(), global_realm, httptimeout, ast_tcptls_session_args::local_address, LOG_NOTICE, manager_debug, manager_enabled, manager_modulecheck(), manager_moduleload(), manager_state_cb(), ast_tls_config::pvtfile, S_OR, timestampevents, var, and webmanager_enabled.

Referenced by init_manager(), and reload_manager().

06465 {
06466    struct ast_config *ucfg = NULL, *cfg = NULL;
06467    const char *val;
06468    char *cat = NULL;
06469    int newhttptimeout = DEFAULT_HTTPTIMEOUT;
06470    struct ast_manager_user *user = NULL;
06471    struct ast_variable *var;
06472    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06473    char a1[256];
06474    char a1_hash[256];
06475    struct sockaddr_in ami_desc_local_address_tmp = { 0, };
06476    struct sockaddr_in amis_desc_local_address_tmp = { 0, };
06477 
06478    if (!registered) {
06479       /* Register default actions */
06480       ast_manager_register_xml("Ping", 0, action_ping);
06481       ast_manager_register_xml("Events", 0, action_events);
06482       ast_manager_register_xml("Logoff", 0, action_logoff);
06483       ast_manager_register_xml("Login", 0, action_login);
06484       ast_manager_register_xml("Challenge", 0, action_challenge);
06485       ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
06486       ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
06487       ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar);
06488       ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
06489       ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
06490       ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
06491       ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
06492       ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
06493       ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
06494       ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect);
06495       ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer);
06496       ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate);
06497       ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command);
06498       ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
06499       ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
06500       ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
06501       ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
06502       ast_manager_register_xml("ListCommands", 0, action_listcommands);
06503       ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext);
06504       ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent);
06505       ast_manager_register_xml("WaitEvent", 0, action_waitevent);
06506       ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
06507       ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
06508       ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
06509       ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
06510       ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
06511       ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
06512       ast_manager_register_xml("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
06513 
06514       ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
06515       ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
06516       registered = 1;
06517       /* Append placeholder event so master_eventq never runs dry */
06518       append_event("Event: Placeholder\r\n\r\n", 0);
06519    }
06520    if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
06521       return 0;
06522    }
06523 
06524    manager_enabled = DEFAULT_ENABLED;
06525    webmanager_enabled = DEFAULT_WEBENABLED;
06526    manager_debug = DEFAULT_MANAGERDEBUG;
06527    displayconnects = DEFAULT_DISPLAYCONNECTS;
06528    broken_events_action = DEFAULT_BROKENEVENTSACTION;
06529    block_sockets = DEFAULT_BLOCKSOCKETS;
06530    timestampevents = DEFAULT_TIMESTAMPEVENTS;
06531    httptimeout = DEFAULT_HTTPTIMEOUT;
06532    authtimeout = DEFAULT_AUTHTIMEOUT;
06533    authlimit = DEFAULT_AUTHLIMIT;
06534 
06535    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
06536       ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled.\n");
06537       return 0;
06538    }
06539 
06540    /* default values */
06541    ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm));
06542    memset(&ami_desc.local_address, 0, sizeof(struct sockaddr_in));
06543    memset(&amis_desc.local_address, 0, sizeof(amis_desc.local_address));
06544    amis_desc_local_address_tmp.sin_port = htons(5039);
06545    ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT);
06546 
06547    ami_tls_cfg.enabled = 0;
06548    if (ami_tls_cfg.certfile) {
06549       ast_free(ami_tls_cfg.certfile);
06550    }
06551    ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
06552    if (ami_tls_cfg.pvtfile) {
06553       ast_free(ami_tls_cfg.pvtfile);
06554    }
06555    ami_tls_cfg.pvtfile = ast_strdup("");
06556    if (ami_tls_cfg.cipher) {
06557       ast_free(ami_tls_cfg.cipher);
06558    }
06559    ami_tls_cfg.cipher = ast_strdup("");
06560 
06561    free_channelvars();
06562 
06563    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
06564       val = var->value;
06565 
06566       if (!ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
06567          continue;
06568       }
06569 
06570       if (!strcasecmp(var->name, "enabled")) {
06571          manager_enabled = ast_true(val);
06572       } else if (!strcasecmp(var->name, "block-sockets")) {
06573          block_sockets = ast_true(val);
06574       } else if (!strcasecmp(var->name, "webenabled")) {
06575          webmanager_enabled = ast_true(val);
06576       } else if (!strcasecmp(var->name, "port")) {
06577          ami_desc_local_address_tmp.sin_port = htons(atoi(val));
06578       } else if (!strcasecmp(var->name, "bindaddr")) {
06579          if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) {
06580             ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
06581             memset(&ami_desc_local_address_tmp.sin_addr, 0,
06582                    sizeof(ami_desc_local_address_tmp.sin_addr));
06583          }
06584       } else if (!strcasecmp(var->name, "brokeneventsaction")) {
06585          broken_events_action = ast_true(val);
06586       } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
06587          allowmultiplelogin = ast_true(val);
06588       } else if (!strcasecmp(var->name, "displayconnects")) {
06589          displayconnects = ast_true(val);
06590       } else if (!strcasecmp(var->name, "timestampevents")) {
06591          timestampevents = ast_true(val);
06592       } else if (!strcasecmp(var->name, "debug")) {
06593          manager_debug = ast_true(val);
06594       } else if (!strcasecmp(var->name, "httptimeout")) {
06595          newhttptimeout = atoi(val);
06596       } else if (!strcasecmp(var->name, "authtimeout")) {
06597          int timeout = atoi(var->value);
06598 
06599          if (timeout < 1) {
06600             ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
06601          } else {
06602             authtimeout = timeout;
06603          }
06604       } else if (!strcasecmp(var->name, "authlimit")) {
06605          int limit = atoi(var->value);
06606 
06607          if (limit < 1) {
06608             ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
06609          } else {
06610             authlimit = limit;
06611          }
06612       } else if (!strcasecmp(var->name, "channelvars")) {
06613          load_channelvars(var);
06614       } else {
06615          ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
06616             var->name, val);
06617       }
06618    }
06619 
06620    ami_desc_local_address_tmp.sin_family = AF_INET;
06621    amis_desc_local_address_tmp.sin_family = AF_INET;
06622 
06623    /* if the amis address has not been set, default is the same as non secure ami */
06624    if (!amis_desc_local_address_tmp.sin_addr.s_addr) {
06625       amis_desc_local_address_tmp.sin_addr =
06626           ami_desc_local_address_tmp.sin_addr;
06627    }
06628 
06629    if (manager_enabled) {
06630       ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp);
06631       ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp);
06632    }
06633 
06634    AST_RWLIST_WRLOCK(&users);
06635 
06636    /* First, get users from users.conf */
06637    ucfg = ast_config_load2("users.conf", "manager", config_flags);
06638    if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
06639       const char *hasmanager;
06640       int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
06641 
06642       while ((cat = ast_category_browse(ucfg, cat))) {
06643          if (!strcasecmp(cat, "general")) {
06644             continue;
06645          }
06646 
06647          hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
06648          if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
06649             const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
06650             const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
06651             const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
06652             const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
06653             const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
06654 
06655             /* Look for an existing entry,
06656              * if none found - create one and add it to the list
06657              */
06658             if (!(user = get_manager_by_name_locked(cat))) {
06659                if (!(user = ast_calloc(1, sizeof(*user)))) {
06660                   break;
06661                }
06662 
06663                /* Copy name over */
06664                ast_copy_string(user->username, cat, sizeof(user->username));
06665                /* Insert into list */
06666                AST_LIST_INSERT_TAIL(&users, user, list);
06667                user->ha = NULL;
06668                user->keep = 1;
06669                user->readperm = -1;
06670                user->writeperm = -1;
06671                /* Default displayconnect from [general] */
06672                user->displayconnects = displayconnects;
06673                user->writetimeout = 100;
06674             }
06675 
06676             if (!user_secret) {
06677                user_secret = ast_variable_retrieve(ucfg, "general", "secret");
06678             }
06679             if (!user_read) {
06680                user_read = ast_variable_retrieve(ucfg, "general", "read");
06681             }
06682             if (!user_write) {
06683                user_write = ast_variable_retrieve(ucfg, "general", "write");
06684             }
06685             if (!user_displayconnects) {
06686                user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
06687             }
06688             if (!user_writetimeout) {
06689                user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
06690             }
06691 
06692             if (!ast_strlen_zero(user_secret)) {
06693                if (user->secret) {
06694                   ast_free(user->secret);
06695                }
06696                user->secret = ast_strdup(user_secret);
06697             }
06698 
06699             if (user_read) {
06700                user->readperm = get_perm(user_read);
06701             }
06702             if (user_write) {
06703                user->writeperm = get_perm(user_write);
06704             }
06705             if (user_displayconnects) {
06706                user->displayconnects = ast_true(user_displayconnects);
06707             }
06708             if (user_writetimeout) {
06709                int value = atoi(user_writetimeout);
06710                if (value < 100) {
06711                   ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at users.conf line %d\n", var->value, var->lineno);
06712                } else {
06713                   user->writetimeout = value;
06714                }
06715             }
06716          }
06717       }
06718       ast_config_destroy(ucfg);
06719    }
06720 
06721    /* cat is NULL here in any case */
06722 
06723    while ((cat = ast_category_browse(cfg, cat))) {
06724       struct ast_ha *oldha;
06725 
06726       if (!strcasecmp(cat, "general")) {
06727          continue;
06728       }
06729 
06730       /* Look for an existing entry, if none found - create one and add it to the list */
06731       if (!(user = get_manager_by_name_locked(cat))) {
06732          if (!(user = ast_calloc(1, sizeof(*user)))) {
06733             break;
06734          }
06735          /* Copy name over */
06736          ast_copy_string(user->username, cat, sizeof(user->username));
06737 
06738          user->ha = NULL;
06739          user->readperm = 0;
06740          user->writeperm = 0;
06741          /* Default displayconnect from [general] */
06742          user->displayconnects = displayconnects;
06743          user->writetimeout = 100;
06744          user->whitefilters = ao2_container_alloc(1, NULL, NULL);
06745          user->blackfilters = ao2_container_alloc(1, NULL, NULL);
06746 
06747          /* Insert into list */
06748          AST_RWLIST_INSERT_TAIL(&users, user, list);
06749       } else {
06750          ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
06751          ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
06752       }
06753 
06754       /* Make sure we keep this user and don't destroy it during cleanup */
06755       user->keep = 1;
06756       oldha = user->ha;
06757       user->ha = NULL;
06758 
06759       var = ast_variable_browse(cfg, cat);
06760       for (; var; var = var->next) {
06761          if (!strcasecmp(var->name, "secret")) {
06762             if (user->secret) {
06763                ast_free(user->secret);
06764             }
06765             user->secret = ast_strdup(var->value);
06766          } else if (!strcasecmp(var->name, "deny") ||
06767                    !strcasecmp(var->name, "permit")) {
06768             user->ha = ast_append_ha(var->name, var->value, user->ha, NULL);
06769          }  else if (!strcasecmp(var->name, "read") ) {
06770             user->readperm = get_perm(var->value);
06771          }  else if (!strcasecmp(var->name, "write") ) {
06772             user->writeperm = get_perm(var->value);
06773          }  else if (!strcasecmp(var->name, "displayconnects") ) {
06774             user->displayconnects = ast_true(var->value);
06775          } else if (!strcasecmp(var->name, "writetimeout")) {
06776             int value = atoi(var->value);
06777             if (value < 100) {
06778                ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
06779             } else {
06780                user->writetimeout = value;
06781             }
06782          } else if (!strcasecmp(var->name, "eventfilter")) {
06783             const char *value = var->value;
06784             regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
06785             if (new_filter) {
06786                int is_blackfilter;
06787                if (value[0] == '!') {
06788                   is_blackfilter = 1;
06789                   value++;
06790                } else {
06791                   is_blackfilter = 0;
06792                }
06793                if (regcomp(new_filter, value, 0)) {
06794                   ao2_t_ref(new_filter, -1, "failed to make regx");
06795                } else {
06796                   if (is_blackfilter) {
06797                      ao2_t_link(user->blackfilters, new_filter, "link new filter into black user container");
06798                   } else {
06799                      ao2_t_link(user->whitefilters, new_filter, "link new filter into white user container");
06800                   }
06801                }
06802             }
06803          } else {
06804             ast_debug(1, "%s is an unknown option.\n", var->name);
06805          }
06806       }
06807       ast_free_ha(oldha);
06808    }
06809    ast_config_destroy(cfg);
06810 
06811    /* Perform cleanup - essentially prune out old users that no longer exist */
06812    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
06813       if (user->keep) { /* valid record. clear flag for the next round */
06814          user->keep = 0;
06815 
06816          /* Calculate A1 for Digest auth */
06817          snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
06818          ast_md5_hash(a1_hash,a1);
06819          if (user->a1_hash) {
06820             ast_free(user->a1_hash);
06821          }
06822          user->a1_hash = ast_strdup(a1_hash);
06823          continue;
06824       }
06825       /* We do not need to keep this user so take them out of the list */
06826       AST_RWLIST_REMOVE_CURRENT(list);
06827       ast_debug(4, "Pruning user '%s'\n", user->username);
06828       /* Free their memory now */
06829       if (user->a1_hash) {
06830          ast_free(user->a1_hash);
06831       }
06832       if (user->secret) {
06833          ast_free(user->secret);
06834       }
06835       ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
06836       ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
06837       ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
06838       ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
06839       ast_free_ha(user->ha);
06840       ast_free(user);
06841    }
06842    AST_RWLIST_TRAVERSE_SAFE_END;
06843 
06844    AST_RWLIST_UNLOCK(&users);
06845 
06846    if (!reload) {
06847       /* If you have a NULL hash fn, you only need a single bucket */
06848       sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn);
06849    }
06850 
06851    if (webmanager_enabled && manager_enabled) {
06852       if (!webregged) {
06853 
06854          ast_http_uri_link(&rawmanuri);
06855          ast_http_uri_link(&manageruri);
06856          ast_http_uri_link(&managerxmluri);
06857 
06858          ast_http_uri_link(&arawmanuri);
06859          ast_http_uri_link(&amanageruri);
06860          ast_http_uri_link(&amanagerxmluri);
06861          webregged = 1;
06862       }
06863    } else {
06864       if (webregged) {
06865          ast_http_uri_unlink(&rawmanuri);
06866          ast_http_uri_unlink(&manageruri);
06867          ast_http_uri_unlink(&managerxmluri);
06868 
06869          ast_http_uri_unlink(&arawmanuri);
06870          ast_http_uri_unlink(&amanageruri);
06871          ast_http_uri_unlink(&amanagerxmluri);
06872          webregged = 0;
06873       }
06874    }
06875 
06876    if (newhttptimeout > 0) {
06877       httptimeout = newhttptimeout;
06878    }
06879 
06880    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled");
06881 
06882    ast_tcptls_server_start(&ami_desc);
06883    if (ast_ssl_setup(amis_desc.tls_cfg)) {
06884       ast_tcptls_server_start(&amis_desc);
06885    }
06886    return 0;
06887 }

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

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

06911 {
06912    AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
06913 
06914    return 0;
06915 }

struct ast_datastore* astman_datastore_find ( struct mansession s,
const struct ast_datastore_info info,
const char *  uid 
)

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

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

06923 {
06924    struct ast_datastore *datastore = NULL;
06925 
06926    if (info == NULL)
06927       return NULL;
06928 
06929    AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
06930       if (datastore->info != info) {
06931          continue;
06932       }
06933 
06934       if (uid == NULL) {
06935          /* matched by type only */
06936          break;
06937       }
06938 
06939       if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
06940          /* Matched by type AND uid */
06941          break;
06942       }
06943    }
06944    AST_LIST_TRAVERSE_SAFE_END;
06945 
06946    return datastore;
06947 }

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

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

06918 {
06919    return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
06920 }

int astman_is_authed ( uint32_t  ident  ) 

Determinie if a manager session ident is authenticated.

Definition at line 5362 of file manager.c.

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

Referenced by http_post_callback(), and static_callback().

05363 {
05364    int authed;
05365    struct mansession_session *session;
05366 
05367    if (!(session = find_session(ident, 0)))
05368       return 0;
05369 
05370    authed = (session->authenticated != 0);
05371 
05372    ao2_unlock(session);
05373    unref_mansession(session);
05374 
05375    return authed;
05376 }

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().

05379 {
05380    int result = 0;
05381    struct mansession_session *session;
05382    struct ao2_iterator i;
05383 
05384    if (ident == 0) {
05385       return 0;
05386    }
05387 
05388    i = ao2_iterator_init(sessions, 0);
05389    while ((session = ao2_iterator_next(&i))) {
05390       ao2_lock(session);
05391       if ((session->managerid == ident) && (session->readperm & perm)) {
05392          result = 1;
05393          ao2_unlock(session);
05394          unref_mansession(session);
05395          break;
05396       }
05397       ao2_unlock(session);
05398       unref_mansession(session);
05399    }
05400    ao2_iterator_destroy(&i);
05401    return result;
05402 }

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().

05405 {
05406    int result = 0;
05407    struct mansession_session *session;
05408    struct ao2_iterator i;
05409 
05410    if (ident == 0) {
05411       return 0;
05412    }
05413 
05414    i = ao2_iterator_init(sessions, 0);
05415    while ((session = ao2_iterator_next(&i))) {
05416       ao2_lock(session);
05417       if ((session->managerid == ident) && (session->writeperm & perm)) {
05418          result = 1;
05419          ao2_unlock(session);
05420          unref_mansession(session);
05421          break;
05422       }
05423       ao2_unlock(session);
05424       unref_mansession(session);
05425    }
05426    ao2_iterator_destroy(&i);
05427    return result;
05428 }

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

References ast_http_error(), AST_HTTP_GET, AST_HTTP_HEAD, AST_HTTP_POST, get_params(), ast_variable::name, ast_variable::next, and mansession::session.

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

05914 {
05915    struct mansession_session *session = NULL;
05916    struct mansession s = { .session = NULL, .tcptls_session = ser };
05917    struct ast_variable *v, *params = get_params;
05918    char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
05919    struct ast_str *http_header = NULL, *out = NULL;
05920    size_t result_size = 512;
05921    struct message m = { 0 };
05922    unsigned int idx;
05923    size_t hdrlen;
05924 
05925    time_t time_now = time(NULL);
05926    unsigned long nonce = 0, nc;
05927    struct ast_http_digest d = { NULL, };
05928    struct ast_manager_user *user = NULL;
05929    int stale = 0;
05930    char resp_hash[256]="";
05931    /* Cache for user data */
05932    char u_username[80];
05933    int u_readperm;
05934    int u_writeperm;
05935    int u_writetimeout;
05936    int u_displayconnects;
05937    struct ast_sockaddr addr;
05938 
05939    if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
05940       ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
05941       return -1;
05942    }
05943 
05944    /* Find "Authorization: " header */
05945    for (v = headers; v; v = v->next) {
05946       if (!strcasecmp(v->name, "Authorization")) {
05947          break;
05948       }
05949    }
05950 
05951    if (!v || ast_strlen_zero(v->value)) {
05952       goto out_401; /* Authorization Header not present - send auth request */
05953    }
05954 
05955    /* Digest found - parse */
05956    if (ast_string_field_init(&d, 128)) {
05957       ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
05958       return -1;
05959    }
05960 
05961    if (ast_parse_digest(v->value, &d, 0, 1)) {
05962       /* Error in Digest - send new one */
05963       nonce = 0;
05964       goto out_401;
05965    }
05966    if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
05967       ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
05968       nonce = 0;
05969       goto out_401;
05970    }
05971 
05972    AST_RWLIST_WRLOCK(&users);
05973    user = get_manager_by_name_locked(d.username);
05974    if(!user) {
05975       AST_RWLIST_UNLOCK(&users);
05976       ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
05977       nonce = 0;
05978       goto out_401;
05979    }
05980 
05981    ast_sockaddr_from_sin(&addr, remote_address);
05982    /* --- We have User for this auth, now check ACL */
05983    if (user->ha && !ast_apply_ha(user->ha, &addr)) {
05984       AST_RWLIST_UNLOCK(&users);
05985       ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
05986       ast_http_error(ser, 403, "Permission denied", "Permission denied\n");
05987       return -1;
05988    }
05989 
05990    /* --- We have auth, so check it */
05991 
05992    /* compute the expected response to compare with what we received */
05993    {
05994       char a2[256];
05995       char a2_hash[256];
05996       char resp[256];
05997 
05998       /* XXX Now request method are hardcoded in A2 */
05999       snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
06000       ast_md5_hash(a2_hash, a2);
06001 
06002       if (d.qop) {
06003          /* RFC 2617 */
06004          snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
06005       }  else {
06006          /* RFC 2069 */
06007          snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
06008       }
06009       ast_md5_hash(resp_hash, resp);
06010    }
06011 
06012    if (!d.nonce  || strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
06013       /* Something was wrong, so give the client to try with a new challenge */
06014       AST_RWLIST_UNLOCK(&users);
06015       nonce = 0;
06016       goto out_401;
06017    }
06018 
06019    /*
06020     * User are pass Digest authentication.
06021     * Now, cache the user data and unlock user list.
06022     */
06023    ast_copy_string(u_username, user->username, sizeof(u_username));
06024    u_readperm = user->readperm;
06025    u_writeperm = user->writeperm;
06026    u_displayconnects = user->displayconnects;
06027    u_writetimeout = user->writetimeout;
06028    AST_RWLIST_UNLOCK(&users);
06029 
06030    if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
06031       /*
06032        * Create new session.
06033        * While it is not in the list we don't need any locking
06034        */
06035       if (!(session = build_mansession(*remote_address))) {
06036          ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
06037          return -1;
06038       }
06039       ao2_lock(session);
06040 
06041       ast_copy_string(session->username, u_username, sizeof(session->username));
06042       session->managerid = nonce;
06043       session->last_ev = grab_last();
06044       AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
06045 
06046       session->readperm = u_readperm;
06047       session->writeperm = u_writeperm;
06048       session->writetimeout = u_writetimeout;
06049 
06050       if (u_displayconnects) {
06051          ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
06052       }
06053       session->noncetime = session->sessionstart = time_now;
06054       session->authenticated = 1;
06055    } else if (stale) {
06056       /*
06057        * Session found, but nonce is stale.
06058        *
06059        * This could be because an old request (w/old nonce) arrived.
06060        *
06061        * This may be as the result of http proxy usage (separate delay or
06062        * multipath) or in a situation where a page was refreshed too quickly
06063        * (seen in Firefox).
06064        *
06065        * In this situation, we repeat the 401 auth with the current nonce
06066        * value.
06067        */
06068       nonce = session->managerid;
06069       ao2_unlock(session);
06070       stale = 1;
06071       goto out_401;
06072    } else {
06073       sscanf(d.nc, "%30lx", &nc);
06074       if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
06075          /*
06076           * Nonce time expired (> 2 minutes) or something wrong with nonce
06077           * counter.
06078           *
06079           * Create new nonce key and resend Digest auth request. Old nonce
06080           * is saved for stale checking...
06081           */
06082          session->nc = 0; /* Reset nonce counter */
06083          session->oldnonce = session->managerid;
06084          nonce = session->managerid = ast_random();
06085          session->noncetime = time_now;
06086          ao2_unlock(session);
06087          stale = 1;
06088          goto out_401;
06089       } else {
06090          session->nc = nc; /* All OK, save nonce counter */
06091       }
06092    }
06093 
06094 
06095    /* Reset session timeout. */
06096    session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
06097    ao2_unlock(session);
06098 
06099    ast_mutex_init(&s.lock);
06100    s.session = session;
06101    s.fd = mkstemp(template);  /* create a temporary file for command output */
06102    unlink(template);
06103    if (s.fd <= -1) {
06104       ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
06105       goto auth_callback_out;
06106    }
06107    s.f = fdopen(s.fd, "w+");
06108    if (!s.f) {
06109       ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
06110       ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
06111       close(s.fd);
06112       goto auth_callback_out;
06113    }
06114 
06115    if (method == AST_HTTP_POST) {
06116       params = ast_http_get_post_vars(ser, headers);
06117    }
06118 
06119    for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
06120       hdrlen = strlen(v->name) + strlen(v->value) + 3;
06121       m.headers[m.hdrcount] = ast_malloc(hdrlen);
06122       if (!m.headers[m.hdrcount]) {
06123          /* Allocation failure */
06124          continue;
06125       }
06126       snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
06127       ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
06128       ++m.hdrcount;
06129    }
06130 
06131    if (process_message(&s, &m)) {
06132       if (u_displayconnects) {
06133          ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
06134       }
06135 
06136       session->needdestroy = 1;
06137    }
06138 
06139    /* Free request headers. */
06140    for (idx = 0; idx < m.hdrcount; ++idx) {
06141       ast_free((void *) m.headers[idx]);
06142       m.headers[idx] = NULL;
06143    }
06144 
06145    if (s.f) {
06146       result_size = ftell(s.f); /* Calculate approx. size of result */
06147    }
06148 
06149    http_header = ast_str_create(80);
06150    out = ast_str_create(result_size * 2 + 512);
06151 
06152    if (http_header == NULL || out == NULL) {
06153       ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
06154       goto auth_callback_out;
06155    }
06156 
06157    ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]);
06158 
06159    if (format == FORMAT_XML) {
06160       ast_str_append(&out, 0, "<ajax-response>\n");
06161    } else if (format == FORMAT_HTML) {
06162       ast_str_append(&out, 0,
06163       "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
06164       "<html><head>\r\n"
06165       "<title>Asterisk&trade; Manager Interface</title>\r\n"
06166       "</head><body style=\"background-color: #ffffff;\">\r\n"
06167       "<form method=\"POST\">\r\n"
06168       "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
06169       "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
06170       "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
06171       "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
06172    }
06173 
06174    process_output(&s, &out, params, format);
06175 
06176    if (format == FORMAT_XML) {
06177       ast_str_append(&out, 0, "</ajax-response>\n");
06178    } else if (format == FORMAT_HTML) {
06179       ast_str_append(&out, 0, "</table></form></body></html>\r\n");
06180    }
06181 
06182    ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
06183    http_header = out = NULL;
06184 
06185 auth_callback_out:
06186    ast_mutex_destroy(&s.lock);
06187 
06188    /* Clear resources and unlock manager session */
06189    if (method == AST_HTTP_POST && params) {
06190       ast_variables_destroy(params);
06191    }
06192 
06193    ast_free(http_header);
06194    ast_free(out);
06195 
06196    ao2_lock(session);
06197    if (session->f) {
06198       fclose(session->f);
06199    }
06200    session->f = NULL;
06201    session->fd = -1;
06202    ao2_unlock(session);
06203 
06204    if (session->needdestroy) {
06205       ast_debug(1, "Need destroy, doing it now!\n");
06206       session_destroy(session);
06207    }
06208    ast_string_field_free_memory(&d);
06209    return 0;
06210 
06211 out_401:
06212    if (!nonce) {
06213       nonce = ast_random();
06214    }
06215 
06216    ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
06217    ast_string_field_free_memory(&d);
06218    return 0;
06219 }

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

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

06281 {
06282    int retval;
06283    struct sockaddr_in ser_remote_address_tmp;
06284 
06285    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06286    retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06287    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06288    return retval;
06289 }

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

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

06292 {
06293    int retval;
06294    struct sockaddr_in ser_remote_address_tmp;
06295 
06296    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06297    retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06298    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06299    return retval;
06300 }

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

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

06303 {
06304    int retval;
06305    struct sockaddr_in ser_remote_address_tmp;
06306 
06307    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06308    retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06309    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06310    return retval;
06311 }

static struct mansession_session* find_session ( uint32_t  ident,
int  incinuse 
) [static]

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, ast_atomic_fetchadd_int(), and unref_mansession().

Referenced by astman_is_authed().

05304 {
05305    struct mansession_session *session;
05306    struct ao2_iterator i;
05307 
05308    if (ident == 0) {
05309       return NULL;
05310    }
05311 
05312    i = ao2_iterator_init(sessions, 0);
05313    while ((session = ao2_iterator_next(&i))) {
05314       ao2_lock(session);
05315       if (session->managerid == ident && !session->needdestroy) {
05316          ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
05317          break;
05318       }
05319       ao2_unlock(session);
05320       unref_mansession(session);
05321    }
05322    ao2_iterator_destroy(&i);
05323 
05324    return session;
05325 }

static struct mansession_session* find_session_by_nonce ( const char *  username,
unsigned long  nonce,
int *  stale 
) [static]

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, and unref_mansession().

05337 {
05338    struct mansession_session *session;
05339    struct ao2_iterator i;
05340 
05341    if (nonce == 0 || username == NULL || stale == NULL) {
05342       return NULL;
05343    }
05344 
05345    i = ao2_iterator_init(sessions, 0);
05346    while ((session = ao2_iterator_next(&i))) {
05347       ao2_lock(session);
05348       if (!strcasecmp(session->username, username) && session->managerid == nonce) {
05349          *stale = 0;
05350          break;
05351       } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
05352          *stale = 1;
05353          break;
05354       }
05355       ao2_unlock(session);
05356       unref_mansession(session);
05357    }
05358    ao2_iterator_destroy(&i);
05359    return session;
05360 }

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]

Definition at line 5693 of file manager.c.

References ast_http_error(), AST_HTTP_GET, ast_http_get_cookies(), AST_HTTP_HEAD, AST_HTTP_POST, get_params(), ast_variable::name, ast_variable::next, mansession::session, and ast_variable::value.

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

05699 {
05700    struct mansession s = { .session = NULL, .tcptls_session = ser };
05701    struct mansession_session *session = NULL;
05702    uint32_t ident = 0;
05703    int blastaway = 0;
05704    struct ast_variable *v, *cookies, *params = get_params;
05705    char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
05706    struct ast_str *http_header = NULL, *out = NULL;
05707    struct message m = { 0 };
05708    unsigned int idx;
05709    size_t hdrlen;
05710 
05711    if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
05712       ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
05713       return -1;
05714    }
05715 
05716    cookies = ast_http_get_cookies(headers);
05717    for (v = cookies; v; v = v->next) {
05718       if (!strcasecmp(v->name, "mansession_id")) {
05719          sscanf(v->value, "%30x", &ident);
05720          break;
05721       }
05722    }
05723    if (cookies) {
05724       ast_variables_destroy(cookies);
05725    }
05726 
05727    if (!(session = find_session(ident, 1))) {
05728 
05729       /**/
05730       /* Create new session.
05731        * While it is not in the list we don't need any locking
05732        */
05733       if (!(session = build_mansession(*remote_address))) {
05734          ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
05735          return -1;
05736       }
05737       ao2_lock(session);
05738       session->sin = *remote_address;
05739       session->fd = -1;
05740       session->waiting_thread = AST_PTHREADT_NULL;
05741       session->send_events = 0;
05742       session->inuse = 1;
05743       /*!\note There is approximately a 1 in 1.8E19 chance that the following
05744        * calculation will produce 0, which is an invalid ID, but due to the
05745        * properties of the rand() function (and the constantcy of s), that
05746        * won't happen twice in a row.
05747        */
05748       while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
05749       session->last_ev = grab_last();
05750       AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
05751    }
05752    ao2_unlock(session);
05753 
05754    http_header = ast_str_create(128);
05755    out = ast_str_create(2048);
05756 
05757    ast_mutex_init(&s.lock);
05758 
05759    if (http_header == NULL || out == NULL) {
05760       ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
05761       goto generic_callback_out;
05762    }
05763 
05764    s.session = session;
05765    s.fd = mkstemp(template);  /* create a temporary file for command output */
05766    unlink(template);
05767    if (s.fd <= -1) {
05768       ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
05769       goto generic_callback_out;
05770    }
05771    s.f = fdopen(s.fd, "w+");
05772    if (!s.f) {
05773       ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
05774       ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
05775       close(s.fd);
05776       goto generic_callback_out;
05777    }
05778 
05779    if (method == AST_HTTP_POST) {
05780       params = ast_http_get_post_vars(ser, headers);
05781    }
05782 
05783    for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
05784       hdrlen = strlen(v->name) + strlen(v->value) + 3;
05785       m.headers[m.hdrcount] = ast_malloc(hdrlen);
05786       if (!m.headers[m.hdrcount]) {
05787          /* Allocation failure */
05788          continue;
05789       }
05790       snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
05791       ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
05792       ++m.hdrcount;
05793    }
05794 
05795    if (process_message(&s, &m)) {
05796       if (session->authenticated) {
05797          if (manager_displayconnects(session)) {
05798             ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
05799          }
05800       } else {
05801          if (displayconnects) {
05802             ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
05803          }
05804       }
05805       session->needdestroy = 1;
05806    }
05807 
05808    /* Free request headers. */
05809    for (idx = 0; idx < m.hdrcount; ++idx) {
05810       ast_free((void *) m.headers[idx]);
05811       m.headers[idx] = NULL;
05812    }
05813 
05814    ast_str_append(&http_header, 0,
05815       "Content-type: text/%s\r\n"
05816       "Cache-Control: no-cache;\r\n"
05817       "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
05818       "Pragma: SuppressEvents\r\n",
05819       contenttype[format],
05820       session->managerid, httptimeout);
05821 
05822    if (format == FORMAT_XML) {
05823       ast_str_append(&out, 0, "<ajax-response>\n");
05824    } else if (format == FORMAT_HTML) {
05825       /*
05826        * When handling AMI-over-HTTP in HTML format, we provide a simple form for
05827        * debugging purposes. This HTML code should not be here, we
05828        * should read from some config file...
05829        */
05830 
05831 #define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
05832 #define TEST_STRING \
05833    "<form action=\"manager\" method=\"post\">\n\
05834    Action: <select name=\"action\">\n\
05835       <option value=\"\">-----&gt;</option>\n\
05836       <option value=\"login\">login</option>\n\
05837       <option value=\"command\">Command</option>\n\
05838       <option value=\"waitevent\">waitevent</option>\n\
05839       <option value=\"listcommands\">listcommands</option>\n\
05840    </select>\n\
05841    or <input name=\"action\"><br/>\n\
05842    CLI Command <input name=\"command\"><br>\n\
05843    user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
05844    <input type=\"submit\">\n</form>\n"
05845 
05846       ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
05847       ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
05848       ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
05849       ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
05850    }
05851 
05852    process_output(&s, &out, params, format);
05853 
05854    if (format == FORMAT_XML) {
05855       ast_str_append(&out, 0, "</ajax-response>\n");
05856    } else if (format == FORMAT_HTML) {
05857       ast_str_append(&out, 0, "</table></body>\r\n");
05858    }
05859 
05860    ao2_lock(session);
05861    /* Reset HTTP timeout.  If we're not authenticated, keep it extremely short */
05862    session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
05863 
05864    if (session->needdestroy) {
05865       if (session->inuse == 1) {
05866          ast_debug(1, "Need destroy, doing it now!\n");
05867          blastaway = 1;
05868       } else {
05869          ast_debug(1, "Need destroy, but can't do it yet!\n");
05870          if (session->waiting_thread != AST_PTHREADT_NULL) {
05871             pthread_kill(session->waiting_thread, SIGURG);
05872          }
05873          session->inuse--;
05874       }
05875    } else {
05876       session->inuse--;
05877    }
05878    ao2_unlock(session);
05879 
05880    ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
05881    http_header = out = NULL;
05882 
05883 generic_callback_out:
05884    ast_mutex_destroy(&s.lock);
05885 
05886    /* Clear resource */
05887 
05888    if (method == AST_HTTP_POST && params) {
05889       ast_variables_destroy(params);
05890    }
05891    if (http_header) {
05892       ast_free(http_header);
05893    }
05894    if (out) {
05895       ast_free(out);
05896    }
05897 
05898    if (session && blastaway) {
05899       session_destroy(session);
05900    } else if (session && session->f) {
05901       fclose(session->f);
05902       session->f = NULL;
05903    }
05904 
05905    return 0;
05906 }

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

References allowmultiplelogin, ami_desc, ami_tls_cfg, amis_desc, 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, displayconnects, ast_tls_config::enabled, ast_cli_args::fd, FORMAT, FORMAT2, httptimeout, ast_tcptls_session_args::local_address, manager_channelvars, manager_debug, manager_enabled, ast_tls_config::pvtfile, S_OR, timestampevents, ast_cli_entry::usage, and webmanager_enabled.

06376 {
06377    switch (cmd) {
06378    case CLI_INIT:
06379       e->command = "manager show settings";
06380       e->usage =
06381          "Usage: manager show settings\n"
06382          "       Provides detailed list of the configuration of the Manager.\n";
06383       return NULL;
06384    case CLI_GENERATE:
06385       return NULL;
06386    }
06387 #define FORMAT "  %-25.25s  %-15.15s\n"
06388 #define FORMAT2 "  %-25.25s  %-15d\n"
06389    if (a->argc != 3) {
06390       return CLI_SHOWUSAGE;
06391    }
06392    ast_cli(a->fd, "\nGlobal Settings:\n");
06393    ast_cli(a->fd, "----------------\n");
06394    ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
06395    ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
06396    ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
06397    ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
06398    ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
06399    ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
06400    ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
06401    ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
06402    ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
06403    ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
06404    ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
06405    ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
06406    ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
06407    ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
06408    ast_cli(a->fd, FORMAT, "Block sockets:", AST_CLI_YESNO(block_sockets));
06409 #undef FORMAT
06410 #undef FORMAT2
06411 
06412    return CLI_SUCCESS;
06413 }

int init_manager ( void   ) 

Called by Asterisk initialization.

Definition at line 6900 of file manager.c.

References __init_manager().

Referenced by main().

06901 {
06902    return __init_manager(0);
06903 }

static void load_channelvars ( struct ast_variable var  )  [static]

Definition at line 6435 of file manager.c.

References ast_calloc, ast_free, AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_strdupa, manager_channel_variable::entry, free_channelvars(), manager_channelvars, manager_channel_variable::next, strsep(), and var.

06436 {
06437    struct manager_channel_variable *mcv;
06438    char *remaining = ast_strdupa(var->value);
06439    char *next;
06440 
06441    ast_free(manager_channelvars);
06442    manager_channelvars = ast_strdup(var->value);
06443 
06444    /*
06445     * XXX TODO: To allow dialplan functions to have more than one
06446     * parameter requires eliminating the '|' as a separator so we
06447     * could use AST_STANDARD_APP_ARGS() to separate items.
06448     */
06449    free_channelvars();
06450    AST_RWLIST_WRLOCK(&channelvars);
06451    while ((next = strsep(&remaining, ",|"))) {
06452       if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
06453          break;
06454       }
06455       strcpy(mcv->name, next); /* SAFE */
06456       if (strchr(next, '(')) {
06457          mcv->isfunc = 1;
06458       }
06459       AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
06460    }
06461    AST_RWLIST_UNLOCK(&channelvars);
06462 }

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

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

06222 {
06223    int retval;
06224    struct sockaddr_in ser_remote_address_tmp;
06225 
06226    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06227    retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06228    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06229    return retval;
06230 }

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

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

06233 {
06234    int retval;
06235    struct sockaddr_in ser_remote_address_tmp;
06236 
06237    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06238    retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06239    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06240    return retval;
06241 }

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

Definition at line 5660 of file manager.c.

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

05661 {
05662    char *buf;
05663    size_t l;
05664 
05665    if (!s->f)
05666       return;
05667 
05668    /* Ensure buffer is NULL-terminated */
05669    fprintf(s->f, "%c", 0);
05670    fflush(s->f);
05671 
05672    if ((l = ftell(s->f))) {
05673       if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) {
05674          ast_log(LOG_WARNING, "mmap failed.  Manager output was not processed\n");
05675       } else {
05676          if (format == FORMAT_XML || format == FORMAT_HTML) {
05677             xml_translate(out, buf, params, format);
05678          } else {
05679             ast_str_append(out, 0, "%s", buf);
05680          }
05681          munmap(buf, l);
05682       }
05683    } else if (format == FORMAT_XML || format == FORMAT_HTML) {
05684       xml_translate(out, "", params, format);
05685    }
05686 
05687    fclose(s->f);
05688    s->f = NULL;
05689    close(s->fd);
05690    s->fd = -1;
05691 }

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

References purge_events(), and purge_sessions().

06347 {
06348    purge_sessions(1);
06349    purge_events();
06350 }

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

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

06244 {
06245    int retval;
06246    struct sockaddr_in ser_remote_address_tmp;
06247 
06248    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06249    retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06250    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06251    return retval;
06252 }

int reload_manager ( void   ) 

Called by Asterisk module functions and the CLI command.

Definition at line 6905 of file manager.c.

References __init_manager().

Referenced by handle_manager_reload().

06906 {
06907    return __init_manager(1);
06908 }

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

Definition at line 5504 of file manager.c.

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

05505 {
05506    /* Due to the simplicity of struct variable_count, it makes no difference
05507     * if you pass in objects or strings, the same operation applies. This is
05508     * due to the fact that the hash occurs on the first element, which means
05509     * the address of both the struct and the string are exactly the same. */
05510    struct variable_count *vc = obj;
05511    char *str = vstr;
05512    return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
05513 }

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

Definition at line 5497 of file manager.c.

References ast_str_hash(), and variable_count::varname.

05498 {
05499    const struct variable_count *vc = vvc;
05500 
05501    return ast_str_hash(vc->varname);
05502 }

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

Definition at line 5435 of file manager.c.

References ast_str_append().

05436 {
05437    /* store in a local buffer to avoid calling ast_str_append too often */
05438    char buf[256];
05439    char *dst = buf;
05440    int space = sizeof(buf);
05441    /* repeat until done and nothing to flush */
05442    for ( ; *src || dst != buf ; src++) {
05443       if (*src == '\0' || space < 10) {   /* flush */
05444          *dst++ = '\0';
05445          ast_str_append(out, 0, "%s", buf);
05446          dst = buf;
05447          space = sizeof(buf);
05448          if (*src == '\0') {
05449             break;
05450          }
05451       }
05452 
05453       if ( (mode & 2) && !isalnum(*src)) {
05454          *dst++ = '_';
05455          space--;
05456          continue;
05457       }
05458       switch (*src) {
05459       case '<':
05460          strcpy(dst, "&lt;");
05461          dst += 4;
05462          space -= 4;
05463          break;
05464       case '>':
05465          strcpy(dst, "&gt;");
05466          dst += 4;
05467          space -= 4;
05468          break;
05469       case '\"':
05470          strcpy(dst, "&quot;");
05471          dst += 6;
05472          space -= 6;
05473          break;
05474       case '\'':
05475          strcpy(dst, "&apos;");
05476          dst += 6;
05477          space -= 6;
05478          break;
05479       case '&':
05480          strcpy(dst, "&amp;");
05481          dst += 5;
05482          space -= 5;
05483          break;
05484 
05485       default:
05486          *dst++ = mode ? tolower(*src) : *src;
05487          space--;
05488       }
05489    }
05490 }

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

References FORMAT_XML, ast_variable::name, ast_variable::next, ast_variable::value, and var.

Referenced by process_output().

05544 {
05545    struct ast_variable *v;
05546    const char *dest = NULL;
05547    char *var, *val;
05548    const char *objtype = NULL;
05549    int in_data = 0;  /* parsing data */
05550    int inobj = 0;
05551    int xml = (format == FORMAT_XML);
05552    struct variable_count *vc = NULL;
05553    struct ao2_container *vco = NULL;
05554 
05555    if (xml) {
05556       /* dest and objtype need only for XML format */
05557       for (v = get_vars; v; v = v->next) {
05558          if (!strcasecmp(v->name, "ajaxdest")) {
05559             dest = v->value;
05560          } else if (!strcasecmp(v->name, "ajaxobjtype")) {
05561             objtype = v->value;
05562          }
05563       }
05564       if (ast_strlen_zero(dest)) {
05565          dest = "unknown";
05566       }
05567       if (ast_strlen_zero(objtype)) {
05568          objtype = "generic";
05569       }
05570    }
05571 
05572    /* we want to stop when we find an empty line */
05573    while (in && *in) {
05574       val = strsep(&in, "\r\n"); /* mark start and end of line */
05575       if (in && *in == '\n') {   /* remove trailing \n if any */
05576          in++;
05577       }
05578       ast_trim_blanks(val);
05579       ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
05580       if (ast_strlen_zero(val)) {
05581          /* empty line */
05582          if (in_data) {
05583             /* close data in Opaque mode */
05584             ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05585             in_data = 0;
05586          }
05587 
05588          if (inobj) {
05589             /* close block */
05590             ast_str_append(out, 0, xml ? " /></response>\n" :
05591                "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05592             inobj = 0;
05593             ao2_ref(vco, -1);
05594             vco = NULL;
05595          }
05596          continue;
05597       }
05598 
05599       if (!inobj) {
05600          /* start new block */
05601          if (xml) {
05602             ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
05603          }
05604          vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
05605          inobj = 1;
05606       }
05607 
05608       if (in_data) {
05609          /* Process data field in Opaque mode. This is a
05610           * followup, so we re-add line feeds. */
05611          ast_str_append(out, 0, xml ? "\n" : "<br>\n");
05612          xml_copy_escape(out, val, 0);   /* data field */
05613          continue;
05614       }
05615 
05616       /* We expect "Name: value" line here */
05617       var = strsep(&val, ":");
05618       if (val) {
05619          /* found the field name */
05620          val = ast_skip_blanks(val);
05621          ast_trim_blanks(var);
05622       } else {
05623          /* field name not found, switch to opaque mode */
05624          val = var;
05625          var = "Opaque-data";
05626          in_data = 1;
05627       }
05628 
05629 
05630       ast_str_append(out, 0, xml ? " " : "<tr><td>");
05631       if ((vc = ao2_find(vco, var, 0))) {
05632          vc->count++;
05633       } else {
05634          /* Create a new entry for this one */
05635          vc = ao2_alloc(sizeof(*vc), NULL);
05636          vc->varname = var;
05637          vc->count = 1;
05638          ao2_link(vco, vc);
05639       }
05640 
05641       xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
05642       if (vc->count > 1) {
05643          ast_str_append(out, 0, "-%d", vc->count);
05644       }
05645       ao2_ref(vc, -1);
05646       ast_str_append(out, 0, xml ? "='" : "</td><td>");
05647       xml_copy_escape(out, val, 0); /* data field */
05648       if (!in_data || !*in) {
05649          ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05650       }
05651    }
05652 
05653    if (inobj) {
05654       ast_str_append(out, 0, xml ? " /></response>\n" :
05655          "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05656       ao2_ref(vco, -1);
05657    }
05658 }


Variable Documentation

struct ast_http_uri amanageruri [static]

Definition at line 6322 of file manager.c.

struct ast_http_uri amanagerxmluri [static]

Definition at line 6331 of file manager.c.

struct ast_tcptls_session_args ami_desc [static]

Definition at line 6353 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_tls_config ami_tls_cfg [static]

Definition at line 6352 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_tcptls_session_args amis_desc [static]

Definition at line 6364 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_http_uri arawmanuri [static]

Definition at line 6313 of file manager.c.

struct ast_cli_entry cli_manager[] [static]

Definition at line 6415 of file manager.c.

Referenced by __init_manager().

const char* const contenttype[] [static]

Initial value:

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

Definition at line 5292 of file manager.c.

struct ast_http_uri manageruri [static]

Definition at line 6262 of file manager.c.

struct ast_http_uri managerxmluri [static]

Definition at line 6270 of file manager.c.

struct ast_http_uri rawmanuri [static]

Definition at line 6254 of file manager.c.

int registered = 0 [static]

Definition at line 6340 of file manager.c.

int webregged = 0 [static]

Definition at line 6341 of file manager.c.

const char* words[AST_MAX_CMD_LEN]

Definition at line 921 of file manager.c.

Referenced by check_blacklist().


Generated on Sat Mar 10 01:55:31 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7