Wed Apr 6 11:30:06 2011

Asterisk developer's documentation


manager.c File Reference

The Asterisk Management Interface - AMI. More...

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

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

Functions

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

Variables

static int allowmultiplelogin = 1
static struct ast_http_uri amanageruri
static struct ast_http_uri amanagerxmluri
static struct ast_tcptls_session_args ami_desc
static struct ast_tls_config ami_tls_cfg
static struct ast_tcptls_session_args amis_desc
static struct ast_http_uri arawmanuri
static struct ast_threadstorage astman_append_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_astman_append_buf , .custom_init = NULL , }
static int 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_BLOCKSOCKETS = 0
static const int DEFAULT_BROKENEVENTSACTION = 0
static const int DEFAULT_DISPLAYCONNECTS = 1
static const int DEFAULT_ENABLED = 0
static const int DEFAULT_HTTPTIMEOUT = 60
static const int DEFAULT_TIMESTAMPEVENTS = 0
static const int DEFAULT_WEBENABLED = 0
static int displayconnects
static char global_realm [MAXHOSTNAMELEN]
static int httptimeout
static char * manager_channelvars
static int manager_debug
static int manager_enabled = 0
static struct ast_threadstorage manager_event_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_manager_event_buf , .custom_init = NULL , }
static struct ast_threadstorage manager_event_funcbuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_manager_event_funcbuf , .custom_init = NULL , }
static struct ast_http_uri manageruri
static struct ast_http_uri managerxmluri
static struct permalias perms []
static struct ast_http_uri rawmanuri
static int registered = 0
static struct ao2_containersessions = NULL
static int timestampevents
static 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 5010 of file manager.c.

05010                    {
05011    FORMAT_RAW,
05012    FORMAT_HTML,
05013    FORMAT_XML,
05014 };


Function Documentation

static int __init_manager ( int  reload  )  [static]

Definition at line 6136 of file manager.c.

References action_aocmessage(), action_atxfer(), action_challenge(), action_command(), action_coresettings(), action_coreshowchannels(), action_corestatus(), action_createconfig(), action_events(), action_extensionstate(), action_getconfig(), action_getconfigjson(), action_getvar(), action_hangup(), action_listcategories(), action_listcommands(), action_login(), action_logoff(), action_mailboxcount(), action_mailboxstatus(), action_originate(), action_ping(), action_redirect(), action_reload(), action_sendtext(), action_setvar(), action_status(), action_timeout(), action_updateconfig(), action_userevent(), action_waitevent(), ami_desc, ami_tls_cfg, amis_desc, append_event(), ARRAY_LEN, AST_CERTFILE, ast_cli_register_multiple(), ast_config_AST_SYSTEM_NAME, ast_config_load2(), ast_copy_string(), ast_extension_state_add(), ast_free, ast_log(), ast_manager_register_xml, ast_strdup, ast_tls_read_conf(), ast_true(), ast_variable_browse(), block_sockets, broken_events_action, ast_tls_config::certfile, ast_tls_config::cipher, cli_manager, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_BLOCKSOCKETS, DEFAULT_BROKENEVENTSACTION, DEFAULT_DISPLAYCONNECTS, DEFAULT_ENABLED, DEFAULT_HTTPTIMEOUT, DEFAULT_MANAGER_PORT, DEFAULT_REALM, DEFAULT_TIMESTAMPEVENTS, DEFAULT_WEBENABLED, displayconnects, ast_tls_config::enabled, EVENT_FLAG_AOC, EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, EVENT_FLAG_CONFIG, EVENT_FLAG_ORIGINATE, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, free_channelvars(), global_realm, httptimeout, ast_tcptls_session_args::local_address, LOG_NOTICE, manager_enabled, manager_modulecheck(), manager_moduleload(), manager_state_cb(), ast_tls_config::pvtfile, S_OR, timestampevents, var, and webmanager_enabled.

Referenced by init_manager(), and reload_manager().

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

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

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

06579 {
06580    AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
06581 
06582    return 0;
06583 }

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

06591 {
06592    struct ast_datastore *datastore = NULL;
06593 
06594    if (info == NULL)
06595       return NULL;
06596 
06597    AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
06598       if (datastore->info != info) {
06599          continue;
06600       }
06601 
06602       if (uid == NULL) {
06603          /* matched by type only */
06604          break;
06605       }
06606 
06607       if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
06608          /* Matched by type AND uid */
06609          break;
06610       }
06611    }
06612    AST_LIST_TRAVERSE_SAFE_END;
06613 
06614    return datastore;
06615 }

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

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

