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