Mon Jun 27 16:51:16 2011

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"

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)
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 int action_events (struct mansession *s, const struct message *m)
static int action_extensionstate (struct mansession *s, const struct message *m)
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,...)
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 ()
 Check if AMI is enabled.
static int check_manager_session_inuse (const char *name)
int check_webmanager_enabled ()
 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 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 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_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
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 5058 of file manager.c.

05058                    {
05059    FORMAT_RAW,
05060    FORMAT_HTML,
05061    FORMAT_XML,
05062 };


Function Documentation

static int __init_manager ( int  reload  )  [static]

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

06185 {
06186    struct ast_config *ucfg = NULL, *cfg = NULL;
06187    const char *val;
06188    char *cat = NULL;
06189    int newhttptimeout = DEFAULT_HTTPTIMEOUT;
06190    struct ast_manager_user *user = NULL;
06191    struct ast_variable *var;
06192    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06193    char a1[256];
06194    char a1_hash[256];
06195    struct sockaddr_in ami_desc_local_address_tmp = { 0, };
06196    struct sockaddr_in amis_desc_local_address_tmp = { 0, };
06197 
06198    if (!registered) {
06199       /* Register default actions */
06200       ast_manager_register_xml("Ping", 0, action_ping);
06201       ast_manager_register_xml("Events", 0, action_events);
06202       ast_manager_register_xml("Logoff", 0, action_logoff);
06203       ast_manager_register_xml("Login", 0, action_login);
06204       ast_manager_register_xml("Challenge", 0, action_challenge);
06205       ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
06206       ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
06207       ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar);
06208       ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
06209       ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
06210       ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
06211       ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
06212       ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
06213       ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
06214       ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect);
06215       ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer);
06216       ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate);
06217       ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command);
06218       ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
06219       ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
06220       ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
06221       ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
06222       ast_manager_register_xml("ListCommands", 0, action_listcommands);
06223       ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext);
06224       ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent);
06225       ast_manager_register_xml("WaitEvent", 0, action_waitevent);
06226       ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
06227       ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
06228       ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
06229       ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
06230       ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
06231       ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
06232       ast_manager_register_xml("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
06233 
06234       ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
06235       ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
06236       registered = 1;
06237       /* Append placeholder event so master_eventq never runs dry */
06238       append_event("Event: Placeholder\r\n\r\n", 0);
06239    }
06240    if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
06241       return 0;
06242    }
06243 
06244    manager_enabled = DEFAULT_ENABLED;
06245    webmanager_enabled = DEFAULT_WEBENABLED;
06246    displayconnects = DEFAULT_DISPLAYCONNECTS;
06247    broken_events_action = DEFAULT_BROKENEVENTSACTION;
06248    block_sockets = DEFAULT_BLOCKSOCKETS;
06249    timestampevents = DEFAULT_TIMESTAMPEVENTS;
06250    httptimeout = DEFAULT_HTTPTIMEOUT;
06251    authtimeout = DEFAULT_AUTHTIMEOUT;
06252    authlimit = DEFAULT_AUTHLIMIT;
06253 
06254    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
06255       ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled.\n");
06256       return 0;
06257    }
06258 
06259    /* default values */
06260    ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm));
06261    memset(&ami_desc.local_address, 0, sizeof(struct sockaddr_in));
06262    memset(&amis_desc.local_address, 0, sizeof(amis_desc.local_address));
06263    amis_desc_local_address_tmp.sin_port = htons(5039);
06264    ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT);
06265 
06266    ami_tls_cfg.enabled = 0;
06267    if (ami_tls_cfg.certfile) {
06268       ast_free(ami_tls_cfg.certfile);
06269    }
06270    ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
06271    if (ami_tls_cfg.pvtfile) {
06272       ast_free(ami_tls_cfg.pvtfile);
06273    }
06274    ami_tls_cfg.pvtfile = ast_strdup("");
06275    if (ami_tls_cfg.cipher) {
06276       ast_free(ami_tls_cfg.cipher);
06277    }
06278    ami_tls_cfg.cipher = ast_strdup("");
06279 
06280    free_channelvars();
06281 
06282    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
06283       val = var->value;
06284 
06285       if (!ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
06286          continue;
06287       }
06288 
06289       if (!strcasecmp(var->name, "enabled")) {
06290          manager_enabled = ast_true(val);
06291       } else if (!strcasecmp(var->name, "block-sockets")) {
06292          block_sockets = ast_true(val);
06293       } else if (!strcasecmp(var->name, "webenabled")) {
06294          webmanager_enabled = ast_true(val);
06295       } else if (!strcasecmp(var->name, "port")) {
06296          ami_desc_local_address_tmp.sin_port = htons(atoi(val));
06297       } else if (!strcasecmp(var->name, "bindaddr")) {
06298          if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) {
06299             ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
06300             memset(&ami_desc_local_address_tmp.sin_addr, 0,
06301                    sizeof(ami_desc_local_address_tmp.sin_addr));
06302          }
06303       } else if (!strcasecmp(var->name, "brokeneventsaction")) {
06304          broken_events_action = ast_true(val);
06305       } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
06306          allowmultiplelogin = ast_true(val);
06307       } else if (!strcasecmp(var->name, "displayconnects")) {
06308          displayconnects = ast_true(val);
06309       } else if (!strcasecmp(var->name, "timestampevents")) {
06310          timestampevents = ast_true(val);
06311       } else if (!strcasecmp(var->name, "debug")) {
06312          manager_debug = ast_true(val);
06313       } else if (!strcasecmp(var->name, "httptimeout")) {
06314          newhttptimeout = atoi(val);
06315       } else if (!strcasecmp(var->name, "authtimeout")) {
06316          int timeout = atoi(var->value);
06317 
06318          if (timeout < 1) {
06319             ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
06320          } else {
06321             authtimeout = timeout;
06322          }
06323       } else if (!strcasecmp(var->name, "authlimit")) {
06324          int limit = atoi(var->value);
06325 
06326          if (limit < 1) {
06327             ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
06328          } else {
06329             authlimit = limit;
06330          }
06331       } else if (!strcasecmp(var->name, "channelvars")) {
06332          struct manager_channel_variable *mcv;
06333          char *remaining = ast_strdupa(val), *next;
06334          ast_free(manager_channelvars);
06335          manager_channelvars = ast_strdup(val);
06336          AST_RWLIST_WRLOCK(&channelvars);
06337          while ((next = strsep(&remaining, ",|"))) {
06338             if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
06339                break;
06340             }
06341             strcpy(mcv->name, next); /* SAFE */
06342             if (strchr(next, '(')) {
06343                mcv->isfunc = 1;
06344             }
06345             AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
06346          }
06347          AST_RWLIST_UNLOCK(&channelvars);
06348       } else {
06349          ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
06350             var->name, val);
06351       }
06352    }
06353 
06354    ami_desc_local_address_tmp.sin_family = AF_INET;
06355    amis_desc_local_address_tmp.sin_family = AF_INET;
06356 
06357    /* if the amis address has not been set, default is the same as non secure ami */
06358    if (!amis_desc_local_address_tmp.sin_addr.s_addr) {
06359       amis_desc_local_address_tmp.sin_addr =
06360           ami_desc_local_address_tmp.sin_addr;
06361    }
06362 
06363    if (manager_enabled) {
06364       ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp);
06365       ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp);
06366    }
06367 
06368    AST_RWLIST_WRLOCK(&users);
06369 
06370    /* First, get users from users.conf */
06371    ucfg = ast_config_load2("users.conf", "manager", config_flags);
06372    if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
06373       const char *hasmanager;
06374       int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
06375 
06376       while ((cat = ast_category_browse(ucfg, cat))) {
06377          if (!strcasecmp(cat, "general")) {
06378             continue;
06379          }
06380 
06381          hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
06382          if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
06383             const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
06384             const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
06385             const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
06386             const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
06387             const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
06388 
06389             /* Look for an existing entry,
06390              * if none found - create one and add it to the list
06391              */
06392             if (!(user = get_manager_by_name_locked(cat))) {
06393                if (!(user = ast_calloc(1, sizeof(*user)))) {
06394                   break;
06395                }
06396 
06397                /* Copy name over */
06398                ast_copy_string(user->username, cat, sizeof(user->username));
06399                /* Insert into list */
06400                AST_LIST_INSERT_TAIL(&users, user, list);
06401                user->ha = NULL;
06402                user->keep = 1;
06403                user->readperm = -1;
06404                user->writeperm = -1;
06405                /* Default displayconnect from [general] */
06406                user->displayconnects = displayconnects;
06407                user->writetimeout = 100;
06408             }
06409 
06410             if (!user_secret) {
06411                user_secret = ast_variable_retrieve(ucfg, "general", "secret");
06412             }
06413             if (!user_read) {
06414                user_read = ast_variable_retrieve(ucfg, "general", "read");
06415             }
06416             if (!user_write) {
06417                user_write = ast_variable_retrieve(ucfg, "general", "write");
06418             }
06419             if (!user_displayconnects) {
06420                user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
06421             }
06422             if (!user_writetimeout) {
06423                user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
06424             }
06425 
06426             if (!ast_strlen_zero(user_secret)) {
06427                if (user->secret) {
06428                   ast_free(user->secret);
06429                }
06430                user->secret = ast_strdup(user_secret);
06431             }
06432 
06433             if (user_read) {
06434                user->readperm = get_perm(user_read);
06435             }
06436             if (user_write) {
06437                user->writeperm = get_perm(user_write);
06438             }
06439             if (user_displayconnects) {
06440                user->displayconnects = ast_true(user_displayconnects);
06441             }
06442             if (user_writetimeout) {
06443                int value = atoi(user_writetimeout);
06444                if (value < 100) {
06445                   ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at users.conf line %d\n", var->value, var->lineno);
06446                } else {
06447                   user->writetimeout = value;
06448                }
06449             }
06450          }
06451       }
06452       ast_config_destroy(ucfg);
06453    }
06454 
06455    /* cat is NULL here in any case */
06456 
06457    while ((cat = ast_category_browse(cfg, cat))) {
06458       struct ast_ha *oldha;
06459 
06460       if (!strcasecmp(cat, "general")) {
06461          continue;
06462       }
06463 
06464       /* Look for an existing entry, if none found - create one and add it to the list */
06465       if (!(user = get_manager_by_name_locked(cat))) {
06466          if (!(user = ast_calloc(1, sizeof(*user)))) {
06467             break;
06468          }
06469          /* Copy name over */
06470          ast_copy_string(user->username, cat, sizeof(user->username));
06471 
06472          user->ha = NULL;
06473          user->readperm = 0;
06474          user->writeperm = 0;
06475          /* Default displayconnect from [general] */
06476          user->displayconnects = displayconnects;
06477          user->writetimeout = 100;
06478          user->whitefilters = ao2_container_alloc(1, NULL, NULL);
06479          user->blackfilters = ao2_container_alloc(1, NULL, NULL);
06480 
06481          /* Insert into list */
06482          AST_RWLIST_INSERT_TAIL(&users, user, list);
06483       } else {
06484          ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
06485          ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
06486       }
06487 
06488       /* Make sure we keep this user and don't destroy it during cleanup */
06489       user->keep = 1;
06490       oldha = user->ha;
06491       user->ha = NULL;
06492 
06493       var = ast_variable_browse(cfg, cat);
06494       for (; var; var = var->next) {
06495          if (!strcasecmp(var->name, "secret")) {
06496             if (user->secret) {
06497                ast_free(user->secret);
06498             }
06499             user->secret = ast_strdup(var->value);
06500          } else if (!strcasecmp(var->name, "deny") ||
06501                    !strcasecmp(var->name, "permit")) {
06502             user->ha = ast_append_ha(var->name, var->value, user->ha, NULL);
06503          }  else if (!strcasecmp(var->name, "read") ) {
06504             user->readperm = get_perm(var->value);
06505          }  else if (!strcasecmp(var->name, "write") ) {
06506             user->writeperm = get_perm(var->value);
06507          }  else if (!strcasecmp(var->name, "displayconnects") ) {
06508             user->displayconnects = ast_true(var->value);
06509          } else if (!strcasecmp(var->name, "writetimeout")) {
06510             int value = atoi(var->value);
06511             if (value < 100) {
06512                ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
06513             } else {
06514                user->writetimeout = value;
06515             }
06516          } else if (!strcasecmp(var->name, "eventfilter")) {
06517             const char *value = var->value;
06518             regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
06519             if (new_filter) {
06520                int is_blackfilter;
06521                if (value[0] == '!') {
06522                   is_blackfilter = 1;
06523                   value++;
06524                } else {
06525                   is_blackfilter = 0;
06526                }
06527                if (regcomp(new_filter, value, 0)) {
06528                   ao2_t_ref(new_filter, -1, "failed to make regx");
06529                } else {
06530                   if (is_blackfilter) {
06531                      ao2_t_link(user->blackfilters, new_filter, "link new filter into black user container");
06532                   } else {
06533                      ao2_t_link(user->whitefilters, new_filter, "link new filter into white user container");
06534                   }
06535                }
06536             }
06537          } else {
06538             ast_debug(1, "%s is an unknown option.\n", var->name);
06539          }
06540       }
06541       ast_free_ha(oldha);
06542    }
06543    ast_config_destroy(cfg);
06544 
06545    /* Perform cleanup - essentially prune out old users that no longer exist */
06546    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
06547       if (user->keep) { /* valid record. clear flag for the next round */
06548          user->keep = 0;
06549 
06550          /* Calculate A1 for Digest auth */
06551          snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
06552          ast_md5_hash(a1_hash,a1);
06553          if (user->a1_hash) {
06554             ast_free(user->a1_hash);
06555          }
06556          user->a1_hash = ast_strdup(a1_hash);
06557          continue;
06558       }
06559       /* We do not need to keep this user so take them out of the list */
06560       AST_RWLIST_REMOVE_CURRENT(list);
06561       ast_debug(4, "Pruning user '%s'\n", user->username);
06562       /* Free their memory now */
06563       if (user->a1_hash) {
06564          ast_free(user->a1_hash);
06565       }
06566       if (user->secret) {
06567          ast_free(user->secret);
06568       }
06569       ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
06570       ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
06571       ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
06572       ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
06573       ast_free_ha(user->ha);
06574       ast_free(user);
06575    }
06576    AST_RWLIST_TRAVERSE_SAFE_END;
06577 
06578    AST_RWLIST_UNLOCK(&users);
06579 
06580    if (!reload) {
06581       /* If you have a NULL hash fn, you only need a single bucket */
06582       sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn);
06583    }
06584 
06585    if (webmanager_enabled && manager_enabled) {
06586       if (!webregged) {
06587 
06588          ast_http_uri_link(&rawmanuri);
06589          ast_http_uri_link(&manageruri);
06590          ast_http_uri_link(&managerxmluri);
06591 
06592          ast_http_uri_link(&arawmanuri);
06593          ast_http_uri_link(&amanageruri);
06594          ast_http_uri_link(&amanagerxmluri);
06595          webregged = 1;
06596       }
06597    } else {
06598       if (webregged) {
06599          ast_http_uri_unlink(&rawmanuri);
06600          ast_http_uri_unlink(&manageruri);
06601          ast_http_uri_unlink(&managerxmluri);
06602 
06603          ast_http_uri_unlink(&arawmanuri);
06604          ast_http_uri_unlink(&amanageruri);
06605          ast_http_uri_unlink(&amanagerxmluri);
06606          webregged = 0;
06607       }
06608    }
06609 
06610    if (newhttptimeout > 0) {
06611       httptimeout = newhttptimeout;
06612    }
06613 
06614    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled");
06615 
06616    ast_tcptls_server_start(&ami_desc);
06617    if (ast_ssl_setup(amis_desc.tls_cfg)) {
06618       ast_tcptls_server_start(&amis_desc);
06619    }
06620    return 0;
06621 }

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

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