06586 {
06587    return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
06588 }

int astman_is_authed ( uint32_t  ident  ) 

Determinie if a manager session ident is authenticated.

Definition at line 5086 of file manager.c.

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

Referenced by http_post_callback(), and static_callback().

05087 {
05088    int authed;
05089    struct mansession_session *session;
05090 
05091    if (!(session = find_session(ident, 0)))
05092       return 0;
05093 
05094    authed = (session->authenticated != 0);
05095 
05096    ao2_unlock(session);
05097    unref_mansession(session);
05098 
05099    return authed;
05100 }

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

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

05103 {
05104    int result = 0;
05105    struct mansession_session *session;
05106    struct ao2_iterator i;
05107 
05108    if (ident == 0) {
05109       return 0;
05110    }
05111 
05112    i = ao2_iterator_init(sessions, 0);
05113    while ((session = ao2_iterator_next(&i))) {
05114       ao2_lock(session);
05115       if ((session->managerid == ident) && (session->readperm & perm)) {
05116          result = 1;
05117          ao2_unlock(session);
05118          unref_mansession(session);
05119          break;
05120       }
05121       ao2_unlock(session);
05122       unref_mansession(session);
05123    }
05124    ao2_iterator_destroy(&i);
05125    return result;
05126 }

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

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

05129 {
05130    int result = 0;
05131    struct mansession_session *session;
05132    struct ao2_iterator i;
05133 
05134    if (ident == 0) {
05135       return 0;
05136    }
05137 
05138    i = ao2_iterator_init(sessions, 0);
05139    while ((session = ao2_iterator_next(&i))) {
05140       ao2_lock(session);
05141       if ((session->managerid == ident) && (session->writeperm & perm)) {
05142          result = 1;
05143          ao2_unlock(session);
05144          unref_mansession(session);
05145          break;
05146       }
05147       ao2_unlock(session);
05148       unref_mansession(session);
05149    }
05150    ao2_iterator_destroy(&i);
05151    return result;
05152 }

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

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

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

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

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

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

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

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

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

06012 {
06013    int retval;
06014    struct sockaddr_in ser_remote_address_tmp;
06015 
06016    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
06017    retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
06018    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
06019    return retval;
06020 }

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

05028 {
05029    struct mansession_session *session;
05030    struct ao2_iterator i;
05031 
05032    if (ident == 0) {
05033       return NULL;
05034    }
05035 
05036    i = ao2_iterator_init(sessions, 0);
05037    while ((session = ao2_iterator_next(&i))) {
05038       ao2_lock(session);
05039       if (session->managerid == ident && !session->needdestroy) {
05040          ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
05041          break;
05042       }
05043       ao2_unlock(session);
05044       unref_mansession(session);
05045    }
05046    ao2_iterator_destroy(&i);
05047 
05048    return session;
05049 }

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

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

05061 {
05062    struct mansession_session *session;
05063    struct ao2_iterator i;
05064 
05065    if (nonce == 0 || username == NULL || stale == NULL) {
05066       return NULL;
05067    }
05068 
05069    i = ao2_iterator_init(sessions, 0);
05070    while ((session = ao2_iterator_next(&i))) {
05071       ao2_lock(session);
05072       if (!strcasecmp(session->username, username) && session->managerid == nonce) {
05073          *stale = 0;
05074          break;
05075       } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
05076          *stale = 1;
05077          break;
05078       }
05079       ao2_unlock(session);
05080       unref_mansession(session);
05081    }
05082    ao2_iterator_destroy(&i);
05083    return session;
05084 }

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

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

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

06085 {
06086    switch (cmd) {
06087    case CLI_INIT:
06088       e->command = "manager show settings";
06089       e->usage =
06090          "Usage: manager show settings\n"
06091          "       Provides detailed list of the configuration of the Manager.\n";
06092       return NULL;
06093    case CLI_GENERATE:
06094       return NULL;
06095    }
06096 #define FORMAT "  %-25.25s  %-15.15s\n"
06097 #define FORMAT2 "  %-25.25s  %-15d\n"
06098    if (a->argc != 3) {
06099       return CLI_SHOWUSAGE;
06100    }
06101    ast_cli(a->fd, "\nGlobal Settings:\n");
06102    ast_cli(a->fd, "----------------\n");
06103    ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
06104    ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
06105    ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
06106    ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
06107    ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
06108    ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
06109    ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
06110    ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
06111    ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
06112    ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
06113    ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
06114    ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
06115    ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
06116    ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
06117    ast_cli(a->fd, FORMAT, "Block sockets:", AST_CLI_YESNO(block_sockets));
06118 #undef FORMAT
06119 #undef FORMAT2
06120 
06121    return CLI_SUCCESS;
06122 }

