Mon Oct 8 12:39:24 2012

Asterisk developer's documentation


manager.c File Reference

The Asterisk Management Interface - AMI. More...

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

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

enum  error_type {
  UNKNOWN_ACTION = 1, UNKNOWN_CATEGORY, UNSPECIFIED_CATEGORY, UNSPECIFIED_ARGUMENT,
  FAILURE_ALLOCATION, FAILURE_NEWCAT, FAILURE_DELCAT, FAILURE_EMPTYCAT,
  FAILURE_UPDATE, FAILURE_DELETE, FAILURE_APPEND
}
enum  output_format { FORMAT_RAW, FORMAT_HTML, FORMAT_XML }

Functions

int __ast_manager_event_multichan (int category, const char *event, int chancount, struct ast_channel **chans, const char *file, int line, const char *func, const char *fmt,...)
static const char * __astman_get_header (const struct message *m, char *var, int mode)
 Return a matching header value.
static void __init_astman_append_buf (void)
 thread local buffer for astman_append
static int __init_manager (int reload)
static void __init_manager_event_buf (void)
static void __init_manager_event_funcbuf (void)
static void __init_userevent_buf (void)
static int action_aocmessage (struct mansession *s, const struct message *m)
static int action_atxfer (struct mansession *s, const struct message *m)
static int action_challenge (struct mansession *s, const struct message *m)
static int action_command (struct mansession *s, const struct message *m)
 Manager command "command" - execute CLI command.
static int action_coresettings (struct mansession *s, const struct message *m)
 Show PBX core settings information.
static int action_coreshowchannels (struct mansession *s, const struct message *m)
 Manager command "CoreShowChannels" - List currently defined channels and some information about them.
static int action_corestatus (struct mansession *s, const struct message *m)
 Show PBX core status information.
static int action_createconfig (struct mansession *s, const struct message *m)
static void action_destroy (void *obj)
static int action_events (struct mansession *s, const struct message *m)
static int action_extensionstate (struct mansession *s, const struct message *m)
static struct manager_actionaction_find (const char *name)
static int action_getconfig (struct mansession *s, const struct message *m)
static int action_getconfigjson (struct mansession *s, const struct message *m)
static int action_getvar (struct mansession *s, const struct message *m)
static int action_hangup (struct mansession *s, const struct message *m)
static int action_listcategories (struct mansession *s, const struct message *m)
static int action_listcommands (struct mansession *s, const struct message *m)
static int action_login (struct mansession *s, const struct message *m)
static int action_logoff (struct mansession *s, const struct message *m)
static int action_mailboxcount (struct mansession *s, const struct message *m)
static int action_mailboxstatus (struct mansession *s, const struct message *m)
static int action_originate (struct mansession *s, const struct message *m)
static int action_ping (struct mansession *s, const struct message *m)
static int action_redirect (struct mansession *s, const struct message *m)
 action_redirect: The redirect manager command
static int action_reload (struct mansession *s, const struct message *m)
 Send a reload event.
static int action_sendtext (struct mansession *s, const struct message *m)
static int action_setvar (struct mansession *s, const struct message *m)
static int action_status (struct mansession *s, const struct message *m)
 Manager "status" command to show channels.