06645 {
06646    AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
06647 
06648    return 0;
06649 }

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

06657 {
06658    struct ast_datastore *datastore = NULL;
06659 
06660    if (info == NULL)
06661       return NULL;
06662 
06663    AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
06664       if (datastore->info != info) {
06665          continue;
06666       }
06667 
06668       if (uid == NULL) {
06669          /* matched by type only */
06670          break;
06671       }
06672 
06673       if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
06674          /* Matched by type AND uid */
06675          break;
06676       }
06677    }
06678    AST_LIST_TRAVERSE_SAFE_END;
06679 
06680    return datastore;
06681 }

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

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

06652 {
06653    return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
06654 }

int astman_is_authed ( uint32_t  ident  ) 

Determinie if a manager session ident is authenticated.

Definition at line 5134 of file manager.c.

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

Referenced by http_post_callback(), and static_callback().

05135 {
05136    int authed;
05137    struct mansession_session *session;
05138 
05139    if (!(session = find_session(ident, 0)))
05140       return 0;
05141 
05142    authed = (session->authenticated != 0);
05143 
05144    ao2_unlock(session);
05145    unref_mansession(session);
05146 
05147    return authed;
05148 }

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

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

05151 {
05152    int result = 0;
05153    struct mansession_session *session;
05154    struct ao2_iterator i;
05155 
05156    if (ident == 0) {
05157       return 0;
05158    }
05159 
05160    i = ao2_iterator_init(sessions, 0);
05161    while ((session = ao2_iterator_next(&i))) {
05162       ao2_lock(session);
05163       if ((session->managerid == ident) && (session->readperm & perm)) {
05164          result = 1;
05165          ao2_unlock(session);
05166          unref_mansession(session);
05167          break;
05168       }
05169       ao2_unlock(session);
05170       unref_mansession(session);
05171    }
05172    ao2_iterator_destroy(&i);
05173    return result;
05174 }

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

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

