Thu Jun 7 02:14:56 2012

Asterisk developer's documentation


manager.c File Reference

The Asterisk Management Interface - AMI. More...

#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include "asterisk/version.h"
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
#include "asterisk/callerid.h"
#include "asterisk/lock.h"
#include "asterisk/logger.h"
#include "asterisk/options.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/http.h"
#include "asterisk/threadstorage.h"
#include "asterisk/linkedlists.h"
#include "asterisk/term.h"
#include "asterisk/astobj2.h"

Go to the source code of this file.

Data Structures

struct  ast_manager_user
struct  eventqent
struct  fast_originate_helper
struct  mansession
struct  mansession_session
struct  permalias
struct  variable_count

Defines

#define ASTMAN_APPEND_BUF_INITSIZE   256
#define MANAGER_EVENT_BUF_INITSIZE   256
#define MAX_BLACKLIST_CMD_LEN   2

Enumerations

enum  { FORMAT_RAW, FORMAT_HTML, FORMAT_XML }

Functions

static void * accept_thread (void *ignore)
static int action_command (struct mansession *s, const struct message *m)
 action_command: 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_corestatus (struct mansession *s, const struct message *m)
 Show PBX core status information.
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_getvar (struct mansession *s, const struct message *m)
static int action_hangup (struct mansession *s, const struct message *m)
static int action_listcommands (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_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 int append_event (const char *str, int category)
static struct ast_manager_userast_get_manager_by_name_locked (const char *name)
static int ast_instring (const char *bigstr, const char *smallstr, char delim)
static int ast_is_number (const char *string)
static AST_LIST_HEAD_STATIC (users, ast_manager_user)
static AST_LIST_HEAD_STATIC (sessions, mansession_session)
int ast_manager_register2 (const char *action, int auth, int(*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
 register a new command with manager, including online help. This is the preferred way to register a manager command
static int ast_manager_register_struct (struct manager_action *act)
int ast_manager_unregister (char *action)
 AST_RWLOCK_DEFINE_STATIC (actionlock)
 AST_THREADSTORAGE (astman_append_buf, astman_append_buf_init)
 AST_THREADSTORAGE (manager_event_buf, manager_event_buf_init)
void astman_append (struct mansession *s, const char *fmt,...)
const char * astman_get_header (const struct message *m, char *var)
struct ast_variableastman_get_variables (const struct message *m)
void astman_send_ack (struct mansession *s, const struct message *m, char *msg)
void astman_send_error (struct mansession *s, const struct message *m, char *error)
void astman_send_response (struct mansession *s, const struct message *m, char *resp, char *msg)
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 authenticate (struct mansession *s, const struct message *m)
static char * authority_to_str (int authority, char *res, int reslen)
 Convert authority code to string with serveral options.
static int check_blacklist (const char *cmd)
int check_manager_enabled ()
 Check if AMI is enabled.
int check_webmanager_enabled ()
 Check if AMI/HTTP is enabled.
static char * complete_show_mancmd (const char *line, const char *word, int pos, int state)
static int compress_char (char c)
static void destroy_session (struct mansession_session *s)
static int do_message (struct mansession *s)
static void * fast_originate (void *data)
static struct mansession_sessionfind_session (uint32_t ident)
static void free_session (struct mansession_session *s)
static char * generic_http_callback (int format, struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
static int get_input (struct mansession_session *s, char *output)
static int get_perm (const char *instr)
static int handle_showmanager (int fd, int argc, char *argv[])
static int handle_showmanagers (int fd, int argc, char *argv[])
static int handle_showmancmd (int fd, int argc, char *argv[])
static int handle_showmancmds (int fd, int argc, char *argv[])
 CLI command Should change to "manager show commands".
static int handle_showmanconn (int fd, int argc, char *argv[])
 CLI command show manager connected.
static int handle_showmaneventq (int fd, int argc, char *argv[])
 CLI command show manager eventq.
static void handle_updates (struct mansession *s, const struct message *m, struct ast_config *cfg)
static char * html_translate (char *in)
int init_manager (void)
int manager_event (int category, const char *event, const char *fmt,...)
 manager_event: Send AMI event to client
static char * manager_http_callback (struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
static int manager_state_cb (char *context, char *exten, int state, void *data)
static char * mxml_http_callback (struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
static int process_events (struct mansession *s)
static int process_message (struct mansession *s, const struct message *m)
static char * rawman_http_callback (struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
int reload_manager (void)
static void * session_do (void *data)
static int set_eventmask (struct mansession_session *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 void unuse_eventqent (struct eventqent *e)
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 void xml_copy_escape (char **dst, size_t *maxlen, const char *src, int lower)
static char * xml_translate (char *in, struct ast_variable *vars)

Variables

static int asock = -1
static int authlimit
static int authtimeout
static int block_sockets
static int broken_events_action
static struct ast_cli_entry cli_manager []
static struct ast_cli_entry cli_show_manager_command_deprecated
static struct ast_cli_entry cli_show_manager_commands_deprecated
static struct ast_cli_entry cli_show_manager_connected_deprecated
static struct ast_cli_entry cli_show_manager_eventq_deprecated
struct {
   char *   words [AST_MAX_CMD_LEN]
command_blacklist []
static char * contenttype [] = { "plain", "html", "xml" }
static const int DEFAULT_AUTHLIMIT = 50
static const int DEFAULT_AUTHTIMEOUT = 30
static const int DEFAULT_BLOCKSOCKETS = 0
static const int DEFAULT_BROKENEVENTSACTION = 0
static const int DEFAULT_DISPLAYCONNECTS = 1
static const int DEFAULT_ENABLED = 0
static const int DEFAULT_HTTPTIMEOUT = 60
static const int DEFAULT_TIMESTAMPEVENTS = 0
static const int DEFAULT_WEBENABLED = 0
static int displayconnects
static struct manager_actionfirst_action
static int httptimeout
static int manager_enabled = 0
struct ast_http_uri manageruri
struct ast_http_uri managerxmluri
static char mandescr_command []
static char mandescr_coresettings []
static char mandescr_corestatus []
static char mandescr_events []
static char mandescr_extensionstate []
static char mandescr_getconfig []
static char mandescr_getvar []
static char mandescr_hangup []
static char mandescr_listcommands []
static char mandescr_logoff []
static char mandescr_mailboxcount []
static char mandescr_mailboxstatus []
 Help text for manager command mailboxstatus.
static char mandescr_originate []
static char mandescr_ping []
 Manager PING.
static char mandescr_redirect []
static char mandescr_setvar []
static char mandescr_timeout []
static char mandescr_updateconfig []
static char mandescr_userevent []
static char mandescr_waitevent []
 Manager WAITEVENT.
struct eventqentmaster_eventq = NULL
static int num_sessions
static struct permalias perms []
static int portno = DEFAULT_MANAGER_PORT
struct ast_http_uri rawmanuri
static int registered = 0
static char showmanager_help []
static char showmanagers_help []
static char showmancmd_help []
static char showmancmds_help []
static char showmanconn_help []
static char showmaneventq_help []
static pthread_t t
static int timestampevents
static int unauth_sessions = 0
static int webmanager_enabled = 0
static int webregged = 0

Detailed Description

The Asterisk Management Interface - AMI.

Author:
Mark Spencer <markster@digium.com>

Channel Management and more

manager.conf

Definition in file manager.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
FORMAT_RAW 
FORMAT_HTML 
FORMAT_XML 

Definition at line 2976 of file manager.c.

02976      {
02977    FORMAT_RAW,
02978    FORMAT_HTML,
02979    FORMAT_XML,
02980 };


Function Documentation

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
Returns:
1 if the session has the permission mask capabilities, otherwise 0

Definition at line 2938 of file manager.c.

References mansession_session::__lock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, mansession_session::managerid, mansession_session::readperm, s, and sessions.

02939 {
02940    int result = 0;
02941    struct mansession_session *s;
02942 
02943    AST_LIST_LOCK(&sessions);
02944    AST_LIST_TRAVERSE(&sessions, s, list) {
02945       ast_mutex_lock(&s->__lock);
02946       if ((s->managerid == ident) && (s->readperm & perm)) {
02947          result = 1;
02948          ast_mutex_unlock(&s->__lock);
02949          break;
02950       }
02951       ast_mutex_unlock(&s->__lock);
02952    }
02953    AST_LIST_UNLOCK(&sessions);
02954    return result;
02955 }

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
Returns:
1 if the session has the permission mask capabilities, otherwise 0

Definition at line 2957 of file manager.c.

References mansession_session::__lock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, mansession_session::managerid, s, sessions, and mansession_session::writeperm.

02958 {
02959    int result = 0;
02960    struct mansession_session *s;
02961 
02962    AST_LIST_LOCK(&sessions);
02963    AST_LIST_TRAVERSE(&sessions, s, list) {
02964       ast_mutex_lock(&s->__lock);
02965       if ((s->managerid == ident) && (s->writeperm & perm)) {
02966          result = 1;
02967          ast_mutex_unlock(&s->__lock);
02968          break;
02969       }
02970       ast_mutex_unlock(&s->__lock);
02971    }
02972    AST_LIST_UNLOCK(&sessions);
02973    return result;
02974 }

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

END Doxygen group

Definition at line 2920 of file manager.c.

References mansession_session::__lock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, mansession_session::inuse, mansession_session::managerid, mansession_session::needdestroy, s, sessions, and mansession_session::sessiontimeout.

Referenced by generic_http_callback().

02921 {
02922    struct mansession_session *s;
02923 
02924    AST_LIST_LOCK(&sessions);
02925    AST_LIST_TRAVERSE(&sessions, s, list) {
02926       ast_mutex_lock(&s->__lock);
02927       if (s->sessiontimeout && (s->managerid == ident) && !s->needdestroy) {
02928          s->inuse++;
02929          break;
02930       }
02931       ast_mutex_unlock(&s->__lock);
02932    }
02933    AST_LIST_UNLOCK(&sessions);
02934 
02935    return s;
02936 }

static char* generic_http_callback ( int  format,
struct sockaddr_in *  requestor,
const char *  uri,
struct ast_variable params,
int *  status,
char **  title,
int *  contentlength 
) [static]

Note:
There is approximately a 1 in 1.8E19 chance that the following calculation will produce 0, which is an invalid ID, but due to the properties of the rand() function (and the constantcy of s), that won't happen twice in a row.

Definition at line 2983 of file manager.c.

References mansession_session::__lock, ast_atomic_fetchadd_int(), ast_build_string(), ast_calloc, ast_http_error(), ast_http_setcookie(), ast_inet_ntoa(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_MAX_MANHEADERS, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, ast_verbose(), mansession_session::authenticated, contenttype, destroy_session(), errno, mansession::fd, mansession_session::fd, find_session(), FORMAT_HTML, FORMAT_XML, free, message::hdrcount, message::headers, html_translate(), mansession_session::inuse, len(), LOG_DEBUG, LOG_ERROR, LOG_EVENT, LOG_WARNING, malloc, mansession_session::managerid, ast_variable::name, mansession_session::needdestroy, eventqent::next, ast_variable::next, option_verbose, mansession_session::outputstr, process_message(), s, mansession_session::send_events, mansession::session, sessions, mansession_session::sessiontimeout, mansession_session::sin, ast_dynamic_str::str, strdup, mansession_session::username, ast_variable::value, VERBOSE_PREFIX_2, mansession_session::waiting_thread, and xml_translate().

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

02984 {
02985    struct mansession_session *s = NULL;
02986    struct mansession ss = { .session = NULL, };
02987    uint32_t ident = 0;
02988    char workspace[512];
02989    char cookie[128];
02990    size_t len = sizeof(workspace);
02991    int blastaway = 0;
02992    char *c = workspace;
02993    char *retval = NULL;
02994    struct ast_variable *v;
02995    char template[] = "/tmp/ast-http-XXXXXX";
02996 
02997    for (v = params; v; v = v->next) {
02998       if (!strcasecmp(v->name, "mansession_id")) {
02999          sscanf(v->value, "%30x", &ident);
03000          break;
03001       }
03002    }
03003    
03004    if (!(s = find_session(ident))) {
03005       /* Create new session */
03006       if (!(s = ast_calloc(1, sizeof(*s)))) {
03007          *status = 500;
03008          goto generic_callback_out;
03009       }
03010       memcpy(&s->sin, requestor, sizeof(s->sin));
03011       s->fd = -1;
03012       s->waiting_thread = AST_PTHREADT_NULL;
03013       s->send_events = 0;
03014       ast_mutex_init(&s->__lock);
03015       ast_mutex_lock(&s->__lock);
03016       s->inuse = 1;
03017       /*!\note There is approximately a 1 in 1.8E19 chance that the following
03018        * calculation will produce 0, which is an invalid ID, but due to the
03019        * properties of the rand() function (and the constantcy of s), that
03020        * won't happen twice in a row.
03021        */
03022       while ((s->managerid = rand() ^ (unsigned long) s) == 0);
03023       AST_LIST_LOCK(&sessions);
03024       AST_LIST_INSERT_HEAD(&sessions, s, list);
03025       /* Hook into the last spot in the event queue */
03026       s->eventq = master_eventq;
03027       while (s->eventq->next)
03028          s->eventq = s->eventq->next;
03029       ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
03030       ast_atomic_fetchadd_int(&num_sessions, 1);
03031       AST_LIST_UNLOCK(&sessions);
03032    }
03033 
03034    /* Reset HTTP timeout.  If we're not yet authenticated, keep it extremely short */
03035    time(&s->sessiontimeout);
03036    if (!s->authenticated && (httptimeout > 5))
03037       s->sessiontimeout += 5;
03038    else
03039       s->sessiontimeout += httptimeout;
03040    ss.session = s;
03041    ast_mutex_unlock(&s->__lock);
03042 
03043    if ((ss.fd = mkstemp(template)) > -1) {
03044       unlink(template);
03045    }
03046 
03047    if (s) {
03048       struct message m = { 0 };
03049       char tmp[80];
03050       unsigned int x;
03051       size_t hdrlen;
03052 
03053       for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
03054          hdrlen = strlen(v->name) + strlen(v->value) + 3;
03055          m.headers[m.hdrcount] = alloca(hdrlen);
03056          snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
03057          m.hdrcount = x + 1;
03058       }
03059 
03060       if (process_message(&ss, &m)) {
03061          if (s->authenticated) {
03062             if (option_verbose > 1) {
03063                if (displayconnects) 
03064                   ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));    
03065             }
03066             ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
03067          } else {
03068             if (option_verbose > 1) {
03069                if (displayconnects)
03070                   ast_verbose(VERBOSE_PREFIX_2 "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
03071             }
03072             ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
03073          }
03074          s->needdestroy = 1;
03075       }
03076       ast_build_string(&c, &len, "Content-type: text/%s\r\n", contenttype[format]);
03077       sprintf(tmp, "%08x", s->managerid);
03078       ast_build_string(&c, &len, "%s\r\n", ast_http_setcookie("mansession_id", tmp, httptimeout, cookie, sizeof(cookie)));
03079       if (format == FORMAT_HTML)
03080          ast_build_string(&c, &len, "<title>Asterisk&trade; Manager Interface</title>");
03081       if (format == FORMAT_XML) {
03082          ast_build_string(&c, &len, "<ajax-response>\n");
03083       } else if (format == FORMAT_HTML) {
03084          ast_build_string(&c, &len, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
03085          ast_build_string(&c, &len, "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\"><h1>&nbsp;&nbsp;Manager Tester</h1></td></tr>\r\n");
03086       }
03087       ast_mutex_lock(&s->__lock);
03088       if (ss.fd > -1) {
03089          char *buf;
03090          size_t l;
03091          ssize_t res;
03092 
03093          /* Make sure that our buffer is NULL terminated */
03094          while ((res = write(ss.fd, "", 1)) < 1) {
03095             if (res == -1) {
03096                ast_log(LOG_ERROR, "Failed to terminate manager response output: %s\n", strerror(errno));
03097                break;
03098             }
03099          }
03100 
03101          if (res == 1 && (l = lseek(ss.fd, 0, SEEK_END)) > 0) {
03102             if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, ss.fd, 0))) {
03103                ast_log(LOG_WARNING, "mmap failed.  Manager request output was not processed\n");
03104             } else {
03105                char *tmpbuf;
03106                if (format == FORMAT_XML)
03107                   tmpbuf = xml_translate(buf, params);
03108                else if (format == FORMAT_HTML)
03109                   tmpbuf = html_translate(buf);
03110                else
03111                   tmpbuf = buf;
03112                if (tmpbuf) {
03113                   size_t wlen, tlen;
03114                   if ((retval = malloc((wlen = strlen(workspace)) + (tlen = strlen(tmpbuf)) + 128))) {
03115                      strcpy(retval, workspace);
03116                      strcpy(retval + wlen, tmpbuf);
03117                      c = retval + wlen + tlen;
03118                      /* Leftover space for footer, if any */
03119                      len = 120;
03120                   }
03121                }
03122                if (tmpbuf != buf)
03123                   free(tmpbuf);
03124                free(s->outputstr);
03125                s->outputstr = NULL;
03126                munmap(buf, l);
03127             }
03128          }
03129          close(ss.fd);
03130          ss.fd = -1;
03131       } else if (s->outputstr) {
03132          char *tmp;
03133          if (format == FORMAT_XML)
03134             tmp = xml_translate(s->outputstr->str, params);
03135          else if (format == FORMAT_HTML)
03136             tmp = html_translate(s->outputstr->str);
03137          else
03138             tmp = s->outputstr->str;
03139          if (tmp) {
03140             retval = malloc(strlen(workspace) + strlen(tmp) + 128);
03141             if (retval) {
03142                strcpy(retval, workspace);
03143                strcpy(retval + strlen(retval), tmp);
03144                c = retval + strlen(retval);
03145                len = 120;
03146             }
03147          }
03148          if (tmp != s->outputstr->str)
03149             free(tmp);
03150          free(s->outputstr);
03151          s->outputstr = NULL;
03152       }
03153       ast_mutex_unlock(&s->__lock);
03154       /* Still okay because c would safely be pointing to workspace even
03155          if retval failed to allocate above */
03156       if (format == FORMAT_XML) {
03157          ast_build_string(&c, &len, "</ajax-response>\n");
03158       } else if (format == FORMAT_HTML)
03159          ast_build_string(&c, &len, "</table></body>\r\n");
03160    } else {
03161       *status = 500;
03162       *title = strdup("Server Error");
03163    }
03164    ast_mutex_lock(&s->__lock);
03165    if (s->needdestroy) {
03166       if (s->inuse == 1) {
03167          ast_log(LOG_DEBUG, "Need destroy, doing it now!\n");
03168          blastaway = 1;
03169       } else {
03170          ast_log(LOG_DEBUG, "Need destroy, but can't do it yet!\n");
03171          if (s->waiting_thread != AST_PTHREADT_NULL)
03172             pthread_kill(s->waiting_thread, SIGURG);
03173          s->inuse--;
03174       }
03175    } else
03176       s->inuse--;
03177    ast_mutex_unlock(&s->__lock);
03178    
03179    if (blastaway)
03180       destroy_session(s);
03181 generic_callback_out:
03182    if (*status != 200)
03183       return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n"); 
03184    return retval;
03185 }

int init_manager ( void   ) 

Called by Asterisk initialization

Definition at line 3226 of file manager.c.

References accept_thread(), action_command(), action_coresettings(), action_corestatus(), action_events(), action_extensionstate(), action_getconfig(), action_getvar(), action_hangup(), action_listcommands(), action_logoff(), action_mailboxcount(), action_mailboxstatus(), action_originate(), action_ping(), action_redirect(), action_setvar(), action_status(), action_timeout(), action_updateconfig(), action_userevent(), action_waitevent(), append_event(), ast_calloc, ast_category_browse(), ast_cli_register_multiple(), ast_config_destroy(), ast_config_load(), ast_copy_string(), ast_extension_state_add(), ast_get_manager_by_name_locked(), ast_http_uri_link(), ast_http_uri_unlink(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_manager_register, ast_manager_register2(), ast_pthread_create_background, ast_strdup, ast_true(), ast_variable_browse(), ast_variable_retrieve(), ast_verbose(), cli_manager, DEFAULT_MANAGER_PORT, ast_manager_user::deny, ast_manager_user::displayconnects, errno, EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, EVENT_FLAG_CONFIG, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, ast_channel::flags, free, ast_manager_user::keep, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, manager_state_cb(), manageruri, managerxmluri, mandescr_command, mandescr_coresettings, mandescr_corestatus, mandescr_events, mandescr_extensionstate, mandescr_getconfig, mandescr_getvar, mandescr_hangup, mandescr_listcommands, mandescr_logoff, mandescr_mailboxcount, mandescr_mailboxstatus, mandescr_originate, mandescr_ping, mandescr_redirect, mandescr_setvar, mandescr_timeout, mandescr_updateconfig, mandescr_userevent, mandescr_waitevent, ast_variable::name, ast_variable::next, option_verbose, ast_manager_user::permit, rawmanuri, ast_manager_user::read, registered, ast_manager_user::secret, ast_manager_user::username, ast_variable::value, var, webregged, and ast_manager_user::write.

Referenced by main(), and reload_manager().

03227 {
03228    struct ast_config *cfg = NULL, *ucfg = NULL;
03229    const char *val;
03230    char *cat = NULL;
03231    int oldportno = portno;
03232    static struct sockaddr_in ba;
03233    int x = 1;
03234    int flags;
03235    int webenabled = DEFAULT_WEBENABLED;
03236    int newhttptimeout = DEFAULT_HTTPTIMEOUT;
03237    struct ast_manager_user *user = NULL;
03238 
03239    if (!registered) {
03240       /* Register default actions */
03241       ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
03242       ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
03243       ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
03244       ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
03245       ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
03246       ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
03247       ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
03248       ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
03249       ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
03250       ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
03251       ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
03252       ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
03253       ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
03254       ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
03255       ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
03256       ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
03257       ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
03258       ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent);
03259       ast_manager_register2("CoreSettings", EVENT_FLAG_SYSTEM, action_coresettings, "Show PBX core settings (version etc)", mandescr_coresettings);
03260       ast_manager_register2("CoreStatus", EVENT_FLAG_SYSTEM, action_corestatus, "Show PBX core status variables", mandescr_corestatus);
03261       ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent);
03262 
03263       ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry));
03264       ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
03265       registered = 1;
03266       /* Append placeholder event so master_eventq never runs dry */
03267       append_event("Event: Placeholder\r\n\r\n", 0);
03268    }
03269 
03270    portno = DEFAULT_MANAGER_PORT;
03271    displayconnects = DEFAULT_DISPLAYCONNECTS;
03272    broken_events_action = DEFAULT_BROKENEVENTSACTION;
03273    block_sockets = DEFAULT_BLOCKSOCKETS;
03274    timestampevents = DEFAULT_TIMESTAMPEVENTS;
03275    httptimeout = DEFAULT_HTTPTIMEOUT;
03276    authtimeout = DEFAULT_AUTHTIMEOUT;
03277    authlimit = DEFAULT_AUTHLIMIT;
03278 
03279    cfg = ast_config_load("manager.conf");
03280    if (!cfg) {
03281       ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf.  Call management disabled.\n");
03282       return 0;
03283    }
03284    if ((val = ast_variable_retrieve(cfg, "general", "enabled"))) {
03285       manager_enabled = ast_true(val);
03286    }
03287    if ((val = ast_variable_retrieve(cfg, "general", "block-sockets"))) {
03288       block_sockets = ast_true(val);
03289    }
03290    if((val = ast_variable_retrieve(cfg, "general", "webenabled"))) {
03291       webmanager_enabled = ast_true(val);
03292    }
03293    if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
03294       if (sscanf(val, "%5d", &portno) != 1) {
03295          ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
03296          portno = DEFAULT_MANAGER_PORT;
03297       }
03298    }
03299 
03300    if ((val = ast_variable_retrieve(cfg, "general", "displayconnects")))
03301       displayconnects = ast_true(val);
03302 
03303    if ((val = ast_variable_retrieve(cfg, "general", "brokeneventsaction")))
03304       broken_events_action = ast_true(val);
03305 
03306    if ((val = ast_variable_retrieve(cfg, "general", "timestampevents")))
03307       timestampevents = ast_true(val);
03308 
03309    if ((val = ast_variable_retrieve(cfg, "general", "httptimeout")))
03310       newhttptimeout = atoi(val);
03311 
03312    if ((val = ast_variable_retrieve(cfg, "general", "authtimeout"))) {
03313       int timeout = atoi(val);
03314 
03315       if (timeout < 1) {
03316          ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", val);
03317       } else {
03318          authtimeout = timeout;
03319       }
03320    }
03321 
03322    if ((val = ast_variable_retrieve(cfg, "general", "authlimit"))) {
03323       int limit = atoi(val);
03324 
03325       if (limit < 1) {
03326          ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", val);
03327       } else {
03328          authlimit = limit;
03329       }
03330    }
03331 
03332    memset(&ba, 0, sizeof(ba));
03333    ba.sin_family = AF_INET;
03334    ba.sin_port = htons(portno);
03335 
03336    if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
03337       if (!inet_aton(val, &ba.sin_addr)) { 
03338          ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
03339          memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
03340       }
03341    }
03342    
03343 
03344    if ((asock > -1) && ((portno != oldportno) || !manager_enabled)) {
03345 #if 0
03346       /* Can't be done yet */
03347       close(asock);
03348       asock = -1;
03349 #else
03350       ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
03351 #endif
03352    }
03353 
03354    AST_LIST_LOCK(&users);
03355 
03356    if ((ucfg = ast_config_load("users.conf"))) {
03357       while ((cat = ast_category_browse(ucfg, cat))) {
03358          int hasmanager = 0;
03359          struct ast_variable *var = NULL;
03360 
03361          if (!strcasecmp(cat, "general")) {
03362             continue;
03363          }
03364 
03365          if (!(hasmanager = ast_true(ast_variable_retrieve(ucfg, cat, "hasmanager")))) {
03366             continue;
03367          }
03368 
03369          /* Look for an existing entry, if none found - create one and add it to the list */
03370          if (!(user = ast_get_manager_by_name_locked(cat))) {
03371             if (!(user = ast_calloc(1, sizeof(*user)))) {
03372                break;
03373             }
03374             /* Copy name over */
03375             ast_copy_string(user->username, cat, sizeof(user->username));
03376             /* Insert into list */
03377             AST_LIST_INSERT_TAIL(&users, user, list);
03378          }
03379 
03380          /* Make sure we keep this user and don't destroy it during cleanup */
03381          user->keep = 1;
03382 
03383          for (var = ast_variable_browse(ucfg, cat); var; var = var->next) {
03384             if (!strcasecmp(var->name, "secret")) {
03385                if (user->secret) {
03386                   free(user->secret);
03387                }
03388                user->secret = ast_strdup(var->value);
03389             } else if (!strcasecmp(var->name, "deny") ) {
03390                if (user->deny) {
03391                   free(user->deny);
03392                }
03393                user->deny = ast_strdup(var->value);
03394             } else if (!strcasecmp(var->name, "permit") ) {
03395                if (user->permit) {
03396                   free(user->permit);
03397                }
03398                user->permit = ast_strdup(var->value);
03399             } else if (!strcasecmp(var->name, "read") ) {
03400                if (user->read) {
03401                   free(user->read);
03402                }
03403                user->read = ast_strdup(var->value);
03404             } else if (!strcasecmp(var->name, "write") ) {
03405                if (user->write) {
03406                   free(user->write);
03407                }
03408                user->write = ast_strdup(var->value);
03409             } else if (!strcasecmp(var->name, "displayconnects") ) {
03410                user->displayconnects = ast_true(var->value);
03411             } else if (!strcasecmp(var->name, "hasmanager")) {
03412                /* already handled */
03413             } else {
03414                ast_log(LOG_DEBUG, "%s is an unknown option (to the manager module).\n", var->name);
03415             }
03416          }
03417       }
03418       ast_config_destroy(ucfg);
03419    }
03420 
03421    while ((cat = ast_category_browse(cfg, cat))) {
03422       struct ast_variable *var = NULL;
03423 
03424       if (!strcasecmp(cat, "general"))
03425          continue;
03426 
03427       /* Look for an existing entry, if none found - create one and add it to the list */
03428       if (!(user = ast_get_manager_by_name_locked(cat))) {
03429          if (!(user = ast_calloc(1, sizeof(*user))))
03430             break;
03431          /* Copy name over */
03432          ast_copy_string(user->username, cat, sizeof(user->username));
03433          /* Insert into list */
03434          AST_LIST_INSERT_TAIL(&users, user, list);
03435       }
03436 
03437       /* Make sure we keep this user and don't destroy it during cleanup */
03438       user->keep = 1;
03439 
03440       var = ast_variable_browse(cfg, cat);
03441       while (var) {
03442          if (!strcasecmp(var->name, "secret")) {
03443             if (user->secret)
03444                free(user->secret);
03445             user->secret = ast_strdup(var->value);
03446          } else if (!strcasecmp(var->name, "deny") ) {
03447             if (user->deny)
03448                free(user->deny);
03449             user->deny = ast_strdup(var->value);
03450          } else if (!strcasecmp(var->name, "permit") ) {
03451             if (user->permit)
03452                free(user->permit);
03453             user->permit = ast_strdup(var->value);
03454          }  else if (!strcasecmp(var->name, "read") ) {
03455             if (user->read)
03456                free(user->read);
03457             user->read = ast_strdup(var->value);
03458          }  else if (!strcasecmp(var->name, "write") ) {
03459             if (user->write)
03460                free(user->write);
03461             user->write = ast_strdup(var->value);
03462          }  else if (!strcasecmp(var->name, "displayconnects") )
03463             user->displayconnects = ast_true(var->value);
03464          else
03465             ast_log(LOG_DEBUG, "%s is an unknown option.\n", var->name);
03466          var = var->next;
03467       }
03468    }
03469 
03470    /* Perform cleanup - essentially prune out old users that no longer exist */
03471    AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
03472       if (user->keep) {
03473          user->keep = 0;
03474          continue;
03475       }
03476       /* We do not need to keep this user so take them out of the list */
03477       AST_LIST_REMOVE_CURRENT(&users, list);
03478       /* Free their memory now */
03479       if (user->secret)
03480          free(user->secret);
03481       if (user->deny)
03482          free(user->deny);
03483       if (user->permit)
03484          free(user->permit);
03485       if (user->read)
03486          free(user->read);
03487       if (user->write)
03488          free(user->write);
03489       free(user);
03490    }
03491    AST_LIST_TRAVERSE_SAFE_END
03492 
03493    AST_LIST_UNLOCK(&users);
03494 
03495    ast_config_destroy(cfg);
03496    
03497    if (webmanager_enabled && manager_enabled) {
03498       if (!webregged) {
03499          ast_http_uri_link(&rawmanuri);
03500          ast_http_uri_link(&manageruri);
03501          ast_http_uri_link(&managerxmluri);
03502          webregged = 1;
03503       }
03504    } else {
03505       if (webregged) {
03506          ast_http_uri_unlink(&rawmanuri);
03507          ast_http_uri_unlink(&manageruri);
03508          ast_http_uri_unlink(&managerxmluri);
03509          webregged = 0;
03510       }
03511    }
03512 
03513    if (newhttptimeout > 0)
03514       httptimeout = newhttptimeout;
03515 
03516    /* If not enabled, do nothing */
03517    if (!manager_enabled)
03518       return 0;
03519 
03520    if (asock < 0) {
03521       asock = socket(AF_INET, SOCK_STREAM, 0);
03522       if (asock < 0) {
03523          ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
03524          return -1;
03525       }
03526       setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
03527       if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
03528          ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
03529          close(asock);
03530          asock = -1;
03531          return -1;
03532       }
03533       if (listen(asock, 2)) {
03534          ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
03535          close(asock);
03536          asock = -1;
03537          return -1;
03538       }
03539       flags = fcntl(asock, F_GETFL);
03540       fcntl(asock, F_SETFL, flags | O_NONBLOCK);
03541       if (option_verbose)
03542          ast_verbose("Asterisk Management interface listening on port %d\n", portno);
03543       ast_pthread_create_background(&t, NULL, accept_thread, NULL);
03544    }
03545    return 0;
03546 }