static int action_timeout (struct mansession *s, const struct message *m)
static int action_updateconfig (struct mansession *s, const struct message *m)
static int action_userevent (struct mansession *s, const struct message *m)
static int action_waitevent (struct mansession *s, const struct message *m)
static struct eventqentadvance_event (struct eventqent *e)
static int aocmessage_get_unit_entry (const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
static void append_channel_vars (struct ast_str **pbuf, struct ast_channel *chan)
static int append_event (const char *str, int category)
int ast_hook_send_action (struct manager_custom_hook *hook, const char *msg)
 Registered hooks can call this function to invoke actions and they will receive responses through registered callback.
static int ast_instring (const char *bigstr, const char *smallstr, const char delim)
int ast_manager_register2 (const char *action, int auth, int(*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
 Register a manager command with the manager interface.
void ast_manager_register_hook (struct manager_custom_hook *hook)
 Add a custom hook to be called when an event is fired.
static int ast_manager_register_struct (struct manager_action *act)
int ast_manager_unregister (char *action)
 Unregister a registered manager command.
void ast_manager_unregister_hook (struct manager_custom_hook *hook)
 Delete a custom hook to be called when an event is fired.
void astman_append (struct mansession *s, const char *fmt,...)
static void astman_append_json (struct mansession *s, const char *str)
int astman_datastore_add (struct mansession *s, struct ast_datastore *datastore)
 Add a datastore to a session.
ast_datastoreastman_datastore_find (struct mansession *s, const struct ast_datastore_info *info, const char *uid)
 Find a datastore on a session.
int astman_datastore_remove (struct mansession *s, struct ast_datastore *datastore)
 Remove a datastore from a session.
const char * astman_get_header (const struct message *m, char *var)
 Get header from mananger transaction.
ast_variableastman_get_variables (const struct message *m)
 Get a linked list of the Variable: headers.
int astman_is_authed (uint32_t ident)
 Determinie if a manager session ident is authenticated.
void astman_send_ack (struct mansession *s, const struct message *m, char *msg)
 Send ack in manager transaction.
void astman_send_error (struct mansession *s, const struct message *m, char *error)
 Send error in manager transaction.
void astman_send_listack (struct mansession *s, const struct message *m, char *msg, char *listflag)
 Send ack in manager list transaction.
void astman_send_response (struct mansession *s, const struct message *m, char *resp, char *msg)
 Send response in manager transaction.
static void astman_send_response_full (struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
static void astman_start_ack (struct mansession *s, const struct message *m)
int astman_verify_session_readpermissions (uint32_t ident, int perm)
 Verify a session's read permissions against a permission mask.
int astman_verify_session_writepermissions (uint32_t ident, int perm)
 Verify a session's write permissions against a permission mask.
static int auth_http_callback (struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, struct sockaddr_in *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_manager_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_mxml_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int auth_rawman_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int authenticate (struct mansession *s, const struct message *m)
static const char * authority_to_str (int authority, struct ast_str **res)
 Convert authority code to a list of options.
static int blackfilter_cmp_fn (void *obj, void *arg, void *data, int flags)
static struct mansession_sessionbuild_mansession (struct sockaddr_in sin)
 Allocate manager session structure and add it to the list of sessions.
static int check_blacklist (const char *cmd)
int check_manager_enabled (void)
 Check if AMI is enabled.
static int check_manager_session_inuse (const char *name)
int check_webmanager_enabled (void)
 Check if AMI/HTTP is enabled.
static void destroy_fast_originate_helper (struct fast_originate_helper *doomed)
static int do_message (struct mansession *s)
static void event_filter_destructor (void *obj)
static void * fast_originate (void *data)
static struct mansession_sessionfind_session (uint32_t ident, int incinuse)
static struct mansession_sessionfind_session_by_nonce (const char *username, unsigned long nonce, int *stale)
static void free_channelvars (void)
static int function_capable_string_allowed_with_auths (const char *evaluating, int writepermlist)
 Checks to see if a string which can be used to evaluate functions should be rejected.
static int generic_http_callback (struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, struct sockaddr_in *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
static int get_input (struct mansession *s, char *output)
static struct ast_manager_userget_manager_by_name_locked (const char *name)
static int get_perm (const char *instr)
static struct eventqentgrab_last (void)
static char * handle_manager_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager reload.
static char * handle_manager_show_settings (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager show settings.
static char * handle_mandebug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmanager (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmanagers (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmancmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmancmds (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list commands.
static char * handle_showmanconn (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list connected.
static char * handle_showmaneventq (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list eventq.
static enum error_type handle_updates (struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
int init_manager (void)
 Called by Asterisk initialization.
static void json_escape (char *out, const char *in)
static void load_channelvars (struct ast_variable *var)
static struct ast_variableman_do_variable_value (struct ast_variable *head, const char *hdr_val)
static int manager_displayconnects (struct mansession_session *session)
 Get displayconnects config option.
static int manager_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int manager_modulecheck (struct mansession *s, const struct message *m)
static int manager_moduleload (struct mansession *s, const struct message *m)
static int manager_state_cb (char *context, char *exten, int state, void *data)
static int mansession_cmp_fn (void *obj, void *arg, int flags)
static struct sockaddr_in * mansession_encode_sin_local (const struct mansession *s, struct sockaddr_in *sin_local)
static enum ast_security_event_transport_type mansession_get_transport (const struct mansession *s)
static void mansession_lock (struct mansession *s)
 Lock the 'mansession' structure.
static void mansession_unlock (struct mansession *s)
 Unlock the 'mansession' structure.
static int match_filter (struct mansession *s, char *eventdata)
static int mxml_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
static int process_events (struct mansession *s)
static int process_message (struct mansession *s, const struct message *m)
static void process_output (struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
static void purge_events (void)
static void purge_old_stuff (void *data)
 cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most
static void purge_sessions (int n_max)
 remove at most n_max stale session from the list.
static int rawman_http_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
int reload_manager (void)
 Called by Asterisk module functions and the CLI command.
static void report_auth_success (const struct mansession *s)
static void report_failed_acl (const struct mansession *s, const char *username)
static void report_failed_challenge_response (const struct mansession *s, const char *response, const char *expected_response)
static void report_inval_password (const struct mansession *s, const char *username)
static void report_invalid_user (const struct mansession *s, const char *username)
static void report_req_bad_format (const struct mansession *s, const char *action)
static void report_req_not_allowed (const struct mansession *s, const char *action)
static void report_session_limit (const struct mansession *s)
static int send_string (struct mansession *s, char *string)
static void session_destroy (struct mansession_session *s)
static void session_destructor (void *obj)
static void * session_do (void *data)
 The body of the individual manager session. Call get_input() to read one line at a time (or be woken up on new events), collect the lines in a message until found an empty line, and execute the request. In any case, deliver events asynchronously through process_events() (called from here if no line is available, or at the end of process_message(). ).
static int set_eventmask (struct mansession *s, const char *eventmask)
 Rather than braindead on,off this now can also accept a specific int mask value or a ',' delim list of mask strings (the same as manager.conf) -anthm.
static int strings_to_mask (const char *string)
static struct mansession_sessionunref_mansession (struct mansession_session *s)
 Unreference manager session object. If no more references, then go ahead and delete it.
static int variable_count_cmp_fn (void *obj, void *vstr, int flags)
static int variable_count_hash_fn (const void *vvc, const int flags)
static int whitefilter_cmp_fn (void *obj, void *arg, void *data, int flags)
static void xml_copy_escape (struct ast_str **out, const char *src, int mode)
static void xml_translate (struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
 Convert the input into XML or HTML. The input is supposed to be a sequence of lines of the form Name: value optionally followed by a blob of unformatted text. A blank line is a section separator. Basically, this is a mixture of the format of Manager Interface and CLI commands. The unformatted text is considered as a single value of a field named 'Opaque-data'.

Variables

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


Detailed Description

The Asterisk Management Interface - AMI.

Author:
Mark Spencer <markster@digium.com>
ExtRef:
OpenSSL http://www.openssl.org - for AMI/SSL
At the moment this file contains a number of functions, namely:

manager.conf

Definition in file manager.c.


Define Documentation

#define FORMAT   " %-25.25s %-15.15s\n"

#define FORMAT2   " %-25.25s %-15d\n"

#define HSMC_FORMAT   " %-15.15s %-15.15s %-55.55s\n"

Referenced by handle_showmancmds().

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

Referenced by handle_showmanconn().

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

Referenced by handle_showmanconn().

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

#define TEST_STRING   "<form action=\"manager\" method=\"post\">\n\ Action: <select name=\"action\">\n\ <option value=\"\">-----&gt;</option>\n\ <option value=\"login\">login</option>\n\ <option value=\"command\">Command</option>\n\ <option value=\"waitevent\">waitevent</option>\n\ <option value=\"listcommands\">listcommands</option>\n\ </select>\n\ or <input name=\"action\"><br/>\n\ CLI Command <input name=\"command\"><br>\n\ user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\ <input type=\"submit\">\n</form>\n"


Enumeration Type Documentation

enum output_format

END Doxygen group

Enumerator:
FORMAT_RAW 
FORMAT_HTML 
FORMAT_XML 

Definition at line 5387 of file manager.c.

05387                    {
05388    FORMAT_RAW,
05389    FORMAT_HTML,
05390    FORMAT_XML,
05391 };


Function Documentation

static int __init_manager ( int  reload  )  [static]

Definition at line 6575 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_sockaddr_setnull(), 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_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_AUTHLIMIT, DEFAULT_AUTHTIMEOUT, DEFAULT_BLOCKSOCKETS, DEFAULT_BROKENEVENTSACTION, DEFAULT_DISPLAYCONNECTS, DEFAULT_ENABLED, DEFAULT_HTTPTIMEOUT, DEFAULT_MANAGER_PORT, DEFAULT_MANAGERDEBUG, DEFAULT_REALM, DEFAULT_TIMESTAMPEVENTS, DEFAULT_WEBENABLED, displayconnects, ast_tls_config::enabled, EVENT_FLAG_AOC, EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, EVENT_FLAG_CONFIG, EVENT_FLAG_ORIGINATE, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, free_channelvars(), global_realm, httptimeout, ast_tcptls_session_args::local_address, LOG_NOTICE, manager_debug, manager_enabled, manager_modulecheck(), manager_moduleload(), manager_state_cb(), ast_tls_config::pvtfile, S_OR, timestampevents, var, and webmanager_enabled.

Referenced by init_manager(), and reload_manager().

06576 {
06577    struct ast_config *ucfg = NULL, *cfg = NULL;
06578    const char *val;
06579    char *cat = NULL;
06580    int newhttptimeout = DEFAULT_HTTPTIMEOUT;
06581    struct ast_manager_user *user = NULL;
06582    struct ast_variable *var;
06583    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06584    char a1[256];
06585    char a1_hash[256];
06586    struct sockaddr_in ami_desc_local_address_tmp = { 0, };
06587    struct sockaddr_in amis_desc_local_address_tmp = { 0, };
06588    int tls_was_enabled = 0;
06589 
06590    if (!registered) {
06591       /* Register default actions */
06592       ast_manager_register_xml("Ping", 0, action_ping);
06593       ast_manager_register_xml("Events", 0, action_events);
06594       ast_manager_register_xml("Logoff", 0, action_logoff);
06595       ast_manager_register_xml("Login", 0, action_login);
06596       ast_manager_register_xml("Challenge", 0, action_challenge);
06597       ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
06598       ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
06599       ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar);
06600       ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
06601       ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
06602       ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
06603       ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
06604       ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
06605       ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
06606       ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect);
06607       ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer);
06608       ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate);
06609       ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command);
06610       ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
06611       ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
06612       ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
06613       ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
06614       ast_manager_register_xml("ListCommands", 0, action_listcommands);
06615       ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext);
06616       ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent);
06617       ast_manager_register_xml("WaitEvent", 0, action_waitevent);
06618       ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
06619       ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
06620       ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
06621       ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
06622       ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
06623       ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
06624       ast_manager_register_xml("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
06625 
06626       ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
06627       ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
06628       registered = 1;
06629       /* Append placeholder event so master_eventq never runs dry */
06630       append_event("Event: Placeholder\r\n\r\n", 0);
06631    }
06632    if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
06633       return 0;
06634    }
06635 
06636    manager_enabled = DEFAULT_ENABLED;
06637    webmanager_enabled = DEFAULT_WEBENABLED;
06638    manager_debug = DEFAULT_MANAGERDEBUG;
06639    displayconnects = DEFAULT_DISPLAYCONNECTS;
06640    broken_events_action = DEFAULT_BROKENEVENTSACTION;
06641    block_sockets = DEFAULT_BLOCKSOCKETS;
06642    timestampevents = DEFAULT_TIMESTAMPEVENTS;
06643    httptimeout = DEFAULT_HTTPTIMEOUT;
06644    authtimeout = DEFAULT_AUTHTIMEOUT;
06645    authlimit = DEFAULT_AUTHLIMIT;
06646 
06647    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
06648       ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled.\n");
06649       return 0;
06650    }
06651 
06652    /* default values */
06653    ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm));
06654    ast_sockaddr_setnull(&ami_desc.local_address);
06655    ast_sockaddr_setnull(&amis_desc.local_address);
06656 
06657    ami_desc_local_address_tmp.sin_family = AF_INET;
06658    amis_desc_local_address_tmp.sin_family = AF_INET;
06659 
06660    ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT);
06661 
06662    tls_was_enabled = (reload && ami_tls_cfg.enabled);
06663 
06664    ami_tls_cfg.enabled = 0;
06665    if (ami_tls_cfg.certfile) {
06666       ast_free(ami_tls_cfg.certfile);
06667    }
06668    ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
06669    if (ami_tls_cfg.pvtfile) {
06670       ast_free(ami_tls_cfg.pvtfile);
06671    }
06672    ami_tls_cfg.pvtfile = ast_strdup("");
06673    if (ami_tls_cfg.cipher) {
06674       ast_free(ami_tls_cfg.cipher);
06675    }
06676    ami_tls_cfg.cipher = ast_strdup("");
06677 
06678    free_channelvars();
06679 
06680    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
06681       val = var->value;
06682 
06683       if (!ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
06684          continue;
06685       }
06686 
06687       if (!strcasecmp(var->name, "enabled")) {
06688          manager_enabled = ast_true(val);
06689       } else if (!strcasecmp(var->name, "block-sockets")) {
06690          block_sockets = ast_true(val);
06691       } else if (!strcasecmp(var->name, "webenabled")) {
06692          webmanager_enabled = ast_true(val);
06693       } else if (!strcasecmp(var->name, "port")) {
06694          ami_desc_local_address_tmp.sin_port = htons(atoi(val));
06695       } else if (!strcasecmp(var->name, "bindaddr")) {
06696          if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) {
06697             ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
06698             memset(&ami_desc_local_address_tmp.sin_addr, 0,
06699                    sizeof(ami_desc_local_address_tmp.sin_addr));
06700          }
06701       } else if (!strcasecmp(var->name, "brokeneventsaction")) {
06702          broken_events_action = ast_true(val);
06703       } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
06704          allowmultiplelogin = ast_true(val);
06705       } else if (!strcasecmp(var->name, "displayconnects")) {
06706          displayconnects = ast_true(val);
06707       } else if (!strcasecmp(var->name, "timestampevents")) {
06708          timestampevents = ast_true(val);
06709       } else if (!strcasecmp(var->name, "debug")) {
06710          manager_debug = ast_true(val);
06711       } else if (!strcasecmp(var->name, "httptimeout")) {
06712          newhttptimeout = atoi(val);
06713       } else if (!strcasecmp(var->name, "authtimeout")) {
06714          int timeout = atoi(var->value);
06715 
06716          if (timeout < 1) {
06717             ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
06718          } else {
06719             authtimeout = timeout;
06720          }
06721       } else if (!strcasecmp(var->name, "authlimit")) {
06722          int limit = atoi(var->value);
06723 
06724          if (limit < 1) {
06725             ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
06726          } else {
06727             authlimit = limit;
06728          }
06729       } else if (!strcasecmp(var->name, "channelvars")) {
06730          load_channelvars(var);
06731       } else {
06732          ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
06733             var->name, val);
06734       }
06735    }
06736 
06737    ast_sockaddr_to_sin(&amis_desc.local_address, &amis_desc_local_address_tmp);
06738 
06739    /* if the amis address has not been set, default is the same as non secure ami */
06740    if (!amis_desc_local_address_tmp.sin_addr.s_addr) {
06741       amis_desc_local_address_tmp.sin_addr =
06742           ami_desc_local_address_tmp.sin_addr;
06743    }
06744 
06745    if (!amis_desc_local_address_tmp.sin_port) {
06746       amis_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_TLS_PORT);
06747    }
06748 
06749    if (manager_enabled) {
06750       ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp);
06751       ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp);
06752    }
06753 
06754    AST_RWLIST_WRLOCK(&users);
06755 
06756    /* First, get users from users.conf */
06757    ucfg = ast_config_load2("users.conf", "manager", config_flags);
06758    if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
06759       const char *hasmanager;
06760       int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
06761 
06762       while ((cat = ast_category_browse(ucfg, cat))) {
06763          if (!strcasecmp(cat, "general")) {
06764             continue;
06765          }
06766 
06767          hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
06768          if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
06769             const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
06770             const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
06771             const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
06772             const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
06773             const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
06774 
06775             /* Look for an existing entry,
06776              * if none found - create one and add it to the list
06777              */
06778             if (!(user = get_manager_by_name_locked(cat))) {
06779                if (!(user = ast_calloc(1, sizeof(*user)))) {
06780                   break;
06781                }
06782 
06783                /* Copy name over */
06784                ast_copy_string(user->username, cat, sizeof(user->username));
06785                /* Insert into list */
06786                AST_LIST_INSERT_TAIL(&users, user, list);
06787                user->ha = NULL;
06788                user->keep = 1;
06789                user->readperm = -1;
06790                user->writeperm = -1;
06791                /* Default displayconnect from [general] */
06792                user->displayconnects = displayconnects;
06793                user->writetimeout = 100;
06794             }
06795 
06796             if (!user_secret) {
06797                user_secret = ast_variable_retrieve(ucfg, "general", "secret");
06798             }
06799             if (!user_read) {
06800                user_read = ast_variable_retrieve(ucfg, "general", "read");
06801             }
06802             if (!user_write) {
06803                user_write = ast_variable_retrieve(ucfg, "general", "write");
06804             }
06805             if (!user_displayconnects) {
06806                user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
06807             }
06808             if (!user_writetimeout) {
06809                user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
06810             }
06811 
06812             if (!ast_strlen_zero(user_secret)) {
06813                if (user->secret) {
06814                   ast_free(user->secret);
06815                }
06816                user->secret = ast_strdup(user_secret);
06817             }
06818 
06819             if (user_read) {
06820                user->readperm = get_perm(user_read);
06821             }
06822             if (user_write) {
06823                user->writeperm = get_perm(user_write);
06824             }
06825             if (user_displayconnects) {
06826                user->displayconnects = ast_true(user_displayconnects);
06827             }
06828             if (user_writetimeout) {
06829                int value = atoi(user_writetimeout);
06830                if (value < 100) {
06831                   ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value);
06832                } else {
06833                   user->writetimeout = value;
06834                }
06835             }
06836          }
06837       }
06838       ast_config_destroy(ucfg);
06839    }
06840 
06841    /* cat is NULL here in any case */
06842 
06843    while ((cat = ast_category_browse(cfg, cat))) {
06844       struct ast_ha *oldha;
06845 
06846       if (!strcasecmp(cat, "general")) {
06847          continue;
06848       }
06849 
06850       /* Look for an existing entry, if none found - create one and add it to the list */
06851       if (!(user = get_manager_by_name_locked(cat))) {
06852          if (!(user = ast_calloc(1, sizeof(*user)))) {
06853             break;
06854          }
06855          /* Copy name over */
06856          ast_copy_string(user->username, cat, sizeof(user->username));
06857 
06858          user->ha = NULL;
06859          user->readperm = 0;
06860          user->writeperm = 0;
06861          /* Default displayconnect from [general] */
06862          user->displayconnects = displayconnects;
06863          user->writetimeout = 100;
06864          user->whitefilters = ao2_container_alloc(1, NULL, NULL);
06865          user->blackfilters = ao2_container_alloc(1, NULL, NULL);
06866 
06867          /* Insert into list */
06868          AST_RWLIST_INSERT_TAIL(&users, user, list);
06869       } else {
06870          ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
06871          ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
06872       }
06873 
06874       /* Make sure we keep this user and don't destroy it during cleanup */
06875       user->keep = 1;
06876       oldha = user->ha;
06877       user->ha = NULL;
06878 
06879       var = ast_variable_browse(cfg, cat);
06880       for (; var; var = var->next) {
06881          if (!strcasecmp(var->name, "secret")) {
06882             if (user->secret) {
06883                ast_free(user->secret);
06884             }
06885             user->secret = ast_strdup(var->value);
06886          } else if (!strcasecmp(var->name, "deny") ||
06887                    !strcasecmp(var->name, "permit")) {
06888             user->ha = ast_append_ha(var->name, var->value, user->ha, NULL);
06889          }  else if (!strcasecmp(var->name, "read") ) {
06890             user->readperm = get_perm(var->value);
06891          }  else if (!strcasecmp(var->name, "write") ) {
06892             user->writeperm = get_perm(var->value);
06893          }  else if (!strcasecmp(var->name, "displayconnects") ) {
06894             user->displayconnects = ast_true(var->value);
06895          } else if (!strcasecmp(var->name, "writetimeout")) {
06896             int value = atoi(var->value);
06897             if (value < 100) {
06898                ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
06899             } else {
06900                user->writetimeout = value;
06901             }
06902          } else if (!strcasecmp(var->name, "eventfilter")) {
06903             const char *value = var->value;
06904             regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
06905             if (new_filter) {
06906                int is_blackfilter;
06907                if (value[0] == '!') {
06908                   is_blackfilter = 1;
06909                   value++;
06910                } else {
06911                   is_blackfilter = 0;
06912                }
06913                if (regcomp(new_filter, value, 0)) {
06914                   ao2_t_ref(new_filter, -1, "failed to make regx");
06915                } else {
06916                   if (is_blackfilter) {
06917                      ao2_t_link(user->blackfilters, new_filter, "link new filter into black user container");
06918                   } else {
06919                      ao2_t_link(user->whitefilters, new_filter, "link new filter into white user container");
06920                   }
06921                }
06922             }
06923          } else {
06924             ast_debug(1, "%s is an unknown option.\n", var->name);
06925          }
06926       }
06927       ast_free_ha(oldha);
06928    }
06929    ast_config_destroy(cfg);
06930 
06931    /* Perform cleanup - essentially prune out old users that no longer exist */
06932    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
06933       if (user->keep) { /* valid record. clear flag for the next round */
06934          user->keep = 0;
06935 
06936          /* Calculate A1 for Digest auth */
06937          snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
06938          ast_md5_hash(a1_hash,a1);
06939          if (user->a1_hash) {
06940             ast_free(user->a1_hash);
06941          }
06942          user->a1_hash = ast_strdup(a1_hash);
06943          continue;
06944       }
06945       /* We do not need to keep this user so take them out of the list */
06946       AST_RWLIST_REMOVE_CURRENT(list);
06947       ast_debug(4, "Pruning user '%s'\n", user->username);
06948       /* Free their memory now */
06949       if (user->a1_hash) {
06950          ast_free(user->a1_hash);
06951       }
06952       if (user->secret) {
06953          ast_free(user->secret);
06954       }
06955       ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
06956       ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
06957       ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
06958       ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
06959       ast_free_ha(user->ha);
06960       ast_free(user);
06961    }
06962    AST_RWLIST_TRAVERSE_SAFE_END;
06963 
06964    AST_RWLIST_UNLOCK(&users);
06965 
06966    if (!reload) {
06967       /* If you have a NULL hash fn, you only need a single bucket */
06968       sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn);
06969    }
06970 
06971    if (webmanager_enabled && manager_enabled) {
06972       if (!webregged) {
06973 
06974          ast_http_uri_link(&rawmanuri);
06975          ast_http_uri_link(&manageruri);
06976          ast_http_uri_link(&managerxmluri);
06977 
06978          ast_http_uri_link(&arawmanuri);
06979          ast_http_uri_link(&amanageruri);
06980          ast_http_uri_link(&amanagerxmluri);
06981          webregged = 1;
06982       }
06983    } else {
06984       if (webregged) {
06985          ast_http_uri_unlink(&rawmanuri);
06986          ast_http_uri_unlink(&manageruri);
06987          ast_http_uri_unlink(&managerxmluri);
06988 
06989          ast_http_uri_unlink(&arawmanuri);
06990          ast_http_uri_unlink(&amanageruri);
06991          ast_http_uri_unlink(&amanagerxmluri);
06992          webregged = 0;
06993       }
06994    }
06995 
06996    if (newhttptimeout > 0) {
06997       httptimeout = newhttptimeout;
06998    }
06999 
07000    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled");
07001 
07002    ast_tcptls_server_start(&ami_desc);
07003    if (tls_was_enabled && !ami_tls_cfg.enabled) {
07004       ast_tcptls_server_stop(&amis_desc);
07005    } else if (ast_ssl_setup(amis_desc.tls_cfg)) {
07006       ast_tcptls_server_start(&amis_desc);
07007    }
07008    return 0;
07009 }

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

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

