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