05177 {
05178    int result = 0;
05179    struct mansession_session *session;
05180    struct ao2_iterator i;
05181 
05182    if (ident == 0) {
05183       return 0;
05184    }
05185 
05186    i = ao2_iterator_init(sessions, 0);
05187    while ((session = ao2_iterator_next(&i))) {
05188       ao2_lock(session);
05189       if ((session->managerid == ident) && (session->writeperm & perm)) {
05190          result = 1;
05191          ao2_unlock(session);
05192          unref_mansession(session);
05193          break;
05194       }
05195       ao2_unlock(session);
05196       unref_mansession(session);
05197    }
05198    ao2_iterator_destroy(&i);
05199    return result;
05200 }

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

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

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

05662 {
05663    struct mansession_session *session = NULL;
05664    struct mansession s = { NULL, };
05665    struct ast_variable *v, *params = get_params;
05666    char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
05667    struct ast_str *http_header = NULL, *out = NULL;
05668    size_t result_size = 512;
05669    struct message m = { 0 };
05670    unsigned int x;
05671    size_t hdrlen;
05672 
05673    time_t time_now = time(NULL);
05674    unsigned long nonce = 0, nc;
05675    struct ast_http_digest d = { NULL, };
05676    struct ast_manager_user *user = NULL;
05677    int stale = 0;
05678    char resp_hash[256]="";
05679    /* Cache for user data */
05680    char u_username[80];
05681    int u_readperm;
05682    int u_writeperm;
05683    int u_writetimeout;
05684    int u_displayconnects;
05685    struct ast_sockaddr addr;
05686 
05687    if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
05688       ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
05689       return -1;
05690    }
05691 
05692    /* Find "Authorization: " header */
05693    for (v = headers; v; v = v->next) {
05694       if (!strcasecmp(v->name, "Authorization")) {
05695          break;
05696       }
05697    }
05698 
05699    if (!v || ast_strlen_zero(v->value)) {
05700       goto out_401; /* Authorization Header not present - send auth request */
05701    }
05702 
05703    /* Digest found - parse */
05704    if (ast_string_field_init(&d, 128)) {
05705       ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
05706       return -1;
05707    }
05708 
05709    if (ast_parse_digest(v->value, &d, 0, 1)) {
05710       /* Error in Digest - send new one */
05711       nonce = 0;
05712       goto out_401;
05713    }
05714    if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
05715       ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
05716       nonce = 0;
05717       goto out_401;
05718    }
05719 
05720    AST_RWLIST_WRLOCK(&users);
05721    user = get_manager_by_name_locked(d.username);
05722    if(!user) {
05723       AST_RWLIST_UNLOCK(&users);
05724       ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
05725       nonce = 0;
05726       goto out_401;
05727    }
05728 
05729    ast_sockaddr_from_sin(&addr, remote_address);
05730    /* --- We have User for this auth, now check ACL */
05731    if (user->ha && !ast_apply_ha(user->ha, &addr)) {
05732       AST_RWLIST_UNLOCK(&users);
05733       ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
05734       ast_http_error(ser, 403, "Permission denied", "Permission denied\n");
05735       return -1;
05736    }
05737 
05738    /* --- We have auth, so check it */
05739 
05740    /* compute the expected response to compare with what we received */
05741    {
05742       char a2[256];
05743       char a2_hash[256];
05744       char resp[256];
05745 
05746       /* XXX Now request method are hardcoded in A2 */
05747       snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
05748       ast_md5_hash(a2_hash, a2);
05749 
05750       if (d.qop) {
05751          /* RFC 2617 */
05752          snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
05753       }  else {
05754          /* RFC 2069 */
05755          snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
05756       }
05757       ast_md5_hash(resp_hash, resp);
05758    }
05759 
05760    if (!d.nonce  || strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
05761       /* Something was wrong, so give the client to try with a new challenge */
05762       AST_RWLIST_UNLOCK(&users);
05763       nonce = 0;
05764       goto out_401;
05765    }
05766 
05767    /*
05768     * User are pass Digest authentication.
05769     * Now, cache the user data and unlock user list.
05770     */
05771    ast_copy_string(u_username, user->username, sizeof(u_username));
05772    u_readperm = user->readperm;
05773    u_writeperm = user->writeperm;
05774    u_displayconnects = user->displayconnects;
05775    u_writetimeout = user->writetimeout;
05776    AST_RWLIST_UNLOCK(&users);
05777 
05778    if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
05779       /*
05780        * Create new session.
05781        * While it is not in the list we don't need any locking
05782        */
05783       if (!(session = build_mansession(*remote_address))) {
05784          ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
05785          return -1;
05786       }
05787       ao2_lock(session);
05788 
05789       ast_copy_string(session->username, u_username, sizeof(session->username));
05790       session->managerid = nonce;
05791       session->last_ev = grab_last();
05792       AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
05793 
05794       session->readperm = u_readperm;
05795       session->writeperm = u_writeperm;
05796       session->writetimeout = u_writetimeout;
05797 
05798       if (u_displayconnects) {
05799          ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
05800       }
05801       session->noncetime = session->sessionstart = time_now;
05802       session->authenticated = 1;
05803    } else if (stale) {
05804       /*
05805        * Session found, but nonce is stale.
05806        *
05807        * This could be because an old request (w/old nonce) arrived.
05808        *
05809        * This may be as the result of http proxy usage (separate delay or
05810        * multipath) or in a situation where a page was refreshed too quickly
05811        * (seen in Firefox).
05812        *
05813        * In this situation, we repeat the 401 auth with the current nonce
05814        * value.
05815        */
05816       nonce = session->managerid;
05817       ao2_unlock(session);
05818       stale = 1;
05819       goto out_401;
05820    } else {
05821       sscanf(d.nc, "%30lx", &nc);
05822       if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
05823          /*
05824           * Nonce time expired (> 2 minutes) or something wrong with nonce
05825           * counter.
05826           *
05827           * Create new nonce key and resend Digest auth request. Old nonce
05828           * is saved for stale checking...
05829           */
05830          session->nc = 0; /* Reset nonce counter */
05831          session->oldnonce = session->managerid;
05832          nonce = session->managerid = ast_random();
05833          session->noncetime = time_now;
05834          ao2_unlock(session);
05835          stale = 1;
05836          goto out_401;
05837       } else {
05838          session->nc = nc; /* All OK, save nonce counter */
05839       }
05840    }
05841 
05842 
05843    /* Reset session timeout. */
05844    session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
05845    ao2_unlock(session);
05846 
05847    ast_mutex_init(&s.lock);
05848    s.session = session;
05849    s.fd = mkstemp(template);  /* create a temporary file for command output */
05850    unlink(template);
05851    if (s.fd <= -1) {
05852       ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
05853       goto auth_callback_out;
05854    }
05855    s.f = fdopen(s.fd, "w+");
05856    if (!s.f) {
05857       ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
05858       ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
05859       close(s.fd);
05860       goto auth_callback_out;
05861    }
05862 
05863    if (method == AST_HTTP_POST) {
05864       params = ast_http_get_post_vars(ser, headers);
05865    }
05866 
05867    for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
05868       hdrlen = strlen(v->name) + strlen(v->value) + 3;
05869       m.headers[m.hdrcount] = alloca(hdrlen);
05870       snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
05871       ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
05872       m.hdrcount = x + 1;
05873    }
05874 
05875    if (process_message(&s, &m)) {
05876       if (u_displayconnects) {
05877          ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
05878       }
05879 
05880       session->needdestroy = 1;
05881    }
05882 
05883    if (s.f) {
05884       result_size = ftell(s.f); /* Calculate approx. size of result */
05885    }
05886 
05887    http_header = ast_str_create(80);
05888    out = ast_str_create(result_size * 2 + 512);
05889 
05890    if (http_header == NULL || out == NULL) {
05891       ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
05892       goto auth_callback_out;
05893    }
05894 
05895    ast_str_append(&http_header, 0, "Content-type: text/%s", contenttype[format]);
05896 
05897    if (format == FORMAT_XML) {
05898       ast_str_append(&out, 0, "<ajax-response>\n");
05899    } else if (format == FORMAT_HTML) {
05900       ast_str_append(&out, 0,
05901       "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
05902       "<html><head>\r\n"
05903       "<title>Asterisk&trade; Manager Interface</title>\r\n"
05904       "</head><body style=\"background-color: #ffffff;\">\r\n"
05905       "<form method=\"POST\">\r\n"
05906       "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
05907       "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
05908       "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
05909       "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
05910    }
05911 
05912    if (s.f != NULL) {   /* have temporary output */
05913       char *buf;
05914       size_t l = ftell(s.f);
05915 
05916       if (l) {
05917          if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s.fd, 0))) {
05918             if (format == FORMAT_XML || format == FORMAT_HTML) {
05919                xml_translate(&out, buf, params, format);
05920             } else {
05921                ast_str_append(&out, 0, "%s", buf);
05922             }
05923             munmap(buf, l);
05924          }
05925       } else if (format == FORMAT_XML || format == FORMAT_HTML) {
05926          xml_translate(&out, "", params, format);
05927       }
05928       fclose(s.f);
05929       s.f = NULL;
05930       s.fd = -1;
05931    }
05932 
05933    if (format == FORMAT_XML) {
05934       ast_str_append(&out, 0, "</ajax-response>\n");
05935    } else if (format == FORMAT_HTML) {
05936       ast_str_append(&out, 0, "</table></form></body></html>\r\n");
05937    }
05938 
05939    ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
05940    http_header = out = NULL;
05941 
05942 auth_callback_out:
05943    ast_mutex_destroy(&s.lock);
05944 
05945    /* Clear resources and unlock manager session */
05946    if (method == AST_HTTP_POST && params) {
05947       ast_variables_destroy(params);
05948    }
05949 
05950    ast_free(http_header);
05951    ast_free(out);
05952 
05953    ao2_lock(session);
05954    if (session->f) {
05955       fclose(session->f);
05956    }
05957    session->f = NULL;
05958    session->fd = -1;
05959    ao2_unlock(session);
05960 
05961    if (session->needdestroy) {
05962       ast_debug(1, "Need destroy, doing it now!\n");
05963       session_destroy(session);
05964    }
05965    ast_string_field_free_memory(&d);
05966    return 0;
05967 
05968 out_401:
05969    if (!nonce) {
05970       nonce = ast_random();
05971    }
05972 
05973    ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
05974    ast_string_field_free_memory(&d);
05975    return 0;
05976 }

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