07033 {
07034    AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
07035 
07036    return 0;
07037 }

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

07045 {
07046    struct ast_datastore *datastore = NULL;
07047 
07048    if (info == NULL)
07049       return NULL;
07050 
07051    AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
07052       if (datastore->info != info) {
07053          continue;
07054       }
07055 
07056       if (uid == NULL) {
07057          /* matched by type only */
07058          break;
07059       }
07060 
07061       if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
07062          /* Matched by type AND uid */
07063          break;
07064       }
07065    }
07066    AST_LIST_TRAVERSE_SAFE_END;
07067 
07068    return datastore;
07069 }

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

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

07040 {
07041    return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
07042 }

int astman_is_authed ( uint32_t  ident  ) 

Determinie if a manager session ident is authenticated.

Definition at line 5463 of file manager.c.

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

Referenced by http_post_callback(), and static_callback().

05464 {
05465    int authed;
05466    struct mansession_session *session;
05467 
05468    if (!(session = find_session(ident, 0)))
05469       return 0;
05470 
05471    authed = (session->authenticated != 0);
05472 
05473    ao2_unlock(session);
05474    unref_mansession(session);
05475 
05476    return authed;
05477 }

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

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

05480 {
05481    int result = 0;
05482    struct mansession_session *session;
05483    struct ao2_iterator i;
05484 
05485    if (ident == 0) {
05486       return 0;
05487    }
05488 
05489    i = ao2_iterator_init(sessions, 0);
05490    while ((session = ao2_iterator_next(&i))) {
05491       ao2_lock(session);
05492       if ((session->managerid == ident) && (session->readperm & perm)) {
05493          result = 1;
05494          ao2_unlock(session);
05495          unref_mansession(session);
05496          break;
05497       }
05498       ao2_unlock(session);
05499       unref_mansession(session);
05500    }
05501    ao2_iterator_destroy(&i);
05502    return result;
05503 }

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

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