static char* manager_http_callback ( struct sockaddr_in *  requestor,
const char *  uri,
struct ast_variable params,
int *  status,
char **  title,
int *  contentlength 
) [static]

Definition at line 3187 of file manager.c.

References FORMAT_HTML, and generic_http_callback().

03188 {
03189    return generic_http_callback(FORMAT_HTML, requestor, uri, params, status, title, contentlength);
03190 }

static char* mxml_http_callback ( struct sockaddr_in *  requestor,
const char *  uri,
struct ast_variable params,
int *  status,
char **  title,
int *  contentlength 
) [static]

Definition at line 3192 of file manager.c.

References FORMAT_XML, and generic_http_callback().

03193 {
03194    return generic_http_callback(FORMAT_XML, requestor, uri, params, status, title, contentlength);
03195 }

static char* rawman_http_callback ( struct sockaddr_in *  requestor,
const char *  uri,
struct ast_variable params,
int *  status,
char **  title,
int *  contentlength 
) [static]

Definition at line 3197 of file manager.c.

References FORMAT_RAW, and generic_http_callback().

03198 {
03199    return generic_http_callback(FORMAT_RAW, requestor, uri, params, status, title, contentlength);
03200 }

int reload_manager ( void   ) 

Definition at line 3548 of file manager.c.

References EVENT_FLAG_SYSTEM, init_manager(), and manager_event().

03549 {
03550    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
03551    return init_manager();
03552 }


Variable Documentation

char* contenttype[] = { "plain", "html", "xml" } [static]

Definition at line 2981 of file manager.c.

Referenced by generic_http_callback().

Definition at line 3209 of file manager.c.

Referenced by init_manager().

Definition at line 3216 of file manager.c.

Referenced by init_manager().

Definition at line 3202 of file manager.c.

Referenced by init_manager().

int registered = 0 [static]

Definition at line 3223 of file manager.c.

Referenced by init_manager().

int webregged = 0 [static]

Definition at line 3224 of file manager.c.

Referenced by init_manager().

char* words[AST_MAX_CMD_LEN]

Definition at line 156 of file manager.c.

Referenced by check_blacklist().


Generated on 7 Jun 2012 for Asterisk - the Open Source PBX by  doxygen 1.6.1