00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "asterisk.h"
00036
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 323559 $")
00038
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <string.h>
00042 #include <ctype.h>
00043 #include <sys/time.h>
00044 #include <sys/types.h>
00045 #include <netdb.h>
00046 #include <sys/socket.h>
00047 #include <netinet/in.h>
00048 #include <netinet/tcp.h>
00049 #include <arpa/inet.h>
00050 #include <signal.h>
00051 #include <errno.h>
00052 #include <unistd.h>
00053 #include <sys/mman.h>
00054
00055 #include "asterisk/version.h"
00056 #include "asterisk/channel.h"
00057 #include "asterisk/file.h"
00058 #include "asterisk/manager.h"
00059 #include "asterisk/config.h"
00060 #include "asterisk/callerid.h"
00061 #include "asterisk/lock.h"
00062 #include "asterisk/logger.h"
00063 #include "asterisk/options.h"
00064 #include "asterisk/cli.h"
00065 #include "asterisk/app.h"
00066 #include "asterisk/pbx.h"
00067 #include "asterisk/md5.h"
00068 #include "asterisk/acl.h"
00069 #include "asterisk/utils.h"
00070 #include "asterisk/http.h"
00071 #include "asterisk/threadstorage.h"
00072 #include "asterisk/linkedlists.h"
00073 #include "asterisk/term.h"
00074 #include "asterisk/astobj2.h"
00075
00076 struct fast_originate_helper {
00077 char tech[AST_MAX_EXTENSION];
00078
00079 char data[512];
00080 int timeout;
00081 int format;
00082 char app[AST_MAX_APP];
00083 char appdata[AST_MAX_EXTENSION];
00084 char cid_name[AST_MAX_EXTENSION];
00085 char cid_num[AST_MAX_EXTENSION];
00086 char context[AST_MAX_CONTEXT];
00087 char exten[AST_MAX_EXTENSION];
00088 char idtext[AST_MAX_EXTENSION];
00089 char account[AST_MAX_ACCOUNT_CODE];
00090 int priority;
00091 struct ast_variable *vars;
00092 };
00093
00094 struct eventqent {
00095 int usecount;
00096 int category;
00097 struct eventqent *next;
00098 char eventdata[1];
00099 };
00100
00101 static const int DEFAULT_ENABLED = 0;
00102 static const int DEFAULT_WEBENABLED = 0;
00103 static const int DEFAULT_BLOCKSOCKETS = 0;
00104 static const int DEFAULT_DISPLAYCONNECTS = 1;
00105 static const int DEFAULT_TIMESTAMPEVENTS = 0;
00106 static const int DEFAULT_HTTPTIMEOUT = 60;
00107 static const int DEFAULT_BROKENEVENTSACTION = 0;
00108 static const int DEFAULT_AUTHTIMEOUT = 30;
00109 static const int DEFAULT_AUTHLIMIT = 50;
00110
00111
00112 static int manager_enabled = 0;
00113 static int webmanager_enabled = 0;
00114
00115 static int portno = DEFAULT_MANAGER_PORT;
00116 static int asock = -1;
00117 static int displayconnects;
00118 static int timestampevents;
00119 static int httptimeout;
00120 static int broken_events_action;
00121 static int authtimeout;
00122 static int authlimit;
00123
00124 static pthread_t t;
00125 static int block_sockets;
00126 static int num_sessions;
00127 static int unauth_sessions = 0;
00128
00129
00130 struct eventqent *master_eventq = NULL;
00131
00132 AST_THREADSTORAGE(manager_event_buf, manager_event_buf_init);
00133 #define MANAGER_EVENT_BUF_INITSIZE 256
00134
00135 AST_THREADSTORAGE(astman_append_buf, astman_append_buf_init);
00136 #define ASTMAN_APPEND_BUF_INITSIZE 256
00137
00138 static struct permalias {
00139 int num;
00140 char *label;
00141 } perms[] = {
00142 { EVENT_FLAG_SYSTEM, "system" },
00143 { EVENT_FLAG_CALL, "call" },
00144 { EVENT_FLAG_LOG, "log" },
00145 { EVENT_FLAG_VERBOSE, "verbose" },
00146 { EVENT_FLAG_COMMAND, "command" },
00147 { EVENT_FLAG_AGENT, "agent" },
00148 { EVENT_FLAG_USER, "user" },
00149 { EVENT_FLAG_CONFIG, "config" },
00150 { INT_MAX, "all" },
00151 { 0, "none" },
00152 };
00153
00154 #define MAX_BLACKLIST_CMD_LEN 2
00155 static struct {
00156 char *words[AST_MAX_CMD_LEN];
00157 } command_blacklist[] = {
00158 {{ "module", "load", NULL }},
00159 {{ "module", "unload", NULL }},
00160 {{ "restart", "gracefully", NULL }},
00161 };
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 struct mansession_session {
00196
00197 ast_mutex_t __lock;
00198
00199 struct sockaddr_in sin;
00200
00201 int fd;
00202
00203 int inuse;
00204
00205 int needdestroy;
00206
00207 pthread_t waiting_thread;
00208
00209 uint32_t managerid;
00210
00211 time_t sessiontimeout;
00212
00213 struct ast_dynamic_str *outputstr;
00214
00215 char username[80];
00216
00217 char challenge[10];
00218
00219 int authenticated;
00220
00221 int readperm;
00222
00223 int writeperm;
00224
00225 char inbuf[1024];
00226 int inlen;
00227 int send_events;
00228 int displaysystemname;
00229
00230 struct eventqent *eventq;
00231
00232 int writetimeout;
00233 time_t authstart;
00234 int pending_event;
00235 AST_LIST_ENTRY(mansession_session) list;
00236 };
00237
00238
00239
00240
00241
00242
00243 struct mansession {
00244 FILE *f;
00245 struct mansession_session *session;
00246 int fd;
00247 };
00248
00249 static AST_LIST_HEAD_STATIC(sessions, mansession_session);
00250
00251 struct ast_manager_user {
00252 char username[80];
00253 char *secret;
00254 char *deny;
00255 char *permit;
00256 char *read;
00257 char *write;
00258 unsigned int displayconnects:1;
00259 int keep;
00260 AST_LIST_ENTRY(ast_manager_user) list;
00261 };
00262
00263 static AST_LIST_HEAD_STATIC(users, ast_manager_user);
00264
00265 static struct manager_action *first_action;
00266 AST_RWLOCK_DEFINE_STATIC(actionlock);
00267
00268 int check_manager_enabled()
00269 {
00270 return manager_enabled;
00271 }
00272
00273 int check_webmanager_enabled()
00274 {
00275 return (webmanager_enabled && manager_enabled);
00276 }
00277
00278
00279 static char *authority_to_str(int authority, char *res, int reslen)
00280 {
00281 int running_total = 0, i;
00282
00283 memset(res, 0, reslen);
00284 for (i = 0; i < (sizeof(perms) / sizeof(perms[0])) - 1; i++) {
00285 if (authority & perms[i].num) {
00286 if (*res) {
00287 strncat(res, ",", (reslen > running_total) ? reslen - running_total - 1 : 0);
00288 running_total++;
00289 }
00290 strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total - 1 : 0);
00291 running_total += strlen(perms[i].label);
00292 }
00293 }
00294
00295 if (ast_strlen_zero(res))
00296 ast_copy_string(res, "<none>", reslen);
00297
00298 return res;
00299 }
00300
00301 static char *complete_show_mancmd(const char *line, const char *word, int pos, int state)
00302 {
00303 struct manager_action *cur;
00304 int which = 0;
00305 char *ret = NULL;
00306
00307 ast_rwlock_rdlock(&actionlock);
00308 for (cur = first_action; cur; cur = cur->next) {
00309 if (!strncasecmp(word, cur->action, strlen(word)) && ++which > state) {
00310 ret = ast_strdup(cur->action);
00311 break;
00312 }
00313 }
00314 ast_rwlock_unlock(&actionlock);
00315
00316 return ret;
00317 }
00318
00319 static void xml_copy_escape(char **dst, size_t *maxlen, const char *src, int lower)
00320 {
00321 while (*src && (*maxlen > 6)) {
00322 switch (*src) {
00323 case '<':
00324 strcpy(*dst, "<");
00325 (*dst) += 4;
00326 *maxlen -= 4;
00327 break;
00328 case '>':
00329 strcpy(*dst, ">");
00330 (*dst) += 4;
00331 *maxlen -= 4;
00332 break;
00333 case '\"':
00334 strcpy(*dst, """);
00335 (*dst) += 6;
00336 *maxlen -= 6;
00337 break;
00338 case '\'':
00339 strcpy(*dst, "'");
00340 (*dst) += 6;
00341 *maxlen -= 6;
00342 break;
00343 case '&':
00344 strcpy(*dst, "&");
00345 (*dst) += 5;
00346 *maxlen -= 5;
00347 break;
00348 default:
00349 *(*dst)++ = lower ? tolower(*src) : *src;
00350 (*maxlen)--;
00351 }
00352 src++;
00353 }
00354 }
00355
00356 struct variable_count {
00357 char *varname;
00358 int count;
00359 };
00360
00361 static int compress_char(char c)
00362 {
00363 c &= 0x7f;
00364 if (c < 32)
00365 return 0;
00366 else if (c >= 'a' && c <= 'z')
00367 return c - 64;
00368 else if (c > 'z')
00369 return '_';
00370 else
00371 return c - 32;
00372 }
00373
00374 static int variable_count_hash_fn(const void *vvc, const int flags)
00375 {
00376 const struct variable_count *vc = vvc;
00377 int res = 0, i;
00378 for (i = 0; i < 5; i++) {
00379 if (vc->varname[i] == '\0')
00380 break;
00381 res += compress_char(vc->varname[i]) << (i * 6);
00382 }
00383 return res;
00384 }
00385
00386 static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
00387 {
00388
00389
00390
00391
00392 struct variable_count *vc = obj;
00393 char *str = vstr;
00394 return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
00395 }
00396
00397 static char *xml_translate(char *in, struct ast_variable *vars)
00398 {
00399 struct ast_variable *v;
00400 char *dest = NULL;
00401 char *out, *tmp, *var, *val;
00402 char *objtype = NULL;
00403 int colons = 0;
00404 int breaks = 0;
00405 size_t len;
00406 int count = 1;
00407 int escaped = 0;
00408 int inobj = 0;
00409 int x;
00410 struct variable_count *vc = NULL;
00411 struct ao2_container *vco = NULL;
00412
00413 for (v = vars; v; v = v->next) {
00414 if (!dest && !strcasecmp(v->name, "ajaxdest"))
00415 dest = v->value;
00416 else if (!objtype && !strcasecmp(v->name, "ajaxobjtype"))
00417 objtype = v->value;
00418 }
00419 if (!dest)
00420 dest = "unknown";
00421 if (!objtype)
00422 objtype = "generic";
00423 for (x = 0; in[x]; x++) {
00424 if (in[x] == ':')
00425 colons++;
00426 else if (in[x] == '\n')
00427 breaks++;
00428 else if (strchr("&\"<>\'", in[x]))
00429 escaped++;
00430 }
00431 len = (size_t) (strlen(in) + colons * 5 + breaks * (40 + strlen(dest) + strlen(objtype)) + escaped * 10);
00432 out = ast_malloc(len);
00433 if (!out)
00434 return 0;
00435 tmp = out;
00436 while (*in) {
00437 var = in;
00438 while (*in && (*in >= 32))
00439 in++;
00440 if (*in) {
00441 if ((count > 3) && inobj) {
00442 ast_build_string(&tmp, &len, " /></response>\n");
00443 inobj = 0;
00444
00445
00446 ao2_ref(vco, -1);
00447 vco = NULL;
00448 }
00449 count = 0;
00450 while (*in && (*in < 32)) {
00451 *in = '\0';
00452 in++;
00453 count++;
00454 }
00455 val = strchr(var, ':');
00456 if (val) {
00457 *val = '\0';
00458 val++;
00459 if (*val == ' ')
00460 val++;
00461 if (!inobj) {
00462 vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
00463 ast_build_string(&tmp, &len, "<response type='object' id='%s'><%s", dest, objtype);
00464 inobj = 1;
00465 }
00466
00467
00468 if ((vc = ao2_find(vco, var, 0)))
00469 vc->count++;
00470 else {
00471
00472 vc = ao2_alloc(sizeof(*vc), NULL);
00473 vc->varname = var;
00474 vc->count = 1;
00475 ao2_link(vco, vc);
00476 }
00477
00478 ast_build_string(&tmp, &len, " ");
00479 xml_copy_escape(&tmp, &len, var, 1);
00480 if (vc->count > 1)
00481 ast_build_string(&tmp, &len, "-%d", vc->count);
00482 ast_build_string(&tmp, &len, "='");
00483 xml_copy_escape(&tmp, &len, val, 0);
00484 ast_build_string(&tmp, &len, "'");
00485 ao2_ref(vc, -1);
00486 }
00487 }
00488 }
00489 if (inobj)
00490 ast_build_string(&tmp, &len, " /></response>\n");
00491 if (vco)
00492 ao2_ref(vco, -1);
00493 return out;
00494 }
00495
00496 static char *html_translate(char *in)
00497 {
00498 int x;
00499 int colons = 0;
00500 int breaks = 0;
00501 size_t len;
00502 int count = 1;
00503 char *tmp, *var, *val, *out;
00504
00505 for (x=0; in[x]; x++) {
00506 if (in[x] == ':')
00507 colons++;
00508 if (in[x] == '\n')
00509 breaks++;
00510 }
00511 len = strlen(in) + colons * 40 + breaks * 40;
00512 out = ast_malloc(len);
00513 if (!out)
00514 return 0;
00515 tmp = out;
00516 while (*in) {
00517 var = in;
00518 while (*in && (*in >= 32))
00519 in++;
00520 if (*in) {
00521 if ((count % 4) == 0){
00522 ast_build_string(&tmp, &len, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00523 }
00524 count = 0;
00525 while (*in && (*in < 32)) {
00526 *in = '\0';
00527 in++;
00528 count++;
00529 }
00530 val = strchr(var, ':');
00531 if (val) {
00532 *val = '\0';
00533 val++;
00534 if (*val == ' ')
00535 val++;
00536 ast_build_string(&tmp, &len, "<tr><td>%s</td><td>%s</td></tr>\r\n", var, val);
00537 }
00538 }
00539 }
00540 return out;
00541 }
00542
00543
00544
00545 static struct ast_manager_user *ast_get_manager_by_name_locked(const char *name)
00546 {
00547 struct ast_manager_user *user = NULL;
00548
00549 AST_LIST_TRAVERSE(&users, user, list)
00550 if (!strcasecmp(user->username, name))
00551 break;
00552 return user;
00553 }
00554
00555 void astman_append(struct mansession *s, const char *fmt, ...)
00556 {
00557 va_list ap;
00558 struct ast_dynamic_str *buf;
00559
00560 ast_mutex_lock(&s->session->__lock);
00561
00562 if (!(buf = ast_dynamic_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
00563 ast_mutex_unlock(&s->session->__lock);
00564 return;
00565 }
00566
00567 va_start(ap, fmt);
00568 ast_dynamic_str_thread_set_va(&buf, 0, &astman_append_buf, fmt, ap);
00569 va_end(ap);
00570
00571 if (s->fd > -1)
00572 ast_carefulwrite(s->fd, buf->str, strlen(buf->str), s->session->writetimeout);
00573 else {
00574 if (!s->session->outputstr && !(s->session->outputstr = ast_calloc(1, sizeof(*s->session->outputstr)))) {
00575 ast_mutex_unlock(&s->session->__lock);
00576 return;
00577 }
00578
00579 ast_dynamic_str_append(&s->session->outputstr, 0, "%s", buf->str);
00580 }
00581
00582 ast_mutex_unlock(&s->session->__lock);
00583 }
00584
00585 static int handle_showmancmd(int fd, int argc, char *argv[])
00586 {
00587 struct manager_action *cur;
00588 char authority[80];
00589 int num;
00590
00591 if (argc != 4)
00592 return RESULT_SHOWUSAGE;
00593
00594 ast_rwlock_rdlock(&actionlock);
00595 for (cur = first_action; cur; cur = cur->next) {
00596 for (num = 3; num < argc; num++) {
00597 if (!strcasecmp(cur->action, argv[num])) {
00598 ast_cli(fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n", cur->action, cur->synopsis, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->description ? cur->description : "");
00599 }
00600 }
00601 }
00602 ast_rwlock_unlock(&actionlock);
00603
00604 return RESULT_SUCCESS;
00605 }
00606
00607 static int handle_showmanager(int fd, int argc, char *argv[])
00608 {
00609 struct ast_manager_user *user = NULL;
00610
00611 if (argc != 4)
00612 return RESULT_SHOWUSAGE;
00613
00614 AST_LIST_LOCK(&users);
00615
00616 if (!(user = ast_get_manager_by_name_locked(argv[3]))) {
00617 ast_cli(fd, "There is no manager called %s\n", argv[3]);
00618 AST_LIST_UNLOCK(&users);
00619 return -1;
00620 }
00621
00622 ast_cli(fd,"\n");
00623 ast_cli(fd,
00624 " username: %s\n"
00625 " secret: %s\n"
00626 " deny: %s\n"
00627 " permit: %s\n"
00628 " read: %s\n"
00629 " write: %s\n"
00630 "displayconnects: %s\n",
00631 (user->username ? user->username : "(N/A)"),
00632 (user->secret ? "<Set>" : "(N/A)"),
00633 (user->deny ? user->deny : "(N/A)"),
00634 (user->permit ? user->permit : "(N/A)"),
00635 (user->read ? user->read : "(N/A)"),
00636 (user->write ? user->write : "(N/A)"),
00637 (user->displayconnects ? "yes" : "no"));
00638
00639 AST_LIST_UNLOCK(&users);
00640
00641 return RESULT_SUCCESS;
00642 }
00643
00644
00645 static int handle_showmanagers(int fd, int argc, char *argv[])
00646 {
00647 struct ast_manager_user *user = NULL;
00648 int count_amu = 0;
00649
00650 if (argc != 3)
00651 return RESULT_SHOWUSAGE;
00652
00653 AST_LIST_LOCK(&users);
00654
00655
00656 if (AST_LIST_EMPTY(&users)) {
00657 ast_cli(fd, "There are no manager users.\n");
00658 AST_LIST_UNLOCK(&users);
00659 return RESULT_SUCCESS;
00660 }
00661
00662 ast_cli(fd, "\nusername\n--------\n");
00663
00664 AST_LIST_TRAVERSE(&users, user, list) {
00665 ast_cli(fd, "%s\n", user->username);
00666 count_amu++;
00667 }
00668
00669 AST_LIST_UNLOCK(&users);
00670
00671 ast_cli(fd,"-------------------\n");
00672 ast_cli(fd,"%d manager users configured.\n", count_amu);
00673
00674 return RESULT_SUCCESS;
00675 }
00676
00677
00678
00679
00680 static int handle_showmancmds(int fd, int argc, char *argv[])
00681 {
00682 struct manager_action *cur;
00683 char authority[80];
00684 char *format = " %-15.15s %-15.15s %-55.55s\n";
00685
00686 ast_cli(fd, format, "Action", "Privilege", "Synopsis");
00687 ast_cli(fd, format, "------", "---------", "--------");
00688
00689 ast_rwlock_rdlock(&actionlock);
00690 for (cur = first_action; cur; cur = cur->next)
00691 ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
00692 ast_rwlock_unlock(&actionlock);
00693
00694 return RESULT_SUCCESS;
00695 }
00696
00697
00698
00699 static int handle_showmanconn(int fd, int argc, char *argv[])
00700 {
00701 struct mansession_session *s;
00702 char wtout[32];
00703 char *format = " %-15.15s %-15.15s %-15.15s\n";
00704
00705 ast_cli(fd, format, "Username", "IP Address", "Timeout");
00706
00707 AST_LIST_LOCK(&sessions);
00708 AST_LIST_TRAVERSE(&sessions, s, list) {
00709 memset(wtout, 0, sizeof(wtout));
00710 snprintf(wtout, sizeof(wtout)-1, "%d", s->writetimeout);
00711 ast_cli(fd, format,s->username, ast_inet_ntoa(s->sin.sin_addr), wtout);
00712 }
00713 AST_LIST_UNLOCK(&sessions);
00714
00715 return RESULT_SUCCESS;
00716 }
00717
00718
00719
00720 static int handle_showmaneventq(int fd, int argc, char *argv[])
00721 {
00722 struct eventqent *s;
00723
00724 AST_LIST_LOCK(&sessions);
00725 for (s = master_eventq; s; s = s->next) {
00726 ast_cli(fd, "Usecount: %d\n",s->usecount);
00727 ast_cli(fd, "Category: %d\n", s->category);
00728 ast_cli(fd, "Event:\n%s", s->eventdata);
00729 }
00730 AST_LIST_UNLOCK(&sessions);
00731
00732 return RESULT_SUCCESS;
00733 }
00734
00735 static char showmancmd_help[] =
00736 "Usage: manager show command <actionname>\n"
00737 " Shows the detailed description for a specific Asterisk manager interface command.\n";
00738
00739 static char showmancmds_help[] =
00740 "Usage: manager show commands\n"
00741 " Prints a listing of all the available Asterisk manager interface commands.\n";
00742
00743 static char showmanconn_help[] =
00744 "Usage: manager show connected\n"
00745 " Prints a listing of the users that are currently connected to the\n"
00746 "Asterisk manager interface.\n";
00747
00748 static char showmaneventq_help[] =
00749 "Usage: manager show eventq\n"
00750 " Prints a listing of all events pending in the Asterisk manger\n"
00751 "event queue.\n";
00752
00753 static char showmanagers_help[] =
00754 "Usage: manager show users\n"
00755 " Prints a listing of all managers that are currently configured on that\n"
00756 " system.\n";
00757
00758 static char showmanager_help[] =
00759 " Usage: manager show user <user>\n"
00760 " Display all information related to the manager user specified.\n";
00761
00762 static struct ast_cli_entry cli_show_manager_command_deprecated = {
00763 { "show", "manager", "command", NULL },
00764 handle_showmancmd, NULL,
00765 NULL, complete_show_mancmd };
00766
00767 static struct ast_cli_entry cli_show_manager_commands_deprecated = {
00768 { "show", "manager", "commands", NULL },
00769 handle_showmancmds, NULL,
00770 NULL };
00771
00772 static struct ast_cli_entry cli_show_manager_connected_deprecated = {
00773 { "show", "manager", "connected", NULL },
00774 handle_showmanconn, NULL,
00775 NULL };
00776
00777 static struct ast_cli_entry cli_show_manager_eventq_deprecated = {
00778 { "show", "manager", "eventq", NULL },
00779 handle_showmaneventq, NULL,
00780 NULL };
00781
00782 static struct ast_cli_entry cli_manager[] = {
00783 { { "manager", "show", "command", NULL },
00784 handle_showmancmd, "Show a manager interface command",
00785 showmancmd_help, complete_show_mancmd, &cli_show_manager_command_deprecated },
00786
00787 { { "manager", "show", "commands", NULL },
00788 handle_showmancmds, "List manager interface commands",
00789 showmancmds_help, NULL, &cli_show_manager_commands_deprecated },
00790
00791 { { "manager", "show", "connected", NULL },
00792 handle_showmanconn, "List connected manager interface users",
00793 showmanconn_help, NULL, &cli_show_manager_connected_deprecated },
00794
00795 { { "manager", "show", "eventq", NULL },
00796 handle_showmaneventq, "List manager interface queued events",
00797 showmaneventq_help, NULL, &cli_show_manager_eventq_deprecated },
00798
00799 { { "manager", "show", "users", NULL },
00800 handle_showmanagers, "List configured manager users",
00801 showmanagers_help, NULL, NULL },
00802
00803 { { "manager", "show", "user", NULL },
00804 handle_showmanager, "Display information on a specific manager user",
00805 showmanager_help, NULL, NULL },
00806 };
00807
00808 static void unuse_eventqent(struct eventqent *e)
00809 {
00810 struct eventqent *next = e->next;
00811 if (ast_atomic_dec_and_test(&e->usecount) && next)
00812 pthread_kill(t, SIGURG);
00813 }
00814
00815 static void free_session(struct mansession_session *s)
00816 {
00817 struct eventqent *eqe;
00818 if (s->fd > -1)
00819 close(s->fd);
00820 if (s->outputstr)
00821 free(s->outputstr);
00822 ast_mutex_destroy(&s->__lock);
00823 while (s->eventq) {
00824 eqe = s->eventq;
00825 s->eventq = s->eventq->next;
00826 unuse_eventqent(eqe);
00827 }
00828 free(s);
00829 }
00830
00831 static void destroy_session(struct mansession_session *s)
00832 {
00833 AST_LIST_LOCK(&sessions);
00834 AST_LIST_REMOVE(&sessions, s, list);
00835 num_sessions--;
00836 free_session(s);
00837 AST_LIST_UNLOCK(&sessions);
00838 }
00839
00840 const char *astman_get_header(const struct message *m, char *var)
00841 {
00842 char cmp[80];
00843 int x;
00844
00845 snprintf(cmp, sizeof(cmp), "%s: ", var);
00846
00847 for (x = 0; x < m->hdrcount; x++) {
00848 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
00849 return m->headers[x] + strlen(cmp);
00850 }
00851
00852 return "";
00853 }
00854
00855 struct ast_variable *astman_get_variables(const struct message *m)
00856 {
00857 int varlen, x, y;
00858 struct ast_variable *head = NULL, *cur;
00859 char *var, *val;
00860
00861 char *parse;
00862 AST_DECLARE_APP_ARGS(args,
00863 AST_APP_ARG(vars)[32];
00864 );
00865
00866 varlen = strlen("Variable: ");
00867
00868 for (x = 0; x < m->hdrcount; x++) {
00869 if (strncasecmp("Variable: ", m->headers[x], varlen))
00870 continue;
00871
00872 parse = ast_strdupa(m->headers[x] + varlen);
00873
00874 AST_STANDARD_APP_ARGS(args, parse);
00875 if (args.argc) {
00876 for (y = 0; y < args.argc; y++) {
00877 if (!args.vars[y])
00878 continue;
00879 var = val = ast_strdupa(args.vars[y]);
00880 strsep(&val, "=");
00881 if (!val || ast_strlen_zero(var))
00882 continue;
00883 cur = ast_variable_new(var, val);
00884 if (head) {
00885 cur->next = head;
00886 head = cur;
00887 } else
00888 head = cur;
00889 }
00890 }
00891 }
00892
00893 return head;
00894 }
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904 void astman_send_error(struct mansession *s, const struct message *m, char *error)
00905 {
00906 const char *id = astman_get_header(m,"ActionID");
00907
00908 astman_append(s, "Response: Error\r\n");
00909 if (!ast_strlen_zero(id))
00910 astman_append(s, "ActionID: %s\r\n", id);
00911 astman_append(s, "Message: %s\r\n\r\n", error);
00912 }
00913
00914 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
00915 {
00916 const char *id = astman_get_header(m,"ActionID");
00917
00918 astman_append(s, "Response: %s\r\n", resp);
00919 if (!ast_strlen_zero(id))
00920 astman_append(s, "ActionID: %s\r\n", id);
00921 if (msg)
00922 astman_append(s, "Message: %s\r\n\r\n", msg);
00923 else
00924 astman_append(s, "\r\n");
00925 }
00926
00927 void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
00928 {
00929 astman_send_response(s, m, "Success", msg);
00930 }
00931
00932
00933
00934
00935
00936
00937 static int ast_instring(const char *bigstr, const char *smallstr, char delim)
00938 {
00939 const char *val = bigstr, *next;
00940
00941 do {
00942 if ((next = strchr(val, delim))) {
00943 if (!strncmp(val, smallstr, (next - val)))
00944 return 1;
00945 else
00946 continue;
00947 } else
00948 return !strcmp(smallstr, val);
00949
00950 } while (*(val = (next + 1)));
00951
00952 return 0;
00953 }
00954
00955 static int get_perm(const char *instr)
00956 {
00957 int x = 0, ret = 0;
00958
00959 if (!instr)
00960 return 0;
00961
00962 for (x = 0; x < (sizeof(perms) / sizeof(perms[0])); x++) {
00963 if (ast_instring(instr, perms[x].label, ','))
00964 ret |= perms[x].num;
00965 }
00966
00967 return ret;
00968 }
00969
00970 static int ast_is_number(const char *string)
00971 {
00972 int ret = 1, x = 0;
00973
00974 if (!string)
00975 return 0;
00976
00977 for (x = 0; x < strlen(string); x++) {
00978 if (!(string[x] >= 48 && string[x] <= 57)) {
00979 ret = 0;
00980 break;
00981 }
00982 }
00983
00984 return ret ? atoi(string) : 0;
00985 }
00986
00987 static int strings_to_mask(const char *string)
00988 {
00989 int x, ret = -1;
00990
00991 x = ast_is_number(string);
00992
00993 if (x)
00994 ret = x;
00995 else if (ast_strlen_zero(string))
00996 ret = -1;
00997 else if (ast_false(string))
00998 ret = 0;
00999 else if (ast_true(string)) {
01000 ret = 0;
01001 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
01002 ret |= perms[x].num;
01003 } else {
01004 ret = 0;
01005 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
01006 if (ast_instring(string, perms[x].label, ','))
01007 ret |= perms[x].num;
01008 }
01009 }
01010
01011 return ret;
01012 }
01013
01014
01015
01016
01017
01018 static int set_eventmask(struct mansession_session *s, const char *eventmask)
01019 {
01020 int maskint = strings_to_mask(eventmask);
01021
01022 ast_mutex_lock(&s->__lock);
01023 if (maskint >= 0)
01024 s->send_events = maskint;
01025 ast_mutex_unlock(&s->__lock);
01026
01027 return maskint;
01028 }
01029
01030 static int authenticate(struct mansession *s, const struct message *m)
01031 {
01032 struct ast_config *cfg;
01033 char *cat;
01034 const char *user = astman_get_header(m, "Username");
01035 const char *pass = astman_get_header(m, "Secret");
01036 const char *authtype = astman_get_header(m, "AuthType");
01037 const char *key = astman_get_header(m, "Key");
01038 const char *events = astman_get_header(m, "Events");
01039
01040 cfg = ast_config_load("manager.conf");
01041 if (!cfg)
01042 return -1;
01043 cat = ast_category_browse(cfg, NULL);
01044 while (cat) {
01045 if (strcasecmp(cat, "general")) {
01046
01047 if (!strcasecmp(cat, user)) {
01048 struct ast_variable *v;
01049 struct ast_ha *ha = NULL;
01050 char *password = NULL;
01051
01052 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
01053 if (!strcasecmp(v->name, "secret")) {
01054 password = v->value;
01055 } else if (!strcasecmp(v->name, "displaysystemname")) {
01056 if (ast_true(v->value)) {
01057 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
01058 s->session->displaysystemname = 1;
01059 } else {
01060 ast_log(LOG_ERROR, "Can't enable displaysystemname in manager.conf - no system name configured in asterisk.conf\n");
01061 }
01062 }
01063 } else if (!strcasecmp(v->name, "permit") ||
01064 !strcasecmp(v->name, "deny")) {
01065 ha = ast_append_ha(v->name, v->value, ha);
01066 } else if (!strcasecmp(v->name, "writetimeout")) {
01067 int val = atoi(v->value);
01068
01069 if (val < 100)
01070 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
01071 else
01072 s->session->writetimeout = val;
01073 }
01074
01075 }
01076 if (ha && !ast_apply_ha(ha, &(s->session->sin))) {
01077 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), user);
01078 ast_free_ha(ha);
01079 ast_config_destroy(cfg);
01080 return -1;
01081 } else if (ha)
01082 ast_free_ha(ha);
01083 if (!strcasecmp(authtype, "MD5")) {
01084 if (!ast_strlen_zero(key) &&
01085 !ast_strlen_zero(s->session->challenge) && !ast_strlen_zero(password)) {
01086 int x;
01087 int len = 0;
01088 char md5key[256] = "";
01089 struct MD5Context md5;
01090 unsigned char digest[16];
01091 MD5Init(&md5);
01092 MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
01093 MD5Update(&md5, (unsigned char *) password, strlen(password));
01094 MD5Final(digest, &md5);
01095 for (x=0; x<16; x++)
01096 len += sprintf(md5key + len, "%2.2x", digest[x]);
01097 if (!strcmp(md5key, key))
01098 break;
01099 else {
01100 ast_config_destroy(cfg);
01101 return -1;
01102 }
01103 } else {
01104 ast_log(LOG_DEBUG, "MD5 authentication is not possible. challenge: '%s'\n",
01105 S_OR(s->session->challenge, ""));
01106 ast_config_destroy(cfg);
01107 return -1;
01108 }
01109 } else if (password && !strcmp(password, pass)) {
01110 break;
01111 } else {
01112 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), user);
01113 ast_config_destroy(cfg);
01114 return -1;
01115 }
01116 }
01117 }
01118 cat = ast_category_browse(cfg, cat);
01119 }
01120 if (cat) {
01121 ast_copy_string(s->session->username, cat, sizeof(s->session->username));
01122 s->session->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
01123 s->session->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
01124 ast_config_destroy(cfg);
01125 if (events)
01126 set_eventmask(s->session, events);
01127 return 0;
01128 }
01129 ast_config_destroy(cfg);
01130 cfg = ast_config_load("users.conf");
01131 if (!cfg)
01132 return -1;
01133 cat = ast_category_browse(cfg, NULL);
01134 while (cat) {
01135 struct ast_variable *v;
01136 const char *password = NULL;
01137 int hasmanager = 0;
01138 const char *readperms = NULL;
01139 const char *writeperms = NULL;
01140
01141 if (strcasecmp(cat, user) || !strcasecmp(cat, "general")) {
01142 cat = ast_category_browse(cfg, cat);
01143 continue;
01144 }
01145 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
01146 if (!strcasecmp(v->name, "secret"))
01147 password = v->value;
01148 else if (!strcasecmp(v->name, "hasmanager"))
01149 hasmanager = ast_true(v->value);
01150 else if (!strcasecmp(v->name, "managerread"))
01151 readperms = v->value;
01152 else if (!strcasecmp(v->name, "managerwrite"))
01153 writeperms = v->value;
01154 }
01155 if (!hasmanager)
01156 break;
01157 if (!password || strcmp(password, pass)) {
01158 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), user);
01159 ast_config_destroy(cfg);
01160 return -1;
01161 }
01162 ast_copy_string(s->session->username, cat, sizeof(s->session->username));
01163 s->session->readperm = readperms ? get_perm(readperms) : -1;
01164 s->session->writeperm = writeperms ? get_perm(writeperms) : -1;
01165 ast_config_destroy(cfg);
01166 if (events)
01167 set_eventmask(s->session, events);
01168 return 0;
01169 }
01170 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), user);
01171 ast_config_destroy(cfg);
01172 return -1;
01173 }
01174
01175
01176 static char mandescr_ping[] =
01177 "Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the\n"
01178 " manager connection open.\n"
01179 "Variables: NONE\n";
01180
01181 static int action_ping(struct mansession *s, const struct message *m)
01182 {
01183 astman_send_response(s, m, "Pong", NULL);
01184 return 0;
01185 }
01186
01187 static char mandescr_getconfig[] =
01188 "Description: A 'GetConfig' action will dump the contents of a configuration\n"
01189 "file by category and contents.\n"
01190 "Variables:\n"
01191 " Filename: Configuration filename (e.g. foo.conf)\n";
01192
01193 static int action_getconfig(struct mansession *s, const struct message *m)
01194 {
01195 struct ast_config *cfg;
01196 const char *fn = astman_get_header(m, "Filename");
01197 int catcount = 0;
01198 int lineno = 0;
01199 char *category=NULL;
01200 struct ast_variable *v;
01201 char idText[256] = "";
01202 const char *id = astman_get_header(m, "ActionID");
01203
01204 if (!ast_strlen_zero(id))
01205 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01206
01207 if (ast_strlen_zero(fn)) {
01208 astman_send_error(s, m, "Filename not specified");
01209 return 0;
01210 }
01211 if (!(cfg = ast_config_load_with_comments(fn))) {
01212 astman_send_error(s, m, "Config file not found");
01213 return 0;
01214 }
01215 astman_append(s, "Response: Success\r\n%s", idText);
01216 while ((category = ast_category_browse(cfg, category))) {
01217 lineno = 0;
01218 astman_append(s, "Category-%06d: %s\r\n", catcount, category);
01219 for (v = ast_variable_browse(cfg, category); v; v = v->next)
01220 astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
01221 catcount++;
01222 }
01223 ast_config_destroy(cfg);
01224 astman_append(s, "\r\n");
01225
01226 return 0;
01227 }
01228
01229
01230 static void handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg)
01231 {
01232 int x;
01233 char hdr[40];
01234 const char *action, *cat, *var, *value, *match;
01235 struct ast_category *category;
01236 struct ast_variable *v;
01237
01238 for (x=0;x<100000;x++) {
01239 unsigned int object = 0;
01240
01241 snprintf(hdr, sizeof(hdr), "Action-%06d", x);
01242 action = astman_get_header(m, hdr);
01243 if (ast_strlen_zero(action))
01244 break;
01245 snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
01246 cat = astman_get_header(m, hdr);
01247 snprintf(hdr, sizeof(hdr), "Var-%06d", x);
01248 var = astman_get_header(m, hdr);
01249 snprintf(hdr, sizeof(hdr), "Value-%06d", x);
01250 value = astman_get_header(m, hdr);
01251 if (!ast_strlen_zero(value) && *value == '>') {
01252 object = 1;
01253 value++;
01254 }
01255 snprintf(hdr, sizeof(hdr), "Match-%06d", x);
01256 match = astman_get_header(m, hdr);
01257 if (!strcasecmp(action, "newcat")) {
01258 if (!ast_strlen_zero(cat)) {
01259 category = ast_category_new(cat);
01260 if (category) {
01261 ast_category_append(cfg, category);
01262 }
01263 }
01264 } else if (!strcasecmp(action, "renamecat")) {
01265 if (!ast_strlen_zero(cat) && !ast_strlen_zero(value)) {
01266 category = ast_category_get(cfg, cat);
01267 if (category)
01268 ast_category_rename(category, value);
01269 }
01270 } else if (!strcasecmp(action, "delcat")) {
01271 if (!ast_strlen_zero(cat))
01272 ast_category_delete(cfg, (char *) cat);
01273 } else if (!strcasecmp(action, "update")) {
01274 if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) && (category = ast_category_get(cfg, cat)))
01275 ast_variable_update(category, var, value, match, object);
01276 } else if (!strcasecmp(action, "delete")) {
01277 if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) && (category = ast_category_get(cfg, cat)))
01278 ast_variable_delete(category, (char *) var, (char *) match);
01279 } else if (!strcasecmp(action, "append")) {
01280 if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) &&
01281 (category = ast_category_get(cfg, cat)) &&
01282 (v = ast_variable_new(var, value))){
01283 if (object || (match && !strcasecmp(match, "object")))
01284 v->object = 1;
01285 ast_variable_append(category, v);
01286 }
01287 }
01288 }
01289 }
01290
01291 static char mandescr_updateconfig[] =
01292 "Description: A 'UpdateConfig' action will modify, create, or delete\n"
01293 "configuration elements in Asterisk configuration files.\n"
01294 "Variables (X's represent 6 digit number beginning with 000000):\n"
01295 " SrcFilename: Configuration filename to read(e.g. foo.conf)\n"
01296 " DstFilename: Configuration filename to write(e.g. foo.conf)\n"
01297 " Reload: Whether or not a reload should take place (or name of specific module)\n"
01298 " Action-XXXXXX: Action to Take (NewCat,RenameCat,DelCat,Update,Delete,Append)\n"
01299 " Cat-XXXXXX: Category to operate on\n"
01300 " Var-XXXXXX: Variable to work on\n"
01301 " Value-XXXXXX: Value to work on\n"
01302 " Match-XXXXXX: Extra match required to match line\n";
01303
01304 static int action_updateconfig(struct mansession *s, const struct message *m)
01305 {
01306 struct ast_config *cfg;
01307 const char *sfn = astman_get_header(m, "SrcFilename");
01308 const char *dfn = astman_get_header(m, "DstFilename");
01309 int res;
01310 char idText[256] = "";
01311 const char *id = astman_get_header(m, "ActionID");
01312 const char *rld = astman_get_header(m, "Reload");
01313
01314 if (!ast_strlen_zero(id))
01315 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01316
01317 if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
01318 astman_send_error(s, m, "Filename not specified");
01319 return 0;
01320 }
01321 if (!(cfg = ast_config_load_with_comments(sfn))) {
01322 astman_send_error(s, m, "Config file not found");
01323 return 0;
01324 }
01325 handle_updates(s, m, cfg);
01326 res = config_text_file_save(dfn, cfg, "Manager");
01327 ast_config_destroy(cfg);
01328 if (res) {
01329 astman_send_error(s, m, "Save of config failed");
01330 return 0;
01331 }
01332 astman_append(s, "Response: Success\r\n%s\r\n", idText);
01333 if (!ast_strlen_zero(rld)) {
01334 if (ast_true(rld))
01335 rld = NULL;
01336 ast_module_reload(rld);
01337 }
01338 return 0;
01339 }
01340
01341
01342 static char mandescr_waitevent[] =
01343 "Description: A 'WaitEvent' action will ellicit a 'Success' response. Whenever\n"
01344 "a manager event is queued. Once WaitEvent has been called on an HTTP manager\n"
01345 "session, events will be generated and queued.\n"
01346 "Variables: \n"
01347 " Timeout: Maximum time to wait for events\n";
01348
01349 static int action_waitevent(struct mansession *s, const struct message *m)
01350 {
01351 const char *timeouts = astman_get_header(m, "Timeout");
01352 int timeout = -1, max;
01353 int x;
01354 int needexit = 0;
01355 time_t now;
01356 struct eventqent *eqe;
01357 const char *id = astman_get_header(m,"ActionID");
01358 char idText[256] = "";
01359
01360 if (!ast_strlen_zero(id))
01361 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01362
01363 if (!ast_strlen_zero(timeouts)) {
01364 sscanf(timeouts, "%30i", &timeout);
01365 }
01366
01367 ast_mutex_lock(&s->session->__lock);
01368 if (s->session->waiting_thread != AST_PTHREADT_NULL) {
01369 pthread_kill(s->session->waiting_thread, SIGURG);
01370 }
01371 if (s->session->sessiontimeout) {
01372 time(&now);
01373 max = s->session->sessiontimeout - now - 10;
01374 if (max < 0)
01375 max = 0;
01376 if ((timeout < 0) || (timeout > max))
01377 timeout = max;
01378 if (!s->session->send_events)
01379 s->session->send_events = -1;
01380
01381 }
01382 ast_mutex_unlock(&s->session->__lock);
01383 s->session->waiting_thread = pthread_self();
01384 if (option_debug)
01385 ast_log(LOG_DEBUG, "Starting waiting for an event!\n");
01386 for (x=0; ((x < timeout) || (timeout < 0)); x++) {
01387 ast_mutex_lock(&s->session->__lock);
01388 if (s->session->eventq && s->session->eventq->next)
01389 needexit = 1;
01390 if (s->session->waiting_thread != pthread_self())
01391 needexit = 1;
01392 if (s->session->needdestroy)
01393 needexit = 1;
01394 ast_mutex_unlock(&s->session->__lock);
01395 if (needexit)
01396 break;
01397 if (s->session->fd > 0) {
01398 if (ast_wait_for_input(s->session->fd, 1000))
01399 break;
01400 } else {
01401 sleep(1);
01402 }
01403 }
01404 if (option_debug)
01405 ast_log(LOG_DEBUG, "Finished waiting for an event!\n");
01406 ast_mutex_lock(&s->session->__lock);
01407 if (s->session->waiting_thread == pthread_self()) {
01408 astman_send_response(s, m, "Success", "Waiting for Event...");
01409
01410 while(s->session->eventq->next) {
01411 eqe = s->session->eventq->next;
01412 if (((s->session->readperm & eqe->category) == eqe->category) &&
01413 ((s->session->send_events & eqe->category) == eqe->category)) {
01414 astman_append(s, "%s", eqe->eventdata);
01415 }
01416 unuse_eventqent(s->session->eventq);
01417 s->session->eventq = eqe;
01418 }
01419 astman_append(s,
01420 "Event: WaitEventComplete\r\n"
01421 "%s"
01422 "\r\n", idText);
01423 s->session->waiting_thread = AST_PTHREADT_NULL;
01424 } else {
01425 ast_log(LOG_DEBUG, "Abandoning event request!\n");
01426 }
01427 ast_mutex_unlock(&s->session->__lock);
01428 return 0;
01429 }
01430
01431 static char mandescr_listcommands[] =
01432 "Description: Returns the action name and synopsis for every\n"
01433 " action that is available to the user\n"
01434 "Variables: NONE\n";
01435
01436
01437 static int action_listcommands(struct mansession *s, const struct message *m)
01438 {
01439 struct manager_action *cur;
01440 char idText[256] = "";
01441 char temp[BUFSIZ];
01442 const char *id = astman_get_header(m,"ActionID");
01443
01444 if (!ast_strlen_zero(id))
01445 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01446 astman_append(s, "Response: Success\r\n%s", idText);
01447 for (cur = first_action; cur; cur = cur->next) {
01448 if ((s->session->writeperm & cur->authority) == cur->authority)
01449 astman_append(s, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)));
01450 }
01451 astman_append(s, "\r\n");
01452
01453 return 0;
01454 }
01455
01456 static char mandescr_events[] =
01457 "Description: Enable/Disable sending of events to this manager\n"
01458 " client.\n"
01459 "Variables:\n"
01460 " EventMask: 'on' if all events should be sent,\n"
01461 " 'off' if no events should be sent,\n"
01462 " 'system,call,log' to select which flags events should have to be sent.\n";
01463
01464 static int action_events(struct mansession *s, const struct message *m)
01465 {
01466 const char *mask = astman_get_header(m, "EventMask");
01467 int res, x;
01468
01469 res = set_eventmask(s->session, mask);
01470 if (broken_events_action) {
01471
01472
01473
01474 if (res > 0) {
01475 for (x = 0; x < ARRAY_LEN(perms); x++) {
01476 if (!strcasecmp(perms[x].label, "all") && res == perms[x].num) {
01477 return 0;
01478 }
01479 }
01480 astman_send_response(s, m, "Events On", NULL);
01481 } else if (res == 0)
01482 astman_send_response(s, m, "Events Off", NULL);
01483 return 0;
01484 }
01485
01486 if (res > 0)
01487 astman_send_response(s, m, "Events On", NULL);
01488 else if (res == 0)
01489 astman_send_response(s, m, "Events Off", NULL);
01490 else
01491 astman_send_error(s, m, "Invalid event mask");
01492
01493 return 0;
01494 }
01495
01496 static char mandescr_logoff[] =
01497 "Description: Logoff this manager session\n"
01498 "Variables: NONE\n";
01499
01500 static int action_logoff(struct mansession *s, const struct message *m)
01501 {
01502 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
01503 return -1;
01504 }
01505
01506 static char mandescr_hangup[] =
01507 "Description: Hangup a channel\n"
01508 "Variables: \n"
01509 " Channel: The channel name to be hungup\n";
01510
01511 static int action_hangup(struct mansession *s, const struct message *m)
01512 {
01513 struct ast_channel *c = NULL;
01514 const char *name = astman_get_header(m, "Channel");
01515 if (ast_strlen_zero(name)) {
01516 astman_send_error(s, m, "No channel specified");
01517 return 0;
01518 }
01519 c = ast_get_channel_by_name_locked(name);
01520 if (!c) {
01521 astman_send_error(s, m, "No such channel");
01522 return 0;
01523 }
01524 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
01525 ast_channel_unlock(c);
01526 astman_send_ack(s, m, "Channel Hungup");
01527 return 0;
01528 }
01529
01530 static char mandescr_setvar[] =
01531 "Description: Set a global or local channel variable.\n"
01532 "Variables: (Names marked with * are required)\n"
01533 " Channel: Channel to set variable for\n"
01534 " *Variable: Variable name\n"
01535 " *Value: Value\n";
01536
01537 static int action_setvar(struct mansession *s, const struct message *m)
01538 {
01539 struct ast_channel *c = NULL;
01540 const char *name = astman_get_header(m, "Channel");
01541 const char *varname = astman_get_header(m, "Variable");
01542 const char *varval = astman_get_header(m, "Value");
01543 int res = 0;
01544
01545 if (ast_strlen_zero(varname)) {
01546 astman_send_error(s, m, "No variable specified");
01547 return 0;
01548 }
01549
01550 if (!ast_strlen_zero(name)) {
01551 c = ast_get_channel_by_name_locked(name);
01552 if (!c) {
01553 astman_send_error(s, m, "No such channel");
01554 return 0;
01555 }
01556 }
01557 if (varname[strlen(varname)-1] == ')') {
01558 char *function = ast_strdupa(varname);
01559 res = ast_func_write(c, function, varval);
01560 } else {
01561 pbx_builtin_setvar_helper(c, varname, S_OR(varval, ""));
01562 }
01563
01564 if (c) {
01565 ast_channel_unlock(c);
01566 }
01567
01568 if (res == 0) {
01569 astman_send_ack(s, m, "Variable Set");
01570 } else {
01571 astman_send_error(s, m, "Variable not set");
01572 }
01573
01574 return 0;
01575 }
01576
01577 static char mandescr_getvar[] =
01578 "Description: Get the value of a global or local channel variable.\n"
01579 "Variables: (Names marked with * are required)\n"
01580 " Channel: Channel to read variable from\n"
01581 " *Variable: Variable name\n"
01582 " ActionID: Optional Action id for message matching.\n";
01583
01584 static int action_getvar(struct mansession *s, const struct message *m)
01585 {
01586 struct ast_channel *c = NULL;
01587 const char *name = astman_get_header(m, "Channel");
01588 const char *varname = astman_get_header(m, "Variable");
01589 const char *id = astman_get_header(m,"ActionID");
01590 char *varval;
01591 char workspace[1024] = "";
01592
01593 if (ast_strlen_zero(varname)) {
01594 astman_send_error(s, m, "No variable specified");
01595 return 0;
01596 }
01597
01598 if (!ast_strlen_zero(name)) {
01599 c = ast_get_channel_by_name_locked(name);
01600 if (!c) {
01601 astman_send_error(s, m, "No such channel");
01602 return 0;
01603 }
01604 }
01605
01606 if (varname[strlen(varname) - 1] == ')') {
01607 char *copy = ast_strdupa(varname);
01608 if (!c) {
01609 c = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/manager");
01610 if (c) {
01611 ast_func_read(c, copy, workspace, sizeof(workspace));
01612 ast_channel_free(c);
01613 c = NULL;
01614 } else
01615 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
01616 } else
01617 ast_func_read(c, copy, workspace, sizeof(workspace));
01618 varval = workspace;
01619 } else {
01620 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
01621 }
01622
01623 if (c)
01624 ast_channel_unlock(c);
01625 astman_append(s, "Response: Success\r\n"
01626 "Variable: %s\r\nValue: %s\r\n", varname, S_OR(varval, ""));
01627 if (!ast_strlen_zero(id))
01628 astman_append(s, "ActionID: %s\r\n",id);
01629 astman_append(s, "\r\n");
01630
01631 return 0;
01632 }
01633
01634
01635
01636
01637 static int action_status(struct mansession *s, const struct message *m)
01638 {
01639 const char *id = astman_get_header(m,"ActionID");
01640 const char *name = astman_get_header(m,"Channel");
01641 char idText[256] = "";
01642 struct ast_channel *c;
01643 char bridge[256];
01644 struct timeval now = ast_tvnow();
01645 long elapsed_seconds = 0;
01646 int all = ast_strlen_zero(name);
01647
01648 if (!ast_strlen_zero(id))
01649 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01650 if (all)
01651 c = ast_channel_walk_locked(NULL);
01652 else {
01653 c = ast_get_channel_by_name_locked(name);
01654 if (!c) {
01655 astman_send_error(s, m, "No such channel");
01656 return 0;
01657 }
01658 }
01659 astman_send_ack(s, m, "Channel status will follow");
01660
01661 while (c) {
01662 if (c->_bridge)
01663 snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->_bridge->name);
01664 else
01665 bridge[0] = '\0';
01666 if (c->pbx) {
01667 if (c->cdr) {
01668 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
01669 }
01670 astman_append(s,
01671 "Event: Status\r\n"
01672 "Privilege: Call\r\n"
01673 "Channel: %s\r\n"
01674 "CallerID: %s\r\n"
01675 "CallerIDNum: %s\r\n"
01676 "CallerIDName: %s\r\n"
01677 "Account: %s\r\n"
01678 "State: %s\r\n"
01679 "Context: %s\r\n"
01680 "Extension: %s\r\n"
01681 "Priority: %d\r\n"
01682 "Seconds: %ld\r\n"
01683 "%s"
01684 "Uniqueid: %s\r\n"
01685 "%s"
01686 "\r\n",
01687 c->name,
01688 S_OR(c->cid.cid_num, "<unknown>"),
01689 S_OR(c->cid.cid_num, "<unknown>"),
01690 S_OR(c->cid.cid_name, "<unknown>"),
01691 c->accountcode,
01692 ast_state2str(c->_state), c->context,
01693 c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
01694 } else {
01695 astman_append(s,
01696 "Event: Status\r\n"
01697 "Privilege: Call\r\n"
01698 "Channel: %s\r\n"
01699 "CallerID: %s\r\n"
01700 "CallerIDNum: %s\r\n"
01701 "CallerIDName: %s\r\n"
01702 "Account: %s\r\n"
01703 "State: %s\r\n"
01704 "%s"
01705 "Uniqueid: %s\r\n"
01706 "%s"
01707 "\r\n",
01708 c->name,
01709 S_OR(c->cid.cid_num, "<unknown>"),
01710 S_OR(c->cid.cid_num, "<unknown>"),
01711 S_OR(c->cid.cid_name, "<unknown>"),
01712 c->accountcode,
01713 ast_state2str(c->_state), bridge, c->uniqueid, idText);
01714 }
01715 ast_channel_unlock(c);
01716 if (!all)
01717 break;
01718 c = ast_channel_walk_locked(c);
01719 }
01720 astman_append(s,
01721 "Event: StatusComplete\r\n"
01722 "%s"
01723 "\r\n",idText);
01724 return 0;
01725 }
01726
01727 static char mandescr_redirect[] =
01728 "Description: Redirect (transfer) a call.\n"
01729 "Variables: (Names marked with * are required)\n"
01730 " *Channel: Channel to redirect\n"
01731 " ExtraChannel: Second call leg to transfer (optional)\n"
01732 " *Exten: Extension to transfer to\n"
01733 " *Context: Context to transfer to\n"
01734 " *Priority: Priority to transfer to\n"
01735 " ActionID: Optional Action id for message matching.\n";
01736
01737
01738 static int action_redirect(struct mansession *s, const struct message *m)
01739 {
01740 const char *name = astman_get_header(m, "Channel");
01741 const char *name2 = astman_get_header(m, "ExtraChannel");
01742 const char *exten = astman_get_header(m, "Exten");
01743 const char *context = astman_get_header(m, "Context");
01744 const char *priority = astman_get_header(m, "Priority");
01745 struct ast_channel *chan, *chan2 = NULL;
01746 int pi = 0;
01747 int res;
01748
01749 if (ast_strlen_zero(name)) {
01750 astman_send_error(s, m, "Channel not specified");
01751 return 0;
01752 }
01753 if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
01754 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
01755 astman_send_error(s, m, "Invalid priority");
01756 return 0;
01757 }
01758 }
01759
01760 chan = ast_get_channel_by_name_locked(name);
01761 if (!chan) {
01762 char buf[BUFSIZ];
01763 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
01764 astman_send_error(s, m, buf);
01765 return 0;
01766 }
01767 if (ast_check_hangup(chan)) {
01768 astman_send_error(s, m, "Redirect failed, channel not up.");
01769 ast_channel_unlock(chan);
01770 return 0;
01771 }
01772 if (!ast_strlen_zero(name2))
01773 chan2 = ast_get_channel_by_name_locked(name2);
01774 if (chan2 && ast_check_hangup(chan2)) {
01775 astman_send_error(s, m, "Redirect failed, extra channel not up.");
01776 ast_channel_unlock(chan);
01777 ast_channel_unlock(chan2);
01778 return 0;
01779 }
01780 if (chan->pbx) {
01781 ast_channel_lock(chan);
01782 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
01783 ast_channel_unlock(chan);
01784 }
01785 res = ast_async_goto(chan, context, exten, pi);
01786 if (!res) {
01787 if (!ast_strlen_zero(name2)) {
01788 if (chan2) {
01789 if (chan2->pbx) {
01790 ast_channel_lock(chan2);
01791 ast_set_flag(chan2, AST_FLAG_BRIDGE_HANGUP_DONT);
01792 ast_channel_unlock(chan2);
01793 }
01794 res = ast_async_goto(chan2, context, exten, pi);
01795 } else {
01796 res = -1;
01797 }
01798 if (!res)
01799 astman_send_ack(s, m, "Dual Redirect successful");
01800 else
01801 astman_send_error(s, m, "Secondary redirect failed");
01802 } else
01803 astman_send_ack(s, m, "Redirect successful");
01804 } else
01805 astman_send_error(s, m, "Redirect failed");
01806 if (chan)
01807 ast_channel_unlock(chan);
01808 if (chan2)
01809 ast_channel_unlock(chan2);
01810 return 0;
01811 }
01812
01813 static int check_blacklist(const char *cmd)
01814 {
01815 char *cmd_copy, *cur_cmd;
01816 char *cmd_words[MAX_BLACKLIST_CMD_LEN] = { NULL, };
01817 int i;
01818
01819 cmd_copy = ast_strdupa(cmd);
01820 for (i = 0; i < MAX_BLACKLIST_CMD_LEN && (cur_cmd = strsep(&cmd_copy, " ")); i++) {
01821 cur_cmd = ast_strip(cur_cmd);
01822 if (ast_strlen_zero(cur_cmd)) {
01823 i--;
01824 continue;
01825 }
01826
01827 cmd_words[i] = cur_cmd;
01828 }
01829
01830 for (i = 0; i < ARRAY_LEN(command_blacklist); i++) {
01831 int j, match = 1;
01832
01833 for (j = 0; command_blacklist[i].words[j]; j++) {
01834 if (ast_strlen_zero(cmd_words[j]) || strcasecmp(cmd_words[j], command_blacklist[i].words[j])) {
01835 match = 0;
01836 break;
01837 }
01838 }
01839
01840 if (match) {
01841 return 1;
01842 }
01843 }
01844
01845 return 0;
01846 }
01847
01848 static char mandescr_command[] =
01849 "Description: Run a CLI command.\n"
01850 "Variables: (Names marked with * are required)\n"
01851 " *Command: Asterisk CLI command to run\n"
01852 " ActionID: Optional Action id for message matching.\n";
01853
01854
01855 static int action_command(struct mansession *s, const struct message *m)
01856 {
01857 const char *cmd = astman_get_header(m, "Command");
01858 const char *id = astman_get_header(m, "ActionID");
01859 char *buf, *final_buf;
01860 char template[] = "/tmp/ast-ami-XXXXXX";
01861 int fd;
01862 off_t l;
01863
01864 if (ast_strlen_zero(cmd)) {
01865 astman_send_error(s, m, "No command provided");
01866 return 0;
01867 }
01868
01869 if (check_blacklist(cmd)) {
01870 astman_send_error(s, m, "Command blacklisted");
01871 return 0;
01872 }
01873
01874 fd = mkstemp(template);
01875
01876 astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
01877 if (!ast_strlen_zero(id))
01878 astman_append(s, "ActionID: %s\r\n", id);
01879
01880 ast_cli_command(fd, cmd);
01881 l = lseek(fd, 0, SEEK_END);
01882
01883
01884 buf = ast_calloc(1, l + 1);
01885 final_buf = ast_calloc(1, l + 1);
01886 if (buf) {
01887 lseek(fd, 0, SEEK_SET);
01888 if (read(fd, buf, l) < 0) {
01889 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01890 }
01891 buf[l] = '\0';
01892 if (final_buf) {
01893 term_strip(final_buf, buf, l);
01894 final_buf[l] = '\0';
01895 }
01896 astman_append(s, "%s", S_OR(final_buf, buf));
01897 ast_free(buf);
01898 }
01899 close(fd);
01900 unlink(template);
01901 astman_append(s, "--END COMMAND--\r\n\r\n");
01902 if (final_buf)
01903 ast_free(final_buf);
01904 return 0;
01905 }
01906
01907 static void *fast_originate(void *data)
01908 {
01909 struct fast_originate_helper *in = data;
01910 int res;
01911 int reason = 0;
01912 struct ast_channel *chan = NULL;
01913 char requested_channel[AST_CHANNEL_NAME];
01914
01915 if (!ast_strlen_zero(in->app)) {
01916 res = ast_pbx_outgoing_app(in->tech, in->format, in->data, in->timeout, in->app, in->appdata, &reason, 1,
01917 S_OR(in->cid_num, NULL),
01918 S_OR(in->cid_name, NULL),
01919 in->vars, in->account, &chan);
01920 } else {
01921 res = ast_pbx_outgoing_exten(in->tech, in->format, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
01922 S_OR(in->cid_num, NULL),
01923 S_OR(in->cid_name, NULL),
01924 in->vars, in->account, &chan);
01925 }
01926
01927 if (!chan)
01928 snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
01929
01930 manager_event(EVENT_FLAG_CALL, "OriginateResponse",
01931 "%s%s"
01932 "Response: %s\r\n"
01933 "Channel: %s\r\n"
01934 "Context: %s\r\n"
01935 "Exten: %s\r\n"
01936 "Reason: %d\r\n"
01937 "Uniqueid: %s\r\n"
01938 "CallerID: %s\r\n"
01939 "CallerIDNum: %s\r\n"
01940 "CallerIDName: %s\r\n",
01941 in->idtext, ast_strlen_zero(in->idtext) ? "" : "\r\n", res ? "Failure" : "Success",
01942 chan ? chan->name : requested_channel, in->context, in->exten, reason,
01943 chan ? chan->uniqueid : "<null>",
01944 S_OR(in->cid_num, "<unknown>"),
01945 S_OR(in->cid_num, "<unknown>"),
01946 S_OR(in->cid_name, "<unknown>")
01947 );
01948
01949
01950 if (chan)
01951 ast_channel_unlock(chan);
01952 free(in);
01953 return NULL;
01954 }
01955
01956 static char mandescr_originate[] =
01957 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
01958 " Application/Data\n"
01959 "Variables: (Names marked with * are required)\n"
01960 " *Channel: Channel name to call\n"
01961 " Exten: Extension to use (requires 'Context' and 'Priority')\n"
01962 " Context: Context to use (requires 'Exten' and 'Priority')\n"
01963 " Priority: Priority to use (requires 'Exten' and 'Context')\n"
01964 " Application: Application to use\n"
01965 " Data: Data to use (requires 'Application')\n"
01966 " Timeout: How long to wait for call to be answered (in ms. Default: 30000)\n"
01967 " CallerID: Caller ID to be set on the outgoing channel\n"
01968 " Variable: Channel variable to set, multiple Variable: headers are allowed\n"
01969 " Codecs: Comma-separated list of codecs to use for the new channels\n"
01970 " Account: Account code\n"
01971 " Async: Set to 'true' for fast origination\n";
01972
01973 static int action_originate(struct mansession *s, const struct message *m)
01974 {
01975 const char *name = astman_get_header(m, "Channel");
01976 const char *exten = astman_get_header(m, "Exten");
01977 const char *context = astman_get_header(m, "Context");
01978 const char *priority = astman_get_header(m, "Priority");
01979 const char *timeout = astman_get_header(m, "Timeout");
01980 const char *callerid = astman_get_header(m, "CallerID");
01981 const char *account = astman_get_header(m, "Account");
01982 const char *app = astman_get_header(m, "Application");
01983 const char *appdata = astman_get_header(m, "Data");
01984 const char *async = astman_get_header(m, "Async");
01985 const char *id = astman_get_header(m, "ActionID");
01986 const char *codecs = astman_get_header(m, "Codecs");
01987 struct ast_variable *vars;
01988 char *tech, *data;
01989 char *l = NULL, *n = NULL;
01990 int pi = 0;
01991 int res;
01992 int to = 30000;
01993 int reason = 0;
01994 char tmp[256];
01995 char tmp2[256];
01996 int format = AST_FORMAT_SLINEAR;
01997
01998 pthread_t th;
01999 pthread_attr_t attr;
02000 if (ast_strlen_zero(name)) {
02001 astman_send_error(s, m, "Channel not specified");
02002 return 0;
02003 }
02004 if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
02005 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
02006 astman_send_error(s, m, "Invalid priority");
02007 return 0;
02008 }
02009 }
02010 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%30d", &to) != 1)) {
02011 astman_send_error(s, m, "Invalid timeout");
02012 return 0;
02013 }
02014 ast_copy_string(tmp, name, sizeof(tmp));
02015 tech = tmp;
02016 data = strchr(tmp, '/');
02017 if (!data) {
02018 astman_send_error(s, m, "Invalid channel");
02019 return 0;
02020 }
02021 *data++ = '\0';
02022 ast_copy_string(tmp2, callerid, sizeof(tmp2));
02023 ast_callerid_parse(tmp2, &n, &l);
02024 if (n) {
02025 if (ast_strlen_zero(n))
02026 n = NULL;
02027 }
02028 if (l) {
02029 ast_shrink_phone_number(l);
02030 if (ast_strlen_zero(l))
02031 l = NULL;
02032 }
02033 if (!ast_strlen_zero(codecs)) {
02034 format = 0;
02035 ast_parse_allow_disallow(NULL, &format, codecs, 1);
02036 }
02037
02038 vars = astman_get_variables(m);
02039
02040 if (ast_true(async)) {
02041 struct fast_originate_helper *fast = ast_calloc(1, sizeof(*fast));
02042 if (!fast) {
02043 res = -1;
02044 } else {
02045 if (!ast_strlen_zero(id))
02046 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s", id);
02047 ast_copy_string(fast->tech, tech, sizeof(fast->tech));
02048 ast_copy_string(fast->data, data, sizeof(fast->data));
02049 ast_copy_string(fast->app, app, sizeof(fast->app));
02050 ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
02051 if (l)
02052 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
02053 if (n)
02054 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
02055 fast->vars = vars;
02056 ast_copy_string(fast->context, context, sizeof(fast->context));
02057 ast_copy_string(fast->exten, exten, sizeof(fast->exten));
02058 ast_copy_string(fast->account, account, sizeof(fast->account));
02059 fast->format = format;
02060 fast->timeout = to;
02061 fast->priority = pi;
02062 pthread_attr_init(&attr);
02063 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02064 if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
02065 ast_free(fast);
02066 res = -1;
02067 } else {
02068 res = 0;
02069 }
02070 pthread_attr_destroy(&attr);
02071 }
02072 } else if (!ast_strlen_zero(app)) {
02073 res = ast_pbx_outgoing_app(tech, format, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
02074 } else {
02075 if (exten && context && pi)
02076 res = ast_pbx_outgoing_exten(tech, format, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
02077 else {
02078 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
02079 if (vars) {
02080 ast_variables_destroy(vars);
02081 }
02082 return 0;
02083 }
02084 }
02085 if (!res)
02086 astman_send_ack(s, m, "Originate successfully queued");
02087 else
02088 astman_send_error(s, m, "Originate failed");
02089 return 0;
02090 }
02091
02092
02093
02094 static char mandescr_mailboxstatus[] =
02095 "Description: Checks a voicemail account for status.\n"
02096 "Variables: (Names marked with * are required)\n"
02097 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
02098 " ActionID: Optional ActionID for message matching.\n"
02099 "Returns number of messages.\n"
02100 " Message: Mailbox Status\n"
02101 " Mailbox: <mailboxid>\n"
02102 " Waiting: <count>\n"
02103 "\n";
02104
02105 static int action_mailboxstatus(struct mansession *s, const struct message *m)
02106 {
02107 const char *mailbox = astman_get_header(m, "Mailbox");
02108 const char *id = astman_get_header(m,"ActionID");
02109 char idText[256] = "";
02110 int ret;
02111 if (ast_strlen_zero(mailbox)) {
02112 astman_send_error(s, m, "Mailbox not specified");
02113 return 0;
02114 }
02115 if (!ast_strlen_zero(id))
02116 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02117 ret = ast_app_has_voicemail(mailbox, NULL);
02118 astman_append(s, "Response: Success\r\n"
02119 "%s"
02120 "Message: Mailbox Status\r\n"
02121 "Mailbox: %s\r\n"
02122 "Waiting: %d\r\n\r\n", idText, mailbox, ret);
02123 return 0;
02124 }
02125
02126 static char mandescr_mailboxcount[] =
02127 "Description: Checks a voicemail account for new messages.\n"
02128 "Variables: (Names marked with * are required)\n"
02129 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
02130 " ActionID: Optional ActionID for message matching.\n"
02131 "Returns number of new and old messages.\n"
02132 " Message: Mailbox Message Count\n"
02133 " Mailbox: <mailboxid>\n"
02134 " NewMessages: <count>\n"
02135 " OldMessages: <count>\n"
02136 "\n";
02137 static int action_mailboxcount(struct mansession *s, const struct message *m)
02138 {
02139 const char *mailbox = astman_get_header(m, "Mailbox");
02140 const char *id = astman_get_header(m,"ActionID");
02141 char idText[256] = "";
02142 int newmsgs = 0, oldmsgs = 0;
02143 if (ast_strlen_zero(mailbox)) {
02144 astman_send_error(s, m, "Mailbox not specified");
02145 return 0;
02146 }
02147 ast_app_inboxcount(mailbox, &newmsgs, &oldmsgs);
02148 if (!ast_strlen_zero(id)) {
02149 snprintf(idText, sizeof(idText), "ActionID: %s\r\n",id);
02150 }
02151 astman_append(s, "Response: Success\r\n"
02152 "%s"
02153 "Message: Mailbox Message Count\r\n"
02154 "Mailbox: %s\r\n"
02155 "NewMessages: %d\r\n"
02156 "OldMessages: %d\r\n"
02157 "\r\n",
02158 idText,mailbox, newmsgs, oldmsgs);
02159 return 0;
02160 }
02161
02162 static char mandescr_extensionstate[] =
02163 "Description: Report the extension state for given extension.\n"
02164 " If the extension has a hint, will use devicestate to check\n"
02165 " the status of the device connected to the extension.\n"
02166 "Variables: (Names marked with * are required)\n"
02167 " *Exten: Extension to check state on\n"
02168 " *Context: Context for extension\n"
02169 " ActionId: Optional ID for this transaction\n"
02170 "Will return an \"Extension Status\" message.\n"
02171 "The response will include the hint for the extension and the status.\n";
02172
02173 static int action_extensionstate(struct mansession *s, const struct message *m)
02174 {
02175 const char *exten = astman_get_header(m, "Exten");
02176 const char *context = astman_get_header(m, "Context");
02177 const char *id = astman_get_header(m,"ActionID");
02178 char idText[256] = "";
02179 char hint[256] = "";
02180 int status;
02181 if (ast_strlen_zero(exten)) {
02182 astman_send_error(s, m, "Extension not specified");
02183 return 0;
02184 }
02185 if (ast_strlen_zero(context))
02186 context = "default";
02187 status = ast_extension_state(NULL, context, exten);
02188 ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
02189 if (!ast_strlen_zero(id)) {
02190 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02191 }
02192 astman_append(s, "Response: Success\r\n"
02193 "%s"
02194 "Message: Extension Status\r\n"
02195 "Exten: %s\r\n"
02196 "Context: %s\r\n"
02197 "Hint: %s\r\n"
02198 "Status: %d\r\n\r\n",
02199 idText,exten, context, hint, status);
02200 return 0;
02201 }
02202
02203 static char mandescr_timeout[] =
02204 "Description: Hangup a channel after a certain time.\n"
02205 "Variables: (Names marked with * are required)\n"
02206 " *Channel: Channel name to hangup\n"
02207 " *Timeout: Maximum duration of the call (sec)\n"
02208 "Acknowledges set time with 'Timeout Set' message\n";
02209
02210 static int action_timeout(struct mansession *s, const struct message *m)
02211 {
02212 struct ast_channel *c = NULL;
02213 const char *name = astman_get_header(m, "Channel");
02214 int timeout = atoi(astman_get_header(m, "Timeout"));
02215 if (ast_strlen_zero(name)) {
02216 astman_send_error(s, m, "No channel specified");
02217 return 0;
02218 }
02219 if (!timeout) {
02220 astman_send_error(s, m, "No timeout specified");
02221 return 0;
02222 }
02223 c = ast_get_channel_by_name_locked(name);
02224 if (!c) {
02225 astman_send_error(s, m, "No such channel");
02226 return 0;
02227 }
02228 ast_channel_setwhentohangup(c, timeout);
02229 ast_channel_unlock(c);
02230 astman_send_ack(s, m, "Timeout Set");
02231 return 0;
02232 }
02233
02234 static int process_events(struct mansession *s)
02235 {
02236 struct eventqent *eqe;
02237 int ret = 0;
02238 ast_mutex_lock(&s->session->__lock);
02239 if (!s->session->eventq)
02240 s->session->eventq = master_eventq;
02241 while(s->session->eventq->next) {
02242 eqe = s->session->eventq->next;
02243 if ((s->session->authenticated && (s->session->readperm & eqe->category) == eqe->category) &&
02244 ((s->session->send_events & eqe->category) == eqe->category)) {
02245 if (s->fd > -1) {
02246 if (!ret && ast_carefulwrite(s->fd, eqe->eventdata, strlen(eqe->eventdata), s->session->writetimeout) < 0)
02247 ret = -1;
02248 } else if (!s->session->outputstr && !(s->session->outputstr = ast_calloc(1, sizeof(*s->session->outputstr))))
02249 ret = -1;
02250 else
02251 ast_dynamic_str_append(&s->session->outputstr, 0, "%s", eqe->eventdata);
02252 }
02253 unuse_eventqent(s->session->eventq);
02254 s->session->eventq = eqe;
02255 }
02256 ast_mutex_unlock(&s->session->__lock);
02257 return ret;
02258 }
02259
02260 static char mandescr_userevent[] =
02261 "Description: Send an event to manager sessions.\n"
02262 "Variables: (Names marked with * are required)\n"
02263 " *UserEvent: EventStringToSend\n"
02264 " Header1: Content1\n"
02265 " HeaderN: ContentN\n";
02266
02267 static int action_userevent(struct mansession *s, const struct message *m)
02268 {
02269 const char *event = astman_get_header(m, "UserEvent");
02270 char body[2048] = "";
02271 int x, bodylen = 0, xlen;
02272 for (x = 0; x < m->hdrcount; x++) {
02273 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
02274 if (sizeof(body) < bodylen + (xlen = strlen(m->headers[x])) + 3) {
02275 ast_log(LOG_WARNING, "UserEvent exceeds our buffer length. Truncating.\n");
02276 break;
02277 }
02278 ast_copy_string(body + bodylen, m->headers[x], sizeof(body) - bodylen - 3);
02279 bodylen += xlen;
02280 ast_copy_string(body + bodylen, "\r\n", 3);
02281 bodylen += 2;
02282 }
02283 }
02284
02285 astman_send_ack(s, m, "Event Sent");
02286 manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, body);
02287 return 0;
02288 }
02289
02290 static char mandescr_coresettings[] =
02291 "Description: Query for Core PBX settings.\n"
02292 "Variables: (Names marked with * are optional)\n"
02293 " *ActionID: ActionID of this transaction\n";
02294
02295
02296 static int action_coresettings(struct mansession *s, const struct message *m)
02297 {
02298 const char *actionid = astman_get_header(m, "ActionID");
02299 char idText[150] = "";
02300
02301 if (!ast_strlen_zero(actionid))
02302 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
02303
02304 astman_append(s, "Response: Success\r\n"
02305 "%s"
02306 "AMIversion: %s\r\n"
02307 "AsteriskVersion: %s\r\n"
02308 "SystemName: %s\r\n"
02309 "CoreMaxCalls: %d\r\n"
02310 "CoreMaxLoadAvg: %f\r\n"
02311 "CoreRunUser: %s\r\n"
02312 "CoreRunGroup: %s\r\n"
02313 "CoreMaxFilehandles: %d\r\n"
02314 "CoreRealTimeEnabled: %s\r\n"
02315 "CoreCDRenabled: %s\r\n"
02316 "CoreHTTPenabled: %s\r\n"
02317 "\r\n",
02318 idText,
02319 AMI_VERSION,
02320 ASTERISK_VERSION,
02321 ast_config_AST_SYSTEM_NAME,
02322 option_maxcalls,
02323 option_maxload,
02324 ast_config_AST_RUN_USER,
02325 ast_config_AST_RUN_GROUP,
02326 option_maxfiles,
02327 ast_realtime_enabled() ? "Yes" : "No",
02328 check_cdr_enabled() ? "Yes" : "No",
02329 check_webmanager_enabled() ? "Yes" : "No"
02330 );
02331 return 0;
02332 }
02333
02334 static char mandescr_corestatus[] =
02335 "Description: Query for Core PBX status.\n"
02336 "Variables: (Names marked with * are optional)\n"
02337 " *ActionID: ActionID of this transaction\n";
02338
02339
02340 static int action_corestatus(struct mansession *s, const struct message *m)
02341 {
02342 const char *actionid = astman_get_header(m, "ActionID");
02343 char idText[150];
02344 char startuptime[150];
02345 char reloadtime[150];
02346 struct tm tm;
02347
02348 if (!ast_strlen_zero(actionid))
02349 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
02350
02351 ast_localtime(&ast_startuptime, &tm, NULL);
02352 strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
02353 ast_localtime(&ast_lastreloadtime, &tm, NULL);
02354 strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
02355
02356 astman_append(s, "Response: Success\r\n"
02357 "%s"
02358 "CoreStartupTime: %s\r\n"
02359 "CoreReloadTime: %s\r\n"
02360 "CoreCurrentCalls: %d\r\n"
02361 "\r\n",
02362 idText,
02363 startuptime,
02364 reloadtime,
02365 ast_active_channels()
02366 );
02367 return 0;
02368 }
02369
02370 static int process_message(struct mansession *s, const struct message *m)
02371 {
02372 char action[80] = "";
02373 struct manager_action *tmp;
02374 const char *id = astman_get_header(m,"ActionID");
02375 char idText[256] = "";
02376 int ret = 0;
02377
02378 ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
02379 if (option_debug)
02380 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
02381
02382 if (ast_strlen_zero(action)) {
02383 astman_send_error(s, m, "Missing action in request");
02384 return 0;
02385 }
02386 if (!ast_strlen_zero(id)) {
02387 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02388 }
02389 if (!s->session->authenticated) {
02390 if (!strcasecmp(action, "Challenge")) {
02391 const char *authtype = astman_get_header(m, "AuthType");
02392
02393 if (!strcasecmp(authtype, "MD5")) {
02394 if (ast_strlen_zero(s->session->challenge))
02395 snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
02396 astman_append(s, "Response: Success\r\n"
02397 "%s"
02398 "Challenge: %s\r\n\r\n",
02399 idText, s->session->challenge);
02400 return 0;
02401 } else {
02402 astman_send_error(s, m, "Must specify AuthType");
02403 return 0;
02404 }
02405 } else if (!strcasecmp(action, "Login")) {
02406 if (authenticate(s, m)) {
02407 sleep(1);
02408 astman_send_error(s, m, "Authentication failed");
02409 return -1;
02410 } else {
02411 s->session->authenticated = 1;
02412 ast_atomic_fetchadd_int(&unauth_sessions, -1);
02413 if (option_verbose > 1) {
02414 if (displayconnects) {
02415 ast_verbose(VERBOSE_PREFIX_2 "%sManager '%s' logged on from %s\n",
02416 (s->session->sessiontimeout ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
02417 }
02418 }
02419 ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n",
02420 (s->session->sessiontimeout ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
02421 astman_send_ack(s, m, "Authentication accepted");
02422 if (ast_opt_send_fullybooted && ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
02423 char auth[80];
02424 authority_to_str(EVENT_FLAG_SYSTEM, auth, sizeof(auth));
02425 astman_append(s, "Event: FullyBooted\r\n"
02426 "Privilege: %s\r\n"
02427 "Status: Fully Booted\r\n\r\n",
02428 auth);
02429 }
02430 }
02431 } else if (!strcasecmp(action, "Logoff")) {
02432 astman_send_ack(s, m, "See ya");
02433 return -1;
02434 } else
02435 astman_send_error(s, m, "Authentication Required");
02436 } else {
02437 if (!strcasecmp(action, "Login"))
02438 astman_send_ack(s, m, "Already logged in");
02439 else {
02440 ast_rwlock_rdlock(&actionlock);
02441 for (tmp = first_action; tmp; tmp = tmp->next) {
02442 if (strcasecmp(action, tmp->action))
02443 continue;
02444 if ((s->session->writeperm & tmp->authority) == tmp->authority) {
02445 if (tmp->func(s, m))
02446 ret = -1;
02447 } else
02448 astman_send_error(s, m, "Permission denied");
02449 break;
02450 }
02451 ast_rwlock_unlock(&actionlock);
02452 if (!tmp)
02453 astman_send_error(s, m, "Invalid/unknown command");
02454 }
02455 }
02456 if (ret)
02457 return ret;
02458 return process_events(s);
02459 }
02460
02461 static int get_input(struct mansession_session *s, char *output)
02462 {
02463
02464 int res;
02465 int x;
02466 struct pollfd fds[1];
02467 int timeout = -1;
02468 time_t now;
02469 for (x = 1; x < s->inlen; x++) {
02470 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
02471
02472 memcpy(output, s->inbuf, x + 1);
02473
02474 output[x+1] = '\0';
02475
02476 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
02477 s->inlen -= (x + 1);
02478 return 1;
02479 }
02480 }
02481 if (s->inlen >= sizeof(s->inbuf) - 1) {
02482 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->sin.sin_addr), s->inbuf);
02483 s->inlen = 0;
02484 }
02485 fds[0].fd = s->fd;
02486 fds[0].events = POLLIN;
02487
02488 do {
02489
02490 if (!s->authenticated) {
02491 if(time(&now) == -1) {
02492 ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
02493 return -1;
02494 }
02495
02496 timeout = (authtimeout - (now - s->authstart)) * 1000;
02497 if (timeout < 0) {
02498
02499 return 0;
02500 }
02501 }
02502
02503 ast_mutex_lock(&s->__lock);
02504 if (s->pending_event) {
02505 s->pending_event = 0;
02506 ast_mutex_unlock(&s->__lock);
02507 return 0;
02508 }
02509 s->waiting_thread = pthread_self();
02510 ast_mutex_unlock(&s->__lock);
02511
02512 res = ast_poll(fds, 1, timeout);
02513
02514 ast_mutex_lock(&s->__lock);
02515 s->waiting_thread = AST_PTHREADT_NULL;
02516 ast_mutex_unlock(&s->__lock);
02517 if (res < 0) {
02518 if (errno == EINTR || errno == EAGAIN) {
02519 return 0;
02520 }
02521 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
02522 return -1;
02523 } else if (res > 0) {
02524 ast_mutex_lock(&s->__lock);
02525 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
02526 ast_mutex_unlock(&s->__lock);
02527 if (res < 1)
02528 return -1;
02529 break;
02530 } else {
02531
02532 return 0;
02533 }
02534 } while(1);
02535 s->inlen += res;
02536 s->inbuf[s->inlen] = '\0';
02537 return 0;
02538 }
02539
02540 static int do_message(struct mansession *s)
02541 {
02542 struct message m = { 0 };
02543 char header_buf[sizeof(s->session->inbuf)] = { '\0' };
02544 int res;
02545 time_t now;
02546
02547 for (;;) {
02548
02549 if (s->session->eventq->next) {
02550 if (process_events(s))
02551 return -1;
02552 }
02553 res = get_input(s->session, header_buf);
02554 if (res == 0) {
02555 if (!s->session->authenticated) {
02556 if(time(&now) == -1) {
02557 ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
02558 return -1;
02559 }
02560
02561 if (now - s->session->authstart > authtimeout) {
02562 ast_log(LOG_EVENT, "Client from %s, failed to authenticate in %d seconds\n", ast_inet_ntoa(s->session->sin.sin_addr), authtimeout);
02563 return -1;
02564 }
02565 }
02566 continue;
02567 } else if (res > 0) {
02568
02569 if (strlen(header_buf) < 2)
02570 continue;
02571 header_buf[strlen(header_buf) - 2] = '\0';
02572 if (ast_strlen_zero(header_buf))
02573 return process_message(s, &m) ? -1 : 0;
02574 else if (m.hdrcount < (AST_MAX_MANHEADERS - 1))
02575 m.headers[m.hdrcount++] = ast_strdupa(header_buf);
02576 } else {
02577 return res;
02578 }
02579 }
02580 }
02581
02582 static void *session_do(void *data)
02583 {
02584 struct mansession_session *session = data;
02585 int res;
02586 struct mansession s = { .session = session, .fd = session->fd };
02587
02588 astman_append(&s, "Asterisk Call Manager/1.0\r\n");
02589 for (;;) {
02590 if ((res = do_message(&s)) < 0)
02591 break;
02592 }
02593 if (session->authenticated) {
02594 if (option_verbose > 1) {
02595 if (displayconnects)
02596 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
02597 }
02598 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
02599 } else {
02600 ast_atomic_fetchadd_int(&unauth_sessions, -1);
02601 if (option_verbose > 1) {
02602 if (displayconnects)
02603 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
02604 }
02605 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(session->sin.sin_addr));
02606 }
02607
02608
02609
02610
02611
02612
02613
02614 destroy_session(session);
02615 return NULL;
02616 }
02617
02618 static void *accept_thread(void *ignore)
02619 {
02620 int as;
02621 struct sockaddr_in sin;
02622 socklen_t sinlen;
02623 struct eventqent *eqe;
02624 struct mansession_session *s;
02625 struct protoent *p;
02626 int arg = 1;
02627 int flags;
02628 pthread_t t;
02629 pthread_attr_t attr;
02630 time_t now;
02631 struct pollfd pfds[1];
02632
02633 pthread_attr_init(&attr);
02634 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02635
02636 for (;;) {
02637 time(&now);
02638 AST_LIST_LOCK(&sessions);
02639 AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, s, list) {
02640 if (s->sessiontimeout && (now > s->sessiontimeout) && !s->inuse) {
02641 AST_LIST_REMOVE_CURRENT(&sessions, list);
02642 num_sessions--;
02643 if (s->authenticated && (option_verbose > 1) && displayconnects) {
02644 ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' timed out from %s\n",
02645 s->username, ast_inet_ntoa(s->sin.sin_addr));
02646 }
02647 free_session(s);
02648 break;
02649 }
02650 }
02651 AST_LIST_TRAVERSE_SAFE_END
02652
02653
02654 eqe = master_eventq;
02655 while (master_eventq->next && !master_eventq->usecount) {
02656 eqe = master_eventq;
02657 master_eventq = master_eventq->next;
02658 free(eqe);
02659 }
02660 AST_LIST_UNLOCK(&sessions);
02661
02662 sinlen = sizeof(sin);
02663 pfds[0].fd = asock;
02664 pfds[0].events = POLLIN;
02665
02666
02667 if (ast_poll(pfds, 1, 5000) < 1)
02668 continue;
02669 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
02670 if (as < 0) {
02671 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
02672 continue;
02673 }
02674
02675 if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= authlimit) {
02676 close(as);
02677 ast_atomic_fetchadd_int(&unauth_sessions, -1);
02678 ast_log(LOG_WARNING, "manager connection rejected, too many unauthenticated sessions.\n");
02679 continue;
02680 }
02681
02682 p = getprotobyname("tcp");
02683 if (p) {
02684 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
02685 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
02686 }
02687 }
02688 if (!(s = ast_calloc(1, sizeof(*s)))) {
02689 close(as);
02690 ast_atomic_fetchadd_int(&unauth_sessions, -1);
02691 continue;
02692 }
02693
02694 memcpy(&s->sin, &sin, sizeof(sin));
02695 s->writetimeout = 100;
02696 s->waiting_thread = AST_PTHREADT_NULL;
02697
02698 if (!block_sockets) {
02699
02700 flags = fcntl(as, F_GETFL);
02701 fcntl(as, F_SETFL, flags | O_NONBLOCK);
02702 } else {
02703 flags = fcntl(as, F_GETFL);
02704 fcntl(as, F_SETFL, flags & ~O_NONBLOCK);
02705 }
02706 ast_mutex_init(&s->__lock);
02707 s->fd = as;
02708 s->send_events = -1;
02709 AST_LIST_LOCK(&sessions);
02710 AST_LIST_INSERT_HEAD(&sessions, s, list);
02711 num_sessions++;
02712
02713
02714 s->eventq = master_eventq;
02715 while(s->eventq->next)
02716 s->eventq = s->eventq->next;
02717 ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
02718 AST_LIST_UNLOCK(&sessions);
02719 if(time(&s->authstart) == -1) {
02720 ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
02721 ast_atomic_fetchadd_int(&unauth_sessions, -1);
02722 destroy_session(s);
02723 continue;
02724 }
02725 if (ast_pthread_create_background(&t, &attr, session_do, s)) {
02726 ast_atomic_fetchadd_int(&unauth_sessions, -1);
02727 destroy_session(s);
02728 }
02729 }
02730 pthread_attr_destroy(&attr);
02731 return NULL;
02732 }
02733
02734 static int append_event(const char *str, int category)
02735 {
02736 struct eventqent *tmp, *prev = NULL;
02737 tmp = ast_malloc(sizeof(*tmp) + strlen(str));
02738
02739 if (!tmp)
02740 return -1;
02741
02742 tmp->next = NULL;
02743 tmp->category = category;
02744 strcpy(tmp->eventdata, str);
02745
02746 if (master_eventq) {
02747 prev = master_eventq;
02748 while (prev->next)
02749 prev = prev->next;
02750 prev->next = tmp;
02751 } else {
02752 master_eventq = tmp;
02753 }
02754
02755 tmp->usecount = num_sessions;
02756
02757 return 0;
02758 }
02759
02760
02761 int manager_event(int category, const char *event, const char *fmt, ...)
02762 {
02763 struct mansession_session *s;
02764 char auth[80];
02765 va_list ap;
02766 struct timeval now;
02767 struct ast_dynamic_str *buf;
02768
02769
02770 if (!num_sessions)
02771 return 0;
02772
02773 if (!(buf = ast_dynamic_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE)))
02774 return -1;
02775
02776 ast_dynamic_str_thread_set(&buf, 0, &manager_event_buf,
02777 "Event: %s\r\nPrivilege: %s\r\n",
02778 event, authority_to_str(category, auth, sizeof(auth)));
02779
02780 if (timestampevents) {
02781 now = ast_tvnow();
02782 ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf,
02783 "Timestamp: %ld.%06lu\r\n",
02784 (long) now.tv_sec, (unsigned long) now.tv_usec);
02785 }
02786
02787 va_start(ap, fmt);
02788 ast_dynamic_str_thread_append_va(&buf, 0, &manager_event_buf, fmt, ap);
02789 va_end(ap);
02790
02791 ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf, "\r\n");
02792
02793
02794 AST_LIST_LOCK(&sessions);
02795 append_event(buf->str, category);
02796 AST_LIST_TRAVERSE(&sessions, s, list) {
02797 ast_mutex_lock(&s->__lock);
02798 if (s->waiting_thread != AST_PTHREADT_NULL)
02799 pthread_kill(s->waiting_thread, SIGURG);
02800 else
02801
02802
02803
02804
02805
02806 s->pending_event = 1;
02807 ast_mutex_unlock(&s->__lock);
02808 }
02809 AST_LIST_UNLOCK(&sessions);
02810
02811 return 0;
02812 }
02813
02814 int ast_manager_unregister(char *action)
02815 {
02816 struct manager_action *cur, *prev;
02817 struct timespec tv = { 5, };
02818
02819 if (ast_rwlock_timedwrlock(&actionlock, &tv)) {
02820 ast_log(LOG_ERROR, "Could not obtain lock on manager list\n");
02821 return -1;
02822 }
02823 cur = prev = first_action;
02824 while (cur) {
02825 if (!strcasecmp(action, cur->action)) {
02826 prev->next = cur->next;
02827 free(cur);
02828 if (option_verbose > 1)
02829 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
02830 ast_rwlock_unlock(&actionlock);
02831 return 0;
02832 }
02833 prev = cur;
02834 cur = cur->next;
02835 }
02836 ast_rwlock_unlock(&actionlock);
02837 return 0;
02838 }
02839
02840 static int manager_state_cb(char *context, char *exten, int state, void *data)
02841 {
02842
02843 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
02844 return 0;
02845 }
02846
02847 static int ast_manager_register_struct(struct manager_action *act)
02848 {
02849 struct manager_action *cur, *prev = NULL;
02850 int ret;
02851 struct timespec tv = { 5, };
02852
02853 if (ast_rwlock_timedwrlock(&actionlock, &tv)) {
02854 ast_log(LOG_ERROR, "Could not obtain lock on manager list\n");
02855 return -1;
02856 }
02857 cur = first_action;
02858 while (cur) {
02859 ret = strcasecmp(cur->action, act->action);
02860 if (ret == 0) {
02861 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
02862 ast_rwlock_unlock(&actionlock);
02863 return -1;
02864 } else if (ret > 0) {
02865
02866 if (prev) {
02867 act->next = prev->next;
02868 prev->next = act;
02869 } else {
02870 act->next = first_action;
02871 first_action = act;
02872 }
02873 break;
02874 }
02875 prev = cur;
02876 cur = cur->next;
02877 }
02878
02879 if (!cur) {
02880 if (prev)
02881 prev->next = act;
02882 else
02883 first_action = act;
02884 act->next = NULL;
02885 }
02886
02887 if (option_verbose > 1)
02888 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
02889 ast_rwlock_unlock(&actionlock);
02890 return 0;
02891 }
02892
02893
02894
02895 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
02896 {
02897 struct manager_action *cur;
02898
02899 cur = ast_malloc(sizeof(*cur));
02900 if (!cur)
02901 return -1;
02902
02903 cur->action = action;
02904 cur->authority = auth;
02905 cur->func = func;
02906 cur->synopsis = synopsis;
02907 cur->description = description;
02908 cur->next = NULL;
02909
02910 if (ast_manager_register_struct(cur)) {
02911 ast_free(cur);
02912 return -1;
02913 }
02914
02915 return 0;
02916 }
02917
02918
02919
02920 static struct mansession_session *find_session(uint32_t ident)
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 }
02937
02938 int astman_verify_session_readpermissions(uint32_t ident, int perm)
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 }
02956
02957 int astman_verify_session_writepermissions(uint32_t ident, int perm)
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 }
02975
02976 enum {
02977 FORMAT_RAW,
02978 FORMAT_HTML,
02979 FORMAT_XML,
02980 };
02981 static char *contenttype[] = { "plain", "html", "xml" };
02982
02983 static char *generic_http_callback(int format, struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
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
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
03018
03019
03020
03021
03022 while ((s->managerid = rand() ^ (unsigned long) s) == 0);
03023 AST_LIST_LOCK(&sessions);
03024 AST_LIST_INSERT_HEAD(&sessions, s, list);
03025
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
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™ 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> 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
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
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
03155
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 }
03186
03187 static char *manager_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
03188 {
03189 return generic_http_callback(FORMAT_HTML, requestor, uri, params, status, title, contentlength);
03190 }
03191
03192 static char *mxml_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
03193 {
03194 return generic_http_callback(FORMAT_XML, requestor, uri, params, status, title, contentlength);
03195 }
03196
03197 static char *rawman_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
03198 {
03199 return generic_http_callback(FORMAT_RAW, requestor, uri, params, status, title, contentlength);
03200 }
03201
03202 struct ast_http_uri rawmanuri = {
03203 .description = "Raw HTTP Manager Event Interface",
03204 .uri = "rawman",
03205 .has_subtree = 0,
03206 .callback = rawman_http_callback,
03207 };
03208
03209 struct ast_http_uri manageruri = {
03210 .description = "HTML Manager Event Interface",
03211 .uri = "manager",
03212 .has_subtree = 0,
03213 .callback = manager_http_callback,
03214 };
03215
03216 struct ast_http_uri managerxmluri = {
03217 .description = "XML Manager Event Interface",
03218 .uri = "mxml",
03219 .has_subtree = 0,
03220 .callback = mxml_http_callback,
03221 };
03222
03223 static int registered = 0;
03224 static int webregged = 0;
03225
03226 int init_manager(void)
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
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
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
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
03370 if (!(user = ast_get_manager_by_name_locked(cat))) {
03371 if (!(user = ast_calloc(1, sizeof(*user)))) {
03372 break;
03373 }
03374
03375 ast_copy_string(user->username, cat, sizeof(user->username));
03376
03377 AST_LIST_INSERT_TAIL(&users, user, list);
03378 }
03379
03380
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
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
03428 if (!(user = ast_get_manager_by_name_locked(cat))) {
03429 if (!(user = ast_calloc(1, sizeof(*user))))
03430 break;
03431
03432 ast_copy_string(user->username, cat, sizeof(user->username));
03433
03434 AST_LIST_INSERT_TAIL(&users, user, list);
03435 }
03436
03437
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
03471 AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
03472 if (user->keep) {
03473 user->keep = 0;
03474 continue;
03475 }
03476
03477 AST_LIST_REMOVE_CURRENT(&users, list);
03478
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
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 }
03547
03548 int reload_manager(void)
03549 {
03550 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
03551 return init_manager();
03552 }