05506 {
05507    int result = 0;
05508    struct mansession_session *session;
05509    struct ao2_iterator i;
05510 
05511    if (ident == 0) {
05512       return 0;
05513    }
05514 
05515    i = ao2_iterator_init(sessions, 0);
05516    while ((session = ao2_iterator_next(&i))) {
05517       ao2_lock(session);
05518       if ((session->managerid == ident) && (session->writeperm & perm)) {
05519          result = 1;
05520          ao2_unlock(session);
05521          unref_mansession(session);
05522          break;
05523       }
05524       ao2_unlock(session);
05525       unref_mansession(session);
05526    }
05527    ao2_iterator_destroy(&i);
05528    return result;
05529 }

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

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

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

06025 {
06026    struct mansession_session *session = NULL;
06027    struct mansession s = { .session = NULL, .tcptls_session = ser };
06028    struct ast_variable *v, *params = get_params;
06029    char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
06030    struct ast_str *http_header = NULL, *out = NULL;
06031    size_t result_size = 512;
06032    struct message m = { 0 };
06033    unsigned int idx;
06034    size_t hdrlen;
06035 
06036    time_t time_now = time(NULL);
06037    unsigned long nonce = 0, nc;
06038    struct ast_http_digest d = { NULL, };
06039    struct ast_manager_user *user = NULL;
06040    int stale = 0;
06041    char resp_hash[256]="";
06042    /* Cache for user data */
06043    char u_username[80];
06044    int u_readperm;
06045    int u_writeperm;
06046    int u_writetimeout;
06047    int u_displayconnects;
06048    struct ast_sockaddr addr;
06049 
06050    if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
06051       ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
06052       return -1;
06053    }
06054 
06055    /* Find "Authorization: " header */
06056    for (v = headers; v; v = v->next) {
06057       if (!strcasecmp(v->name, "Authorization")) {
06058          break;
06059       }
06060    }
06061 
06062    if (!v || ast_strlen_zero(v->value)) {
06063       goto out_401; /* Authorization Header not present - send auth request */
06064    }
06065 
06066    /* Digest found - parse */
06067    if (ast_string_field_init(&d, 128)) {
06068       ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
06069       return -1;
06070    }
06071 
06072    if (ast_parse_digest(v->value, &d, 0, 1)) {
06073       /* Error in Digest - send new one */
06074       nonce = 0;
06075       goto out_401;
06076    }
06077    if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
06078       ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
06079       nonce = 0;
06080       goto out_401;
06081    }
06082 
06083    AST_RWLIST_WRLOCK(&users);
06084    user = get_manager_by_name_locked(d.username);
06085    if(!user) {
06086       AST_RWLIST_UNLOCK(&users);
06087       ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
06088       nonce = 0;
06089       goto out_401;
06090    }
06091 
06092    ast_sockaddr_from_sin(&addr, remote_address);
06093    /* --- We have User for this auth, now check ACL */
06094    if (user->ha && !ast_apply_ha(user->ha, &addr)) {
06095       AST_RWLIST_UNLOCK(&users);
06096       ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
06097       ast_http_error(ser, 403, "Permission denied", "Permission denied\n");
06098       return -1;
06099    }
06100 
06101    /* --- We have auth, so check it */
06102 
06103    /* compute the expected response to compare with what we received */
06104    {
06105       char a2[256];
06106       char a2_hash[256];
06107       char resp[256];
06108 
06109       /* XXX Now request method are hardcoded in A2 */
06110       snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
06111       ast_md5_hash(a2_hash, a2);
06112 
06113       if (d.qop) {
06114          /* RFC 2617 */
06115          snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
06116       }  else {
06117          /* RFC 2069 */
06118          snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
06119       }
06120       ast_md5_hash(resp_hash, resp);
06121    }
06122 
06123    if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
06124       /* Something was wrong, so give the client to try with a new challenge */
06125       AST_RWLIST_UNLOCK(&users);
06126       nonce = 0;
06127       goto out_401;
06128    }
06129 
06130    /*
06131     * User are pass Digest authentication.
06132     * Now, cache the user data and unlock user list.
06133     */
06134    ast_copy_string(u_username, user->username, sizeof(u_username));
06135    u_readperm = user->readperm;
06136    u_writeperm = user->writeperm;
06137    u_displayconnects = user->displayconnects;
06138    u_writetimeout = user->writetimeout;
06139    AST_RWLIST_UNLOCK(&users);
06140 
06141    if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
06142       /*
06143        * Create new session.
06144        * While it is not in the list we don't need any locking
06145        */
06146       if (!(session = build_mansession(*remote_address))) {
06147          ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
06148          return -1;
06149       }
06150       ao2_lock(session);
06151 
06152       ast_copy_string(session->username, u_username, sizeof(session->username));
06153       session->managerid = nonce;
06154       session->last_ev = grab_last();
06155       AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
06156 
06157       session->readperm = u_readperm;
06158       session->writeperm = u_writeperm;
06159       session->writetimeout = u_writetimeout;
06160 
06161       if (u_displayconnects) {
06162          ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
06163       }
06164       session->noncetime = session->sessionstart = time_now;
06165       session->authenticated = 1;
06166    } else if (stale) {
06167       /*
06168        * Session found, but nonce is stale.
06169        *
06170        * This could be because an old request (w/old nonce) arrived.
06171        *
06172        * This may be as the result of http proxy usage (separate delay or
06173        * multipath) or in a situation where a page was refreshed too quickly
06174        * (seen in Firefox).
06175        *
06176        * In this situation, we repeat the 401 auth with the current nonce
06177        * value.
06178        */
06179       nonce = session->managerid;
06180       ao2_unlock(session);
06181       stale = 1;
06182       goto out_401;
06183    } else {
06184       sscanf(d.nc, "%30lx", &nc);
06185       if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
06186          /*
06187           * Nonce time expired (> 2 minutes) or something wrong with nonce
06188           * counter.
06189           *
06190           * Create new nonce key and resend Digest auth request. Old nonce
06191           * is saved for stale checking...
06192           */
06193          session->nc = 0; /* Reset nonce counter */
06194          session->oldnonce = session->managerid;
06195          nonce = session->managerid = ast_random();
06196          session->noncetime = time_now;
06197          ao2_unlock(session);
06198          stale = 1;
06199          goto out_401;
06200       } else {
06201          session->nc = nc; /* All OK, save nonce counter */
06202       }
06203    }
06204 
06205 
06206    /* Reset session timeout. */
06207    session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
06208    ao2_unlock(session);
06209 
06210    ast_mutex_init(&s.lock);
06211    s.session = session;
06212    s.fd = mkstemp(template);  /* create a temporary file for command output */
06213    unlink(template);
06214    if (s.fd <= -1) {
06215       ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
06216       goto auth_callback_out;
06217    }
06218    s.f = fdopen(s.fd, "w+");
06219    if (!s.f) {
06220       ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
06221       ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
06222       close(s.fd);
06223       goto auth_callback_out;
06224    }
06225 
06226    if (method == AST_HTTP_POST) {
06227       params = ast_http_get_post_vars(ser, headers);
06228    }
06229 
06230    for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
06231       hdrlen = strlen(v->name) + strlen(v->value) + 3;
06232       m.headers[m.hdrcount] = ast_malloc(hdrlen);
06233       if (!m.headers[m.hdrcount]) {
06234          /* Allocation failure */
06235          continue;
06236       }
06237       snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
06238       ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
06239       ++m.hdrcount;
06240    }
06241 
06242    if (process_message(&s, &m)) {
06243       if (u_displayconnects) {
06244          ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
06245       }
06246 
06247       session->needdestroy = 1;
06248    }
06249 
06250    /* Free request headers. */
06251    for (idx = 0; idx < m.hdrcount; ++idx) {
06252       ast_free((void *) m.headers[idx]);
06253       m.headers[idx] = NULL;
06254    }
06255 
06256    if (s.f) {
06257       result_size = ftell(s.f); /* Calculate approx. size of result */
06258    }
06259 
06260    http_header = ast_str_create(80);
06261    out = ast_str_create(result_size * 2 + 512);
06262 
06263    if (http_header == NULL || out == NULL) {
06264       ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
06265       goto auth_callback_out;
06266    }
06267 
06268    ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]);
06269 
06270    if (format == FORMAT_XML) {
06271       ast_str_append(&out, 0, "<ajax-response>\n");
06272    } else if (format == FORMAT_HTML) {
06273       ast_str_append(&out, 0,
06274       "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
06275       "<html><head>\r\n"
06276       "<title>Asterisk&trade; Manager Interface</title>\r\n"
06277       "</head><body style=\"background-color: #ffffff;\">\r\n"
06278       "<form method=\"POST\">\r\n"
06279       "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
06280       "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
06281       "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
06282       "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
06283    }
06284 
06285    process_output(&s, &out, params, format);
06286 
06287    if (format == FORMAT_XML) {
06288       ast_str_append(&out, 0, "</ajax-response>\n");
06289    } else if (format == FORMAT_HTML) {
06290       ast_str_append(&out, 0, "</table></form></body></html>\r\n");
06291    }
06292 
06293    ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
06294    http_header = out = NULL;
06295 
06296 auth_callback_out:
06297    ast_mutex_destroy(&s.lock);
06298 
06299    /* Clear resources and unlock manager session */
06300    if (method == AST_HTTP_POST && params) {
06301       ast_variables_destroy(params);
06302    }
06303 
06304    ast_free(http_header);
06305    ast_free(out);
06306 
06307    ao2_lock(session);
06308    if (session->f) {
06309       fclose(session->f);
06310    }
06311    session->f = NULL;
06312    session->fd = -1;
06313    ao2_unlock(session);
06314 
06315    if (session->needdestroy) {
06316       ast_debug(1, "Need destroy, doing it now!\n");
06317       session_destroy(session);
06318    }
06319    ast_string_field_free_memory(&d);
06320    return 0;
06321 
06322 out_401:
06323    if (!nonce) {
06324       nonce = ast_random();
06325    }
06326 
06327    ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
06328    ast_string_field_free_memory(&d);
06329    return 0;
06330 }

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