06038 {
06039    int retval;
06040    struct sockaddr_in ser_remote_address_tmp;
06041 
06042    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06043    retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06044    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06045    return retval;
06046 }

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

06049 {
06050    int retval;
06051    struct sockaddr_in ser_remote_address_tmp;
06052 
06053    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06054    retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06055    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06056    return retval;
06057 }

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

06060 {
06061    int retval;
06062    struct sockaddr_in ser_remote_address_tmp;
06063 
06064    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06065    retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06066    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06067    return retval;
06068 }

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

05076 {
05077    struct mansession_session *session;
05078    struct ao2_iterator i;
05079 
05080    if (ident == 0) {
05081       return NULL;
05082    }
05083 
05084    i = ao2_iterator_init(sessions, 0);
05085    while ((session = ao2_iterator_next(&i))) {
05086       ao2_lock(session);
05087       if (session->managerid == ident && !session->needdestroy) {
05088          ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
05089          break;
05090       }
05091       ao2_unlock(session);
05092       unref_mansession(session);
05093    }
05094    ao2_iterator_destroy(&i);
05095 
05096    return session;
05097 }

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

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

05109 {
05110    struct mansession_session *session;
05111    struct ao2_iterator i;
05112 
05113    if (nonce == 0 || username == NULL || stale == NULL) {
05114       return NULL;
05115    }
05116 
05117    i = ao2_iterator_init(sessions, 0);
05118    while ((session = ao2_iterator_next(&i))) {
05119       ao2_lock(session);
05120       if (!strcasecmp(session->username, username) && session->managerid == nonce) {
05121          *stale = 0;
05122          break;
05123       } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
05124          *stale = 1;
05125          break;
05126       }
05127       ao2_unlock(session);
05128       unref_mansession(session);
05129    }
05130    ao2_iterator_destroy(&i);
05131    return session;
05132 }

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