int init_manager ( void   ) 

Called by Asterisk initialization.

Definition at line 6568 of file manager.c.

References __init_manager().

Referenced by main().

06569 {
06570    return __init_manager(0);
06571 }

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

05931 {
05932    int retval;
05933    struct sockaddr_in ser_remote_address_tmp;
05934 
05935    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
05936    retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
05937    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
05938    return retval;
05939 }

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

05942 {
05943    int retval;
05944    struct sockaddr_in ser_remote_address_tmp;
05945 
05946    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
05947    retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
05948    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
05949    return retval;
05950 }

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

References purge_events(), and purge_sessions().

06056 {
06057    purge_sessions(1);
06058    purge_events();
06059 }

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

05953 {
05954    int retval;
05955    struct sockaddr_in ser_remote_address_tmp;
05956 
05957    ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
05958    retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
05959    ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
05960    return retval;
05961 }

int reload_manager ( void   ) 

Called by Asterisk module functions and the CLI command.

Definition at line 6573 of file manager.c.

References __init_manager().

Referenced by handle_manager_reload().

06574 {
06575    return __init_manager(1);
06576 }

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

Definition at line 5228 of file manager.c.

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

05229 {
05230    /* Due to the simplicity of struct variable_count, it makes no difference
05231     * if you pass in objects or strings, the same operation applies. This is
05232     * due to the fact that the hash occurs on the first element, which means
05233     * the address of both the struct and the string are exactly the same. */
05234    struct variable_count *vc = obj;
05235    char *str = vstr;
05236    return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
05237 }

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

Definition at line 5221 of file manager.c.

References ast_str_hash(), and variable_count::varname.

05222 {
05223    const struct variable_count *vc = vvc;
05224 
05225    return ast_str_hash(vc->varname);
05226 }

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

Definition at line 5159 of file manager.c.

References ast_str_append().

05160 {
05161    /* store in a local buffer to avoid calling ast_str_append too often */
05162    char buf[256];
05163    char *dst = buf;
05164    int space = sizeof(buf);
05165    /* repeat until done and nothing to flush */
05166    for ( ; *src || dst != buf ; src++) {
05167       if (*src == '\0' || space < 10) {   /* flush */
05168          *dst++ = '\0';
05169          ast_str_append(out, 0, "%s", buf);
05170          dst = buf;
05171          space = sizeof(buf);
05172          if (*src == '\0') {
05173             break;
05174          }
05175       }
05176 
05177       if ( (mode & 2) && !isalnum(*src)) {
05178          *dst++ = '_';
05179          space--;
05180          continue;
05181       }
05182       switch (*src) {
05183       case '<':
05184          strcpy(dst, "&lt;");
05185          dst += 4;
05186          space -= 4;
05187          break;
05188       case '>':
05189          strcpy(dst, "&gt;");
05190          dst += 4;
05191          space -= 4;
05192          break;
05193       case '\"':
05194          strcpy(dst, "&quot;");
05195          dst += 6;
05196          space -= 6;
05197          break;
05198       case '\'':
05199          strcpy(dst, "&apos;");
05200          dst += 6;
05201          space -= 6;
05202          break;
05203       case '&':
05204          strcpy(dst, "&amp;");
05205          dst += 5;
05206          space -= 5;
05207          break;
05208 
05209       default:
05210          *dst++ = mode ? tolower(*src) : *src;
05211          space--;
05212       }
05213    }
05214 }

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

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