06392 {
06393    int retval;
06394    struct sockaddr_in ser_remote_address_tmp;
06395 
06396    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06397    retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06398    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06399    return retval;
06400 }

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

06403 {
06404    int retval;
06405    struct sockaddr_in ser_remote_address_tmp;
06406 
06407    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06408    retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06409    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06410    return retval;
06411 }

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

06414 {
06415    int retval;
06416    struct sockaddr_in ser_remote_address_tmp;
06417 
06418    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06419    retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06420    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06421    return retval;
06422 }

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

05405 {
05406    struct mansession_session *session;
05407    struct ao2_iterator i;
05408 
05409    if (ident == 0) {
05410       return NULL;
05411    }
05412 
05413    i = ao2_iterator_init(sessions, 0);
05414    while ((session = ao2_iterator_next(&i))) {
05415       ao2_lock(session);
05416       if (session->managerid == ident && !session->needdestroy) {
05417          ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
05418          break;
05419       }
05420       ao2_unlock(session);
05421       unref_mansession(session);
05422    }
05423    ao2_iterator_destroy(&i);
05424 
05425    return session;
05426 }

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

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

05438 {
05439    struct mansession_session *session;
05440    struct ao2_iterator i;
05441 
05442    if (nonce == 0 || username == NULL || stale == NULL) {
05443       return NULL;
05444    }
05445 
05446    i = ao2_iterator_init(sessions, 0);
05447    while ((session = ao2_iterator_next(&i))) {
05448       ao2_lock(session);
05449       if (!strcasecmp(session->username, username) && session->managerid == nonce) {
05450          *stale = 0;
05451          break;
05452       } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
05453          *stale = 1;
05454          break;
05455       }
05456       ao2_unlock(session);
05457       unref_mansession(session);
05458    }
05459    ao2_iterator_destroy(&i);
05460    return session;
05461 }

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