05435 {
05436    struct mansession s = { .session = NULL, .tcptls_session = ser };
05437    struct mansession_session *session = NULL;
05438    uint32_t ident = 0;
05439    int blastaway = 0;
05440    struct ast_variable *v, *cookies, *params = get_params;
05441    char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
05442    struct ast_str *http_header = NULL, *out = NULL;
05443    struct message m = { 0 };
05444    unsigned int x;
05445    size_t hdrlen;
05446 
05447    if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
05448       ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
05449       return -1;
05450    }
05451 
05452    cookies = ast_http_get_cookies(headers);
05453    for (v = cookies; v; v = v->next) {
05454       if (!strcasecmp(v->name, "mansession_id")) {
05455          sscanf(v->value, "%30x", &ident);
05456          break;
05457       }
05458    }
05459    if (cookies) {
05460       ast_variables_destroy(cookies);
05461    }
05462 
05463    if (!(session = find_session(ident, 1))) {
05464 
05465       /**/
05466       /* Create new session.
05467        * While it is not in the list we don't need any locking
05468        */
05469       if (!(session = build_mansession(*remote_address))) {
05470          ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
05471          return -1;
05472       }
05473       ao2_lock(session);
05474       session->sin = *remote_address;
05475       session->fd = -1;
05476       session->waiting_thread = AST_PTHREADT_NULL;
05477       session->send_events = 0;
05478       session->inuse = 1;
05479       /*!\note There is approximately a 1 in 1.8E19 chance that the following
05480        * calculation will produce 0, which is an invalid ID, but due to the
05481        * properties of the rand() function (and the constantcy of s), that
05482        * won't happen twice in a row.
05483        */
05484       while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
05485       session->last_ev = grab_last();
05486       AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
05487    }
05488    ao2_unlock(session);
05489 
05490    http_header = ast_str_create(128);
05491    out = ast_str_create(2048);
05492 
05493    ast_mutex_init(&s.lock);
05494 
05495    if (http_header == NULL || out == NULL) {
05496       ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
05497       goto generic_callback_out;
05498    }
05499 
05500    s.session = session;
05501    s.fd = mkstemp(template);  /* create a temporary file for command output */
05502    unlink(template);
05503    if (s.fd <= -1) {
05504       ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
05505       goto generic_callback_out;
05506    }
05507    s.f = fdopen(s.fd, "w+");
05508    if (!s.f) {
05509       ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
05510       ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
05511       close(s.fd);
05512       goto generic_callback_out;
05513    }
05514 
05515    if (method == AST_HTTP_POST) {
05516       params = ast_http_get_post_vars(ser, headers);
05517    }
05518 
05519    for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
05520       hdrlen = strlen(v->name) + strlen(v->value) + 3;
05521       m.headers[m.hdrcount] = alloca(hdrlen);
05522       snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
05523       ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
05524       m.hdrcount = x + 1;
05525    }
05526 
05527    if (process_message(&s, &m)) {
05528       if (session->authenticated) {
05529          if (manager_displayconnects(session)) {
05530             ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
05531          }
05532       } else {
05533          if (displayconnects) {
05534             ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
05535          }
05536       }
05537       session->needdestroy = 1;
05538    }
05539 
05540    ast_str_append(&http_header, 0,
05541       "Content-type: text/%s\r\n"
05542       "Cache-Control: no-cache;\r\n"
05543       "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
05544       "Pragma: SuppressEvents\r\n",
05545       contenttype[format],
05546       session->managerid, httptimeout);
05547 
05548    if (format == FORMAT_XML) {
05549       ast_str_append(&out, 0, "<ajax-response>\n");
05550    } else if (format == FORMAT_HTML) {
05551       /*
05552        * When handling AMI-over-HTTP in HTML format, we provide a simple form for
05553        * debugging purposes. This HTML code should not be here, we
05554        * should read from some config file...
05555        */
05556 
05557 #define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
05558 #define TEST_STRING \
05559    "<form action=\"manager\" method=\"post\">\n\
05560    Action: <select name=\"action\">\n\
05561       <option value=\"\">-----&gt;</option>\n\
05562       <option value=\"login\">login</option>\n\
05563       <option value=\"command\">Command</option>\n\
05564       <option value=\"waitevent\">waitevent</option>\n\
05565       <option value=\"listcommands\">listcommands</option>\n\
05566    </select>\n\
05567    or <input name=\"action\"><br/>\n\
05568    CLI Command <input name=\"command\"><br>\n\
05569    user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
05570    <input type=\"submit\">\n</form>\n"
05571 
05572       ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
05573       ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
05574       ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
05575       ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
05576    }
05577 
05578    if (s.f != NULL) {   /* have temporary output */
05579       char *buf;
05580       size_t l;
05581 
05582       if ((l = ftell(s.f))) {
05583          if (MAP_FAILED == (buf = mmap(NULL, l + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, s.fd, 0))) {
05584             ast_log(LOG_WARNING, "mmap failed.  Manager output was not processed\n");
05585          } else {
05586             buf[l] = '\0';
05587             if (format == FORMAT_XML || format == FORMAT_HTML) {
05588                xml_translate(&out, buf, params, format);
05589             } else {
05590                ast_str_append(&out, 0, "%s", buf);
05591             }
05592             munmap(buf, l + 1);
05593          }
05594       } else if (format == FORMAT_XML || format == FORMAT_HTML) {
05595          xml_translate(&out, "", params, format);
05596       }
05597       fclose(s.f);
05598       s.f = NULL;
05599       s.fd = -1;
05600    }
05601 
05602    if (format == FORMAT_XML) {
05603       ast_str_append(&out, 0, "</ajax-response>\n");
05604    } else if (format == FORMAT_HTML) {
05605       ast_str_append(&out, 0, "</table></body>\r\n");
05606    }
05607 
05608    ao2_lock(session);
05609    /* Reset HTTP timeout.  If we're not authenticated, keep it extremely short */
05610    session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
05611 
05612    if (session->needdestroy) {
05613       if (session->inuse == 1) {
05614          ast_debug(1, "Need destroy, doing it now!\n");
05615          blastaway = 1;
05616       } else {
05617          ast_debug(1, "Need destroy, but can't do it yet!\n");
05618          if (session->waiting_thread != AST_PTHREADT_NULL) {
05619             pthread_kill(session->waiting_thread, SIGURG);
05620          }
05621          session->inuse--;
05622       }
05623    } else {
05624       session->inuse--;
05625    }
05626    ao2_unlock(session);
05627 
05628    ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
05629    http_header = out = NULL;
05630 
05631 generic_callback_out:
05632    ast_mutex_destroy(&s.lock);
05633 
05634    /* Clear resource */
05635 
05636    if (method == AST_HTTP_POST && params) {
05637       ast_variables_destroy(params);
05638    }
05639    if (http_header) {
05640       ast_free(http_header);
05641    }
05642    if (out) {
05643       ast_free(out);
05644    }
05645 
05646    if (session && blastaway) {
05647       session_destroy(session);
05648    } else if (session && session->f) {
05649       fclose(session->f);
05650       session->f = NULL;
05651    }
05652 
05653    return 0;
05654 }

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