05268 {
05269    struct ast_variable *v;
05270    const char *dest = NULL;
05271    char *var, *val;
05272    const char *objtype = NULL;
05273    int in_data = 0;  /* parsing data */
05274    int inobj = 0;
05275    int xml = (format == FORMAT_XML);
05276    struct variable_count *vc = NULL;
05277    struct ao2_container *vco = NULL;
05278 
05279    if (xml) {
05280       /* dest and objtype need only for XML format */
05281       for (v = get_vars; v; v = v->next) {
05282          if (!strcasecmp(v->name, "ajaxdest")) {
05283             dest = v->value;
05284          } else if (!strcasecmp(v->name, "ajaxobjtype")) {
05285             objtype = v->value;
05286          }
05287       }
05288       if (ast_strlen_zero(dest)) {
05289          dest = "unknown";
05290       }
05291       if (ast_strlen_zero(objtype)) {
05292          objtype = "generic";
05293       }
05294    }
05295 
05296    /* we want to stop when we find an empty line */
05297    while (in && *in) {
05298       val = strsep(&in, "\r\n"); /* mark start and end of line */
05299       if (in && *in == '\n') {   /* remove trailing \n if any */
05300          in++;
05301       }
05302       ast_trim_blanks(val);
05303       ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
05304       if (ast_strlen_zero(val)) {
05305          /* empty line */
05306          if (in_data) {
05307             /* close data in Opaque mode */
05308             ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05309             in_data = 0;
05310          }
05311 
05312          if (inobj) {
05313             /* close block */
05314             ast_str_append(out, 0, xml ? " /></response>\n" :
05315                "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05316             inobj = 0;
05317             ao2_ref(vco, -1);
05318             vco = NULL;
05319          }
05320          continue;
05321       }
05322 
05323       if (!inobj) {
05324          /* start new block */
05325          if (xml) {
05326             ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
05327          }
05328          vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
05329          inobj = 1;
05330       }
05331 
05332       if (in_data) {
05333          /* Process data field in Opaque mode */
05334          xml_copy_escape(out, val, 0);   /* data field */
05335          ast_str_append(out, 0, xml ? "\n" : "<br>\n");
05336          continue;
05337       }
05338 
05339       /* We expect "Name: value" line here */
05340       var = strsep(&val, ":");
05341       if (val) {
05342          /* found the field name */
05343          val = ast_skip_blanks(val);
05344          ast_trim_blanks(var);
05345       } else {
05346          /* field name not found, switch to opaque mode */
05347          val = var;
05348          var = "Opaque-data";
05349          in_data = 1;
05350       }
05351 
05352 
05353       ast_str_append(out, 0, xml ? " " : "<tr><td>");
05354       if ((vc = ao2_find(vco, var, 0))) {
05355          vc->count++;
05356       } else {
05357          /* Create a new entry for this one */
05358          vc = ao2_alloc(sizeof(*vc), NULL);
05359          vc->varname = var;
05360          vc->count = 1;
05361          ao2_link(vco, vc);
05362       }
05363 
05364       xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
05365       if (vc->count > 1) {
05366          ast_str_append(out, 0, "-%d", vc->count);
05367       }
05368       ao2_ref(vc, -1);
05369       ast_str_append(out, 0, xml ? "='" : "</td><td>");
05370       xml_copy_escape(out, val, 0); /* data field */
05371       ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
05372    }
05373 
05374    if (inobj) {
05375       ast_str_append(out, 0, xml ? " /></response>\n" :
05376          "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
05377       ao2_ref(vco, -1);
05378    }
05379 }


Variable Documentation

struct ast_http_uri amanageruri [static]

Definition at line 6031 of file manager.c.

struct ast_http_uri amanagerxmluri [static]

Definition at line 6040 of file manager.c.

struct ast_tcptls_session_args ami_desc [static]

Definition at line 6062 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_tls_config ami_tls_cfg [static]

Definition at line 6061 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_tcptls_session_args amis_desc [static]

Definition at line 6073 of file manager.c.

Referenced by __init_manager(), and handle_manager_show_settings().

struct ast_http_uri arawmanuri [static]

Definition at line 6022 of file manager.c.

struct ast_cli_entry cli_manager[] [static]

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

struct ast_http_uri manageruri [static]

Definition at line 5971 of file manager.c.

struct ast_http_uri managerxmluri [static]

Definition at line 5979 of file manager.c.

struct ast_http_uri rawmanuri [static]

Definition at line 5963 of file manager.c.

int registered = 0 [static]

Definition at line 6049 of file manager.c.

int webregged = 0 [static]

Definition at line 6050 of file manager.c.

const char* words[AST_MAX_CMD_LEN]

Definition at line 892 of file manager.c.

Referenced by check_blacklist().


Generated on Wed Apr 6 11:30:06 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7