05810 {
05811    struct mansession s = { .session = NULL, .tcptls_session = ser };
05812    struct mansession_session *session = NULL;
05813    uint32_t ident = 0;
05814    int blastaway = 0;
05815    struct ast_variable *v, *cookies, *params = get_params;
05816    char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
05817    struct ast_str *http_header = NULL, *out = NULL;
05818    struct message m = { 0 };
05819    unsigned int idx;
05820    size_t hdrlen;
05821 
05822    if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
05823       ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
05824       return -1;
05825    }
05826 
05827    cookies = ast_http_get_cookies(headers);
05828    for (v = cookies; v; v = v->next) {
05829       if (!strcasecmp(v->name, "mansession_id")) {
05830          sscanf(v->value, "%30x", &ident);
05831          break;
05832       }
05833    }
05834    if (cookies) {
05835       ast_variables_destroy(cookies);
05836    }
05837 
05838    if (!(session = find_session(ident, 1))) {
05839 
05840       /**/
05841       /* Create new session.
05842        * While it is not in the list we don't need any locking
05843        */
05844       if (!(session = build_mansession(*remote_address))) {
05845          ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
05846          return -1;
05847       }
05848       ao2_lock(session);
05849       session->sin = *remote_address;
05850       session->fd = -1;
05851       session->waiting_thread = AST_PTHREADT_NULL;
05852       session->send_events = 0;
05853       session->inuse = 1;
05854       /*!\note There is approximately a 1 in 1.8E19 chance that the following
05855        * calculation will produce 0, which is an invalid ID, but due to the
05856        * properties of the rand() function (and the constantcy of s), that
05857        * won't happen twice in a row.
05858        */
05859       while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
05860       session->last_ev = grab_last();
05861       AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
05862    }
05863    ao2_unlock(session);
05864 
05865    http_header = ast_str_create(128);
05866    out = ast_str_create(2048);
05867 
05868    ast_mutex_init(&s.lock);
05869 
05870    if (http_header == NULL || out == NULL) {
05871       ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
05872       goto generic_callback_out;
05873    }
05874 
05875    s.session = session;
05876    s.fd = mkstemp(template);  /* create a temporary file for command output */
05877    unlink(template);
05878    if (s.fd <= -1) {
05879       ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
05880       goto generic_callback_out;
05881    }
05882    s.f = fdopen(s.fd, "w+");
05883    if (!s.f) {
05884       ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
05885       ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
05886       close(s.fd);
05887       goto generic_callback_out;
05888    }
05889 
05890    if (method == AST_HTTP_POST) {
05891       params = ast_http_get_post_vars(ser, headers);
05892    }
05893 
05894    for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
05895       hdrlen = strlen(v->name) + strlen(v->value) + 3;
05896       m.headers[m.hdrcount] = ast_malloc(hdrlen);
05897       if (!m.headers[m.hdrcount]) {
05898          /* Allocation failure */
05899          continue;
05900       }
05901       snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
05902       ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
05903       ++m.hdrcount;
05904    }
05905 
05906    if (process_message(&s, &m)) {
05907       if (session->authenticated) {
05908          if (manager_displayconnects(session)) {
05909             ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
05910          }
05911       } else {
05912          if (displayconnects) {
05913             ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
05914          }
05915       }
05916       session->needdestroy = 1;
05917    }
05918 
05919    /* Free request headers. */
05920    for (idx = 0; idx < m.hdrcount; ++idx) {
05921       ast_free((void *) m.headers[idx]);
05922       m.headers[idx] = NULL;
05923    }
05924 
05925    ast_str_append(&http_header, 0,
05926       "Content-type: text/%s\r\n"
05927       "Cache-Control: no-cache;\r\n"
05928       "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
05929       "Pragma: SuppressEvents\r\n",
05930       contenttype[format],
05931       session->managerid, httptimeout);
05932 
05933    if (format == FORMAT_XML) {
05934       ast_str_append(&out, 0, "<ajax-response>\n");
05935    } else if (format == FORMAT_HTML) {
05936       /*
05937        * When handling AMI-over-HTTP in HTML format, we provide a simple form for
05938        * debugging purposes. This HTML code should not be here, we
05939        * should read from some config file...
05940        */
05941 
05942 #define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
05943 #define TEST_STRING \
05944    "<form action=\"manager\" method=\"post\">\n\
05945    Action: <select name=\"action\">\n\
05946       <option value=\"\">-----&gt;</option>\n\
05947       <option value=\"login\">login</option>\n\
05948       <option value=\"command\">Command</option>\n\
05949       <option value=\"waitevent\">waitevent</option>\n\
05950       <option value=\"listcommands\">listcommands</option>\n\
05951    </select>\n\
05952    or <input name=\"action\"><br/>\n\
05953    CLI Command <input name=\"command\"><br>\n\
05954    user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
05955    <input type=\"submit\">\n</form>\n"
05956 
05957       ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
05958       ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
05959       ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
05960       ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
05961    }
05962 
05963    process_output(&s, &out, params, format);
05964 
05965    if (format == FORMAT_XML) {
05966       ast_str_append(&out, 0, "</ajax-response>\n");
05967    } else if (format == FORMAT_HTML) {
05968       ast_str_append(&out, 0, "</table></body>\r\n");
05969    }
05970 
05971    ao2_lock(session);
05972    /* Reset HTTP timeout.  If we're not authenticated, keep it extremely short */
05973    session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
05974 
05975    if (session->needdestroy) {
05976       if (session->inuse == 1) {
05977          ast_debug(1, "Need destroy, doing it now!\n");
05978          blastaway = 1;
05979       } else {
05980          ast_debug(1, "Need destroy, but can't do it yet!\n");
05981          if (session->waiting_thread != AST_PTHREADT_NULL) {
05982             pthread_kill(session->waiting_thread, SIGURG);
05983          }
05984          session->inuse--;
05985       }
05986    } else {
05987       session->inuse--;
05988    }
05989    ao2_unlock(session);
05990 
05991    ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
05992    http_header = out = NULL;
05993 
05994 generic_callback_out:
05995    ast_mutex_destroy(&s.lock);
05996 
05997    /* Clear resource */
05998 
05999    if (method == AST_HTTP_POST && params) {
06000       ast_variables_destroy(params);
06001    }
06002    if (http_header) {
06003       ast_free(http_header);
06004    }
06005    if (out) {
06006       ast_free(out);
06007    }
06008 
06009    if (session && blastaway) {
06010       session_destroy(session);
06011    } else if (session && session->f) {
06012       fclose(session->f);
06013       session->f = NULL;
06014    }
06015 
06016    return 0;
06017 }

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