06133 {
06134    switch (cmd) {
06135    case CLI_INIT:
06136       e->command = "manager show settings";
06137       e->usage =
06138          "Usage: manager show settings\n"
06139          "       Provides detailed list of the configuration of the Manager.\n";
06140       return NULL;
06141    case CLI_GENERATE:
06142       return NULL;
06143    }
06144 #define FORMAT "  %-25.25s  %-15.15s\n"
06145 #define FORMAT2 "  %-25.25s  %-15d\n"
06146    if (a->argc != 3) {
06147       return CLI_SHOWUSAGE;
06148    }
06149    ast_cli(a->fd, "\nGlobal Settings:\n");
06150    ast_cli(a->fd, "----------------\n");
06151    ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
06152    ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
06153    ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
06154    ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
06155    ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
06156    ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
06157    ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
06158    ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
06159    ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
06160    ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
06161    ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
06162    ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
06163    ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
06164    ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
06165    ast_cli(a->fd, FORMAT, "Block sockets:", AST_CLI_YESNO(block_sockets));
06166 #undef FORMAT
06167 #undef FORMAT2
06168 
06169    return CLI_SUCCESS;
06170 }

int init_manager ( void   ) 

Called by Asterisk initialization.

Definition at line 6634 of file manager.c.

References __init_manager().

Referenced by main().

06635 {
06636    return __init_manager(0);
06637 }

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

05979 {
05980    int retval;
05981    struct sockaddr_in ser_remote_address_tmp;
05982 
05983    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
05984    retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
05985    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
05986    return retval;
05987 }

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

05990 {
05991    int retval;
05992    struct sockaddr_in ser_remote_address_tmp;
05993 
05994    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
05995    retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
05996    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
05997    return retval;
05998 }

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

References purge_events(), and purge_sessions().

06104 {
06105    purge_sessions(1);
06106    purge_events();
06107 }

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

06001 {
06002    int retval;
06003    struct sockaddr_in ser_remote_address_tmp;
06004 
06005    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06006    retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06007    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06008    return retval;
06009 }

int reload_manager ( void   ) 

Called by Asterisk module functions and the CLI command.

Definition at line 6639 of file manager.c.

References __init_manager().

Referenced by handle_manager_reload().

06640 {
06641    return __init_manager(1);
06642 }

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

Definition at line 5276 of file manager.c.

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

05277 {
05278    /* Due to the simplicity of struct variable_count, it makes no difference
05279     * if you pass in objects or strings, the same operation applies. This is
05280     * due to the fact that the hash occurs on the first element, which means
05281     * the address of both the struct and the string are exactly the same. */
05282    struct variable_count *vc = obj;
05283    char *str = vstr;
05284    return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
05285 }

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

Definition at line 5269 of file manager.c.

References ast_str_hash(), and variable_count::varname.

05270 {
05271    const struct variable_count *vc = vvc;
05272 
05273    return ast_str_hash(vc->varname);
05274 }

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

Definition at line 5207 of file manager.c.

References ast_str_append().