06487 {
06488    switch (cmd) {
06489    case CLI_INIT:
06490       e->command = "manager show settings";
06491       e->usage =
06492          "Usage: manager show settings\n"
06493          "       Provides detailed list of the configuration of the Manager.\n";
06494       return NULL;
06495    case CLI_GENERATE:
06496       return NULL;
06497    }
06498 #define FORMAT "  %-25.25s  %-15.15s\n"
06499 #define FORMAT2 "  %-25.25s  %-15d\n"
06500    if (a->argc != 3) {
06501       return CLI_SHOWUSAGE;
06502    }
06503    ast_cli(a->fd, "\nGlobal Settings:\n");
06504    ast_cli(a->fd, "----------------\n");
06505    ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
06506    ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
06507    ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
06508    ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
06509    ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
06510    ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
06511    ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
06512    ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
06513    ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
06514    ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
06515    ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
06516    ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
06517    ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
06518    ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
06519    ast_cli(a->fd, FORMAT, "Block sockets:", AST_CLI_YESNO(block_sockets));
06520 #undef FORMAT
06521 #undef FORMAT2
06522 
06523    return CLI_SUCCESS;
06524 }

int init_manager ( void   ) 

Called by Asterisk initialization.

Definition at line 7022 of file manager.c.

References __init_manager().

Referenced by main().

07023 {
07024    return __init_manager(0);
07025 }

static void load_channelvars ( struct ast_variable var  )  [static]

Definition at line 6546 of file manager.c.

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

06547 {
06548    struct manager_channel_variable *mcv;
06549    char *remaining = ast_strdupa(var->value);
06550    char *next;
06551 
06552    ast_free(manager_channelvars);
06553    manager_channelvars = ast_strdup(var->value);
06554 
06555    /*
06556     * XXX TODO: To allow dialplan functions to have more than one
06557     * parameter requires eliminating the '|' as a separator so we
06558     * could use AST_STANDARD_APP_ARGS() to separate items.
06559     */
06560    free_channelvars();
06561    AST_RWLIST_WRLOCK(&channelvars);
06562    while ((next = strsep(&remaining, ",|"))) {
06563       if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
06564          break;
06565       }
06566       strcpy(mcv->name, next); /* SAFE */
06567       if (strchr(next, '(')) {
06568          mcv->isfunc = 1;
06569       }
06570       AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
06571    }
06572    AST_RWLIST_UNLOCK(&channelvars);
06573 }

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

06333 {
06334    int retval;
06335    struct sockaddr_in ser_remote_address_tmp;
06336 
06337    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06338    retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
06339    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06340    return retval;
06341 }

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

06344 {
06345    int retval;
06346    struct sockaddr_in ser_remote_address_tmp;
06347 
06348    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06349    retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
06350    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06351    return retval;
06352 }

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

Definition at line 5761 of file manager.c.

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

05762 {
05763    char *buf;
05764    size_t l;
05765 
05766    if (!s->f)
05767       return;
05768 
05769    /* Ensure buffer is NULL-terminated */
05770    fprintf(s->f, "%c", 0);
05771    fflush(s->f);
05772 
05773    if ((l = ftell(s->f)) > 0) {
05774       if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) {
05775          ast_log(LOG_WARNING, "mmap failed.  Manager output was not processed\n");
05776       } else {
05777          if (format == FORMAT_XML || format == FORMAT_HTML) {
05778             xml_translate(out, buf, params, format);
05779          } else {
05780             ast_str_append(out, 0, "%s", buf);
05781          }
05782          munmap(buf, l);
05783       }
05784    } else if (format == FORMAT_XML || format == FORMAT_HTML) {
05785       xml_translate(out, "", params, format);
05786    }
05787 
05788    if (s->f) {
05789       if (fclose(s->f)) {
05790          ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
05791       }
05792       s->f = NULL;
05793       s->fd = -1;
05794    } else if (s->fd != -1) {
05795       if (close(s->fd)) {
05796          ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
05797       }
05798       s->fd = -1;
05799    } else {
05800       ast_log(LOG_ERROR, "process output attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n");
05801    }
05802 }

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

References purge_events(), and purge_sessions().

06458 {
06459    purge_sessions(1);
06460    purge_events();
06461 }

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

06355 {
06356    int retval;
06357    struct sockaddr_in ser_remote_address_tmp;
06358 
06359    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06360    retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06361    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06362    return retval;
06363 }

int reload_manager ( void   ) 

Called by Asterisk module functions and the CLI command.

Definition at line 7027 of file manager.c.

References __init_manager().

Referenced by handle_manager_reload().

07028 {
07029    return __init_manager(1);
07030 }

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

Definition at line 5605 of file manager.c.

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

05606 {
05607    /* Due to the simplicity of struct variable_count, it makes no difference
05608     * if you pass in objects or strings, the same operation applies. This is
05609     * due to the fact that the hash occurs on the first element, which means
05610     * the address of both the struct and the string are exactly the same. */
05611    struct variable_count *vc = obj;
05612    char *str = vstr;
05613    return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
05614 }

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

Definition at line 5598 of file manager.c.

References ast_str_hash(), and variable_count::varname.

05599 {
05600    const struct variable_count *vc = vvc;
05601 
05602    return ast_str_hash(vc->varname);
05603 }

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

Definition at line 5536 of file manager.c.

References ast_str_append().

05537 {
05538    /* store in a local buffer to avoid calling ast_str_append too often */
05539    char buf[256];
05540    char *dst = buf;
05541    int space = sizeof(buf);
05542    /* repeat until done and nothing to flush */
05543    for ( ; *src || dst != buf ; src++) {
05544       if (*src == '\0' || space < 10) {   /* flush */
05545          *dst++ = '\0';
05546          ast_str_append(out, 0, "%s", buf);
05547          dst = buf;
05548          space = sizeof(buf);
05549          if (*src == '\0') {
05550             break;
05551          }
05552       }
05553 
05554       if ( (mode & 2) && !isalnum(*src)) {
05555          *dst++ = '_';
05556          space--;
05557          continue;
05558       }
05559       switch (*src) {
05560       case '<':
05561          strcpy(dst, "&lt;");
05562          dst += 4;
05563          space -= 4;
05564          break;
05565       case '>':
05566          strcpy(dst, "&gt;");
05567          dst += 4;
05568          space -= 4;
05569          break;
05570       case '\"':
05571          strcpy(dst, "&quot;");
05572          dst += 6;
05573          space -= 6;
05574          break;
05575       case '\'':
05576          strcpy(dst, "&apos;");
05577          dst += 6;
05578          space -= 6;
05579          break;
05580       case '&':
05581          strcpy(dst, "&amp;");
05582          dst += 5;
05583          space -= 5;
05584          break;
05585 
05586       default:
05587          *dst++ = mode ? tolower(*src) : *src;
05588          space--;
05589       }
05590    }
05591 }

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

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

Referenced by process_output().

05645 {
05646    struct ast_variable *v;
05647    const char *dest = NULL;
05648    char *var, *val;
05649    const char *objtype = NULL;
05650    int in_data = 0;  /* parsing data */
05651    int inobj = 0;
05652    int xml = (format == FORMAT_XML);
05653    struct variable_count *vc = NULL;
05654    struct ao2_container *vco = NULL;
05655 
05656    if (xml) {
05657       /* dest and objtype need only for XML format */
05658       for (v = get_vars; v; v = v->next) {
05659          if (!strcasecmp(v->name, "ajaxdest")) {
05660             dest = v->value;
05661          } else if (!strcasecmp(v->name, "ajaxobjtype")) {
05662             objtype = v->value;
05663          }
05664       }
05665       if (ast_strlen_zero(dest)) {
05666          dest = "unknown";
05667       }
05668       if (ast_strlen_zero(objtype)) {
05669          objtype = "generic";
05670       }
05671    }
05672 
05673    /* we want to stop when we find an empty line */
05674    while (in && *in) {
05675       val = strsep(&in, "\r\n"); /* mark start and end of line */
05676       if (in && *in == '\n') {   /* remove trailing \n if any */
05677          in++;
05678       }
05679       ast_trim_blanks(val);
05680       ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
05681       if (ast_strlen_zero(val)) {
05682          /* empty line */
05683          if (in_data) {
05684             /* close data in Opaque mode */
05685             ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05686             in_data = 0;
05687          }
05688 
05689          if (inobj) {
05690             /* close block */
05691             ast_str_append(out, 0, xml ? " /></response>\n" :
05692                "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05693             inobj = 0;
05694             ao2_ref(vco, -1);
05695             vco = NULL;
05696          }
05697          continue;
05698       }
05699 
05700       if (!inobj) {
05701          /* start new block */
05702          if (xml) {
05703             ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
05704          }
05705          vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
05706          inobj = 1;
05707       }
05708 
05709       if (in_data) {
05710          /* Process data field in Opaque mode. This is a
05711           * followup, so we re-add line feeds. */
05712          ast_str_append(out, 0, xml ? "\n" : "<br>\n");
05713          xml_copy_escape(out, val, 0);   /* data field */
05714          continue;
05715       }
05716 
05717       /* We expect "Name: value" line here */
05718       var = strsep(&val, ":");
05719       if (val) {
05720          /* found the field name */
05721          val = ast_skip_blanks(val);
05722          ast_trim_blanks(var);
05723       } else {
05724          /* field name not found, switch to opaque mode */
05725          val = var;
05726          var = "Opaque-data";
05727          in_data = 1;
05728       }
05729 
05730 
05731       ast_str_append(out, 0, xml ? " " : "<tr><td>");
05732       if ((vc = ao2_find(vco, var, 0))) {
05733          vc->count++;
05734       } else {
05735          /* Create a new entry for this one */
05736          vc = ao2_alloc(sizeof(*vc), NULL);
05737          vc->varname = var;
05738          vc->count = 1;
05739          ao2_link(vco, vc);
05740       }
05741 
05742       xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
05743       if (vc->count > 1) {
05744          ast_str_append(out, 0, "-%d", vc->count);
05745       }
05746       ao2_ref(vc, -1);
05747       ast_str_append(out, 0, xml ? "='" : "</td><td>");
05748       xml_copy_escape(out, val, 0); /* data field */
05749       if (!in_data || !*in) {
05750          ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05751       }
05752    }
05753 
05754    if (inobj) {
05755       ast_str_append(out, 0, xml ? " /></response>\n" :
05756          "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05757       ao2_ref(vco, -1);
05758    }
05759 }


Variable Documentation

struct ast_http_uri amanageruri [static]

Definition at line 6433 of file manager.c.

struct ast_http_uri amanagerxmluri [static]

Definition at line 6442 of file manager.c.

struct ast_tcptls_session_args ami_desc [static]

Definition at line 6464 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_tls_config ami_tls_cfg [static]

Definition at line 6463 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_tcptls_session_args amis_desc [static]

Definition at line 6475 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_http_uri arawmanuri [static]

Definition at line 6424 of file manager.c.

struct ast_cli_entry cli_manager[] [static]

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

struct ast_http_uri manageruri [static]

Definition at line 6373 of file manager.c.

struct ast_http_uri managerxmluri [static]

Definition at line 6381 of file manager.c.

struct ast_http_uri rawmanuri [static]

Definition at line 6365 of file manager.c.

int registered = 0 [static]

Definition at line 6451 of file manager.c.

int webregged = 0 [static]

Definition at line 6452 of file manager.c.

const char* words[AST_MAX_CMD_LEN]

Definition at line 921 of file manager.c.

Referenced by check_blacklist().


Generated on Mon Oct 8 12:39:24 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7