05208 {
05209    /* store in a local buffer to avoid calling ast_str_append too often */
05210    char buf[256];
05211    char *dst = buf;
05212    int space = sizeof(buf);
05213    /* repeat until done and nothing to flush */
05214    for ( ; *src || dst != buf ; src++) {
05215       if (*src == '\0' || space < 10) {   /* flush */
05216          *dst++ = '\0';
05217          ast_str_append(out, 0, "%s", buf);
05218          dst = buf;
05219          space = sizeof(buf);
05220          if (*src == '\0') {
05221             break;
05222          }
05223       }
05224 
05225       if ( (mode & 2) && !isalnum(*src)) {
05226          *dst++ = '_';
05227          space--;
05228          continue;
05229       }
05230       switch (*src) {
05231       case '<':
05232          strcpy(dst, "&lt;");
05233          dst += 4;
05234          space -= 4;
05235          break;
05236       case '>':
05237          strcpy(dst, "&gt;");
05238          dst += 4;
05239          space -= 4;
05240          break;
05241       case '\"':
05242          strcpy(dst, "&quot;");
05243          dst += 6;
05244          space -= 6;
05245          break;
05246       case '\'':
05247          strcpy(dst, "&apos;");
05248          dst += 6;
05249          space -= 6;
05250          break;
05251       case '&':
05252          strcpy(dst, "&amp;");
05253          dst += 5;
05254          space -= 5;
05255          break;
05256 
05257       default:
05258          *dst++ = mode ? tolower(*src) : *src;
05259          space--;
05260       }
05261    }
05262 }

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

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

05316 {
05317    struct ast_variable *v;
05318    const char *dest = NULL;
05319    char *var, *val;
05320    const char *objtype = NULL;
05321    int in_data = 0;  /* parsing data */
05322    int inobj = 0;
05323    int xml = (format == FORMAT_XML);
05324    struct variable_count *vc = NULL;
05325    struct ao2_container *vco = NULL;
05326 
05327    if (xml) {
05328       /* dest and objtype need only for XML format */
05329       for (v = get_vars; v; v = v->next) {
05330          if (!strcasecmp(v->name, "ajaxdest")) {
05331             dest = v->value;
05332          } else if (!strcasecmp(v->name, "ajaxobjtype")) {
05333             objtype = v->value;
05334          }
05335       }
05336       if (ast_strlen_zero(dest)) {
05337          dest = "unknown";
05338       }
05339       if (ast_strlen_zero(objtype)) {
05340          objtype = "generic";
05341       }
05342    }
05343 
05344    /* we want to stop when we find an empty line */
05345    while (in && *in) {
05346       val = strsep(&in, "\r\n"); /* mark start and end of line */
05347       if (in && *in == '\n') {   /* remove trailing \n if any */
05348          in++;
05349       }
05350       ast_trim_blanks(val);
05351       ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
05352       if (ast_strlen_zero(val)) {
05353          /* empty line */
05354          if (in_data) {
05355             /* close data in Opaque mode */
05356             ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05357             in_data = 0;
05358          }
05359 
05360          if (inobj) {
05361             /* close block */
05362             ast_str_append(out, 0, xml ? " /></response>\n" :
05363                "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05364             inobj = 0;
05365             ao2_ref(vco, -1);
05366             vco = NULL;
05367          }
05368          continue;
05369       }
05370 
05371       if (!inobj) {
05372          /* start new block */
05373          if (xml) {
05374             ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
05375          }
05376          vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
05377          inobj = 1;
05378       }
05379 
05380       if (in_data) {
05381          /* Process data field in Opaque mode */
05382          xml_copy_escape(out, val, 0);   /* data field */
05383          ast_str_append(out, 0, xml ? "\n" : "<br>\n");
05384          continue;
05385       }
05386 
05387       /* We expect "Name: value" line here */
05388       var = strsep(&val, ":");
05389       if (val) {
05390          /* found the field name */
05391          val = ast_skip_blanks(val);
05392          ast_trim_blanks(var);
05393       } else {
05394          /* field name not found, switch to opaque mode */
05395          val = var;
05396          var = "Opaque-data";
05397          in_data = 1;
05398       }
05399 
05400 
05401       ast_str_append(out, 0, xml ? " " : "<tr><td>");
05402       if ((vc = ao2_find(vco, var, 0))) {
05403          vc->count++;
05404       } else {
05405          /* Create a new entry for this one */
05406          vc = ao2_alloc(sizeof(*vc), NULL);
05407          vc->varname = var;
05408          vc->count = 1;
05409          ao2_link(vco, vc);
05410       }
05411 
05412       xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
05413       if (vc->count > 1) {
05414          ast_str_append(out, 0, "-%d", vc->count);
05415       }
05416       ao2_ref(vc, -1);
05417       ast_str_append(out, 0, xml ? "='" : "</td><td>");
05418       xml_copy_escape(out, val, 0); /* data field */
05419       ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05420    }
05421 
05422    if (inobj) {
05423       ast_str_append(out, 0, xml ? " /></response>\n" :
05424          "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05425       ao2_ref(vco, -1);
05426    }
05427 }


Variable Documentation

struct ast_http_uri amanageruri [static]

Definition at line 6079 of file manager.c.

struct ast_http_uri amanagerxmluri [static]

Definition at line 6088 of file manager.c.

struct ast_tcptls_session_args ami_desc [static]

Definition at line 6110 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_tls_config ami_tls_cfg [static]

Definition at line 6109 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_tcptls_session_args amis_desc [static]

Definition at line 6121 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_http_uri arawmanuri [static]

Definition at line 6070 of file manager.c.

struct ast_cli_entry cli_manager[] [static]

Definition at line 6172 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 5064 of file manager.c.

struct ast_http_uri manageruri [static]

Definition at line 6019 of file manager.c.

struct ast_http_uri managerxmluri [static]

Definition at line 6027 of file manager.c.

struct ast_http_uri rawmanuri [static]

Definition at line 6011 of file manager.c.

int registered = 0 [static]

Definition at line 6097 of file manager.c.

int webregged = 0 [static]

Definition at line 6098 of file manager.c.

const char* words[AST_MAX_CMD_LEN]

Definition at line 897 of file manager.c.

Referenced by check_blacklist().


Generated on Mon Jun 27 16:51:16 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7