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: 226138 $")
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 manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, body);
02279 return 0;
02280 }
02281
02282 static char mandescr_coresettings[] =
02283 "Description: Query for Core PBX settings.\n"
02284 "Variables: (Names marked with * are optional)\n"
02285 " *ActionID: ActionID of this transaction\n";
02286
02287
02288 static int action_coresettings(struct mansession *s, const struct message *m)
02289 {
02290 const char *actionid = astman_get_header(m, "ActionID");
02291 char idText[150] = "";
02292
02293 if (!ast_strlen_zero(actionid))
02294 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
02295
02296 astman_append(s, "Response: Success\r\n"
02297 "%s"
02298 "AMIversion: %s\r\n"
02299 "AsteriskVersion: %s\r\n"
02300 "SystemName: %s\r\n"
02301 "CoreMaxCalls: %d\r\n"
02302 "CoreMaxLoadAvg: %f\r\n"
02303 "CoreRunUser: %s\r\n"
02304 "CoreRunGroup: %s\r\n"
02305 "CoreMaxFilehandles: %d\r\n"
02306 "CoreRealTimeEnabled: %s\r\n"
02307 "CoreCDRenabled: %s\r\n"
02308 "CoreHTTPenabled: %s\r\n"
02309 "\r\n",
02310 idText,
02311 AMI_VERSION,
02312 ASTERISK_VERSION,
02313 ast_config_AST_SYSTEM_NAME,
02314 option_maxcalls,
02315 option_maxload,
02316 ast_config_AST_RUN_USER,
02317 ast_config_AST_RUN_GROUP,
02318 option_maxfiles,
02319 ast_realtime_enabled() ? "Yes" : "No",
02320 check_cdr_enabled() ? "Yes" : "No",
02321 check_webmanager_enabled() ? "Yes" : "No"
02322 );
02323 return 0;
02324 }
02325
02326 static char mandescr_corestatus[] =
02327 "Description: Query for Core PBX status.\n"
02328 "Variables: (Names marked with * are optional)\n"
02329 " *ActionID: ActionID of this transaction\n";
02330
02331
02332 static int action_corestatus(struct mansession *s, const struct message *m)
02333 {
02334 const char *actionid = astman_get_header(m, "ActionID");
02335 char idText[150];
02336 char startuptime[150];
02337 char reloadtime[150];
02338 struct tm tm;
02339
02340 if (!ast_strlen_zero(actionid))
02341 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
02342
02343 ast_localtime(&ast_startuptime, &tm, NULL);
02344 strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
02345 ast_localtime(&ast_lastreloadtime, &tm, NULL);
02346 strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
02347
02348 astman_append(s, "Response: Success\r\n"
02349 "%s"
02350 "CoreStartupTime: %s\r\n"
02351 "CoreReloadTime: %s\r\n"
02352 "CoreCurrentCalls: %d\r\n"
02353 "\r\n",
02354 idText,
02355 startuptime,
02356 reloadtime,
02357 ast_active_channels()
02358 );
02359 return 0;
02360 }
02361
02362 static int process_message(struct mansession *s, const struct message *m)
02363 {
02364 char action[80] = "";
02365 struct manager_action *tmp;
02366 const char *id = astman_get_header(m,"ActionID");
02367 char idText[256] = "";
02368 int ret = 0;
02369
02370 ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
02371 if (option_debug)
02372 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
02373
02374 if (ast_strlen_zero(action)) {
02375 astman_send_error(s, m, "Missing action in request");
02376 return 0;
02377 }
02378 if (!ast_strlen_zero(id)) {
02379 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02380 }
02381 if (!s->session->authenticated) {
02382 if (!strcasecmp(action, "Challenge")) {
02383 const char *authtype = astman_get_header(m, "AuthType");
02384
02385 if (!strcasecmp(authtype, "MD5")) {
02386 if (ast_strlen_zero(s->session->challenge))
02387 snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
02388 astman_append(s, "Response: Success\r\n"
02389 "%s"
02390 "Challenge: %s\r\n\r\n",
02391 idText, s->session->challenge);
02392 return 0;
02393 } else {
02394 astman_send_error(s, m, "Must specify AuthType");
02395 return 0;
02396 }
02397 } else if (!strcasecmp(action, "Login")) {
02398 if (authenticate(s, m)) {
02399 sleep(1);
02400 astman_send_error(s, m, "Authentication failed");
02401 return -1;
02402 } else {
02403 s->session->authenticated = 1;
02404 if (option_verbose > 1) {
02405 if (displayconnects) {
02406 ast_verbose(VERBOSE_PREFIX_2 "%sManager '%s' logged on from %s\n",
02407 (s->session->sessiontimeout ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
02408 }
02409 }
02410 ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n",
02411 (s->session->sessiontimeout ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
02412 astman_send_ack(s, m, "Authentication accepted");
02413 }
02414 } else if (!strcasecmp(action, "Logoff")) {
02415 astman_send_ack(s, m, "See ya");
02416 return -1;
02417 } else
02418 astman_send_error(s, m, "Authentication Required");
02419 } else {
02420 if (!strcasecmp(action, "Login"))
02421 astman_send_ack(s, m, "Already logged in");
02422 else {
02423 ast_rwlock_rdlock(&actionlock);
02424 for (tmp = first_action; tmp; tmp = tmp->next) {
02425 if (strcasecmp(action, tmp->action))
02426 continue;
02427 if ((s->session->writeperm & tmp->authority) == tmp->authority) {
02428 if (tmp->func(s, m))
02429 ret = -1;
02430 } else
02431 astman_send_error(s, m, "Permission denied");
02432 break;
02433 }
02434 ast_rwlock_unlock(&actionlock);
02435 if (!tmp)
02436 astman_send_error(s, m, "Invalid/unknown command");
02437 }
02438 }
02439 if (ret)
02440 return ret;
02441 return process_events(s);
02442 }
02443
02444 static int get_input(struct mansession_session *s, char *output)
02445 {
02446
02447 int res;
02448 int x;
02449 struct pollfd fds[1];
02450 for (x = 1; x < s->inlen; x++) {
02451 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
02452
02453 memcpy(output, s->inbuf, x + 1);
02454
02455 output[x+1] = '\0';
02456
02457 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
02458 s->inlen -= (x + 1);
02459 return 1;
02460 }
02461 }
02462 if (s->inlen >= sizeof(s->inbuf) - 1) {
02463 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->sin.sin_addr), s->inbuf);
02464 s->inlen = 0;
02465 }
02466 fds[0].fd = s->fd;
02467 fds[0].events = POLLIN;
02468 do {
02469 ast_mutex_lock(&s->__lock);
02470 if (s->pending_event) {
02471 s->pending_event = 0;
02472 ast_mutex_unlock(&s->__lock);
02473 return 0;
02474 }
02475 s->waiting_thread = pthread_self();
02476 ast_mutex_unlock(&s->__lock);
02477
02478 res = ast_poll(fds, 1, -1);
02479
02480 ast_mutex_lock(&s->__lock);
02481 s->waiting_thread = AST_PTHREADT_NULL;
02482 ast_mutex_unlock(&s->__lock);
02483 if (res < 0) {
02484 if (errno == EINTR || errno == EAGAIN) {
02485 return 0;
02486 }
02487 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
02488 return -1;
02489 } else if (res > 0) {
02490 ast_mutex_lock(&s->__lock);
02491 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
02492 ast_mutex_unlock(&s->__lock);
02493 if (res < 1)
02494 return -1;
02495 break;
02496 }
02497 } while(1);
02498 s->inlen += res;
02499 s->inbuf[s->inlen] = '\0';
02500 return 0;
02501 }
02502
02503 static int do_message(struct mansession *s)
02504 {
02505 struct message m = { 0 };
02506 char header_buf[sizeof(s->session->inbuf)] = { '\0' };
02507 int res;
02508
02509 for (;;) {
02510
02511 if (s->session->eventq->next) {
02512 if (process_events(s))
02513 return -1;
02514 }
02515 res = get_input(s->session, header_buf);
02516 if (res == 0) {
02517 continue;
02518 } else if (res > 0) {
02519
02520 if (strlen(header_buf) < 2)
02521 continue;
02522 header_buf[strlen(header_buf) - 2] = '\0';
02523 if (ast_strlen_zero(header_buf))
02524 return process_message(s, &m) ? -1 : 0;
02525 else if (m.hdrcount < (AST_MAX_MANHEADERS - 1))
02526 m.headers[m.hdrcount++] = ast_strdupa(header_buf);
02527 } else {
02528 return res;
02529 }
02530 }
02531 }
02532
02533 static void *session_do(void *data)
02534 {
02535 struct mansession_session *session = data;
02536 int res;
02537 struct mansession s = { .session = session, .fd = session->fd };
02538
02539 astman_append(&s, "Asterisk Call Manager/1.0\r\n");
02540 for (;;) {
02541 if ((res = do_message(&s)) < 0)
02542 break;
02543 }
02544 if (session->authenticated) {
02545 if (option_verbose > 1) {
02546 if (displayconnects)
02547 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
02548 }
02549 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
02550 } else {
02551 if (option_verbose > 1) {
02552 if (displayconnects)
02553 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
02554 }
02555 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(session->sin.sin_addr));
02556 }
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567
02568
02569 usleep(1);
02570
02571 destroy_session(session);
02572 return NULL;
02573 }
02574
02575 static void *accept_thread(void *ignore)
02576 {
02577 int as;
02578 struct sockaddr_in sin;
02579 socklen_t sinlen;
02580 struct eventqent *eqe;
02581 struct mansession_session *s;
02582 struct protoent *p;
02583 int arg = 1;
02584 int flags;
02585 pthread_attr_t attr;
02586 time_t now;
02587 struct pollfd pfds[1];
02588
02589 pthread_attr_init(&attr);
02590 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02591
02592 for (;;) {
02593 time(&now);
02594 AST_LIST_LOCK(&sessions);
02595 AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, s, list) {
02596 if (s->sessiontimeout && (now > s->sessiontimeout) && !s->inuse) {
02597 AST_LIST_REMOVE_CURRENT(&sessions, list);
02598 num_sessions--;
02599 if (s->authenticated && (option_verbose > 1) && displayconnects) {
02600 ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' timed out from %s\n",
02601 s->username, ast_inet_ntoa(s->sin.sin_addr));
02602 }
02603 free_session(s);
02604 break;
02605 }
02606 }
02607 AST_LIST_TRAVERSE_SAFE_END
02608
02609
02610 eqe = master_eventq;
02611 while (master_eventq->next && !master_eventq->usecount) {
02612 eqe = master_eventq;
02613 master_eventq = master_eventq->next;
02614 free(eqe);
02615 }
02616 AST_LIST_UNLOCK(&sessions);
02617
02618 sinlen = sizeof(sin);
02619 pfds[0].fd = asock;
02620 pfds[0].events = POLLIN;
02621
02622
02623 if (ast_poll(pfds, 1, 5000) < 1)
02624 continue;
02625 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
02626 if (as < 0) {
02627 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
02628 continue;
02629 }
02630 p = getprotobyname("tcp");
02631 if (p) {
02632 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
02633 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
02634 }
02635 }
02636 if (!(s = ast_calloc(1, sizeof(*s))))
02637 continue;
02638
02639 memcpy(&s->sin, &sin, sizeof(sin));
02640 s->writetimeout = 100;
02641 s->waiting_thread = AST_PTHREADT_NULL;
02642
02643 if (!block_sockets) {
02644
02645 flags = fcntl(as, F_GETFL);
02646 fcntl(as, F_SETFL, flags | O_NONBLOCK);
02647 } else {
02648 flags = fcntl(as, F_GETFL);
02649 fcntl(as, F_SETFL, flags & ~O_NONBLOCK);
02650 }
02651 ast_mutex_init(&s->__lock);
02652 s->fd = as;
02653 s->send_events = -1;
02654 AST_LIST_LOCK(&sessions);
02655 AST_LIST_INSERT_HEAD(&sessions, s, list);
02656 num_sessions++;
02657
02658
02659 s->eventq = master_eventq;
02660 while(s->eventq->next)
02661 s->eventq = s->eventq->next;
02662 ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
02663 AST_LIST_UNLOCK(&sessions);
02664 if (ast_pthread_create_background(&s->t, &attr, session_do, s))
02665 destroy_session(s);
02666 }
02667 pthread_attr_destroy(&attr);
02668 return NULL;
02669 }
02670
02671 static int append_event(const char *str, int category)
02672 {
02673 struct eventqent *tmp, *prev = NULL;
02674 tmp = ast_malloc(sizeof(*tmp) + strlen(str));
02675
02676 if (!tmp)
02677 return -1;
02678
02679 tmp->next = NULL;
02680 tmp->category = category;
02681 strcpy(tmp->eventdata, str);
02682
02683 if (master_eventq) {
02684 prev = master_eventq;
02685 while (prev->next)
02686 prev = prev->next;
02687 prev->next = tmp;
02688 } else {
02689 master_eventq = tmp;
02690 }
02691
02692 tmp->usecount = num_sessions;
02693
02694 return 0;
02695 }
02696
02697
02698 int manager_event(int category, const char *event, const char *fmt, ...)
02699 {
02700 struct mansession_session *s;
02701 char auth[80];
02702 va_list ap;
02703 struct timeval now;
02704 struct ast_dynamic_str *buf;
02705
02706
02707 if (!num_sessions)
02708 return 0;
02709
02710 if (!(buf = ast_dynamic_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE)))
02711 return -1;
02712
02713 ast_dynamic_str_thread_set(&buf, 0, &manager_event_buf,
02714 "Event: %s\r\nPrivilege: %s\r\n",
02715 event, authority_to_str(category, auth, sizeof(auth)));
02716
02717 if (timestampevents) {
02718 now = ast_tvnow();
02719 ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf,
02720 "Timestamp: %ld.%06lu\r\n",
02721 now.tv_sec, (unsigned long) now.tv_usec);
02722 }
02723
02724 va_start(ap, fmt);
02725 ast_dynamic_str_thread_append_va(&buf, 0, &manager_event_buf, fmt, ap);
02726 va_end(ap);
02727
02728 ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf, "\r\n");
02729
02730
02731 AST_LIST_LOCK(&sessions);
02732 append_event(buf->str, category);
02733 AST_LIST_TRAVERSE(&sessions, s, list) {
02734 ast_mutex_lock(&s->__lock);
02735 if (s->waiting_thread != AST_PTHREADT_NULL)
02736 pthread_kill(s->waiting_thread, SIGURG);
02737 else
02738
02739
02740
02741
02742
02743 s->pending_event = 1;
02744 ast_mutex_unlock(&s->__lock);
02745 }
02746 AST_LIST_UNLOCK(&sessions);
02747
02748 return 0;
02749 }
02750
02751 int ast_manager_unregister(char *action)
02752 {
02753 struct manager_action *cur, *prev;
02754 struct timespec tv = { 5, };
02755
02756 if (ast_rwlock_timedwrlock(&actionlock, &tv)) {
02757 ast_log(LOG_ERROR, "Could not obtain lock on manager list\n");
02758 return -1;
02759 }
02760 cur = prev = first_action;
02761 while (cur) {
02762 if (!strcasecmp(action, cur->action)) {
02763 prev->next = cur->next;
02764 free(cur);
02765 if (option_verbose > 1)
02766 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
02767 ast_rwlock_unlock(&actionlock);
02768 return 0;
02769 }
02770 prev = cur;
02771 cur = cur->next;
02772 }
02773 ast_rwlock_unlock(&actionlock);
02774 return 0;
02775 }
02776
02777 static int manager_state_cb(char *context, char *exten, int state, void *data)
02778 {
02779
02780 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
02781 return 0;
02782 }
02783
02784 static int ast_manager_register_struct(struct manager_action *act)
02785 {
02786 struct manager_action *cur, *prev = NULL;
02787 int ret;
02788 struct timespec tv = { 5, };
02789
02790 if (ast_rwlock_timedwrlock(&actionlock, &tv)) {
02791 ast_log(LOG_ERROR, "Could not obtain lock on manager list\n");
02792 return -1;
02793 }
02794 cur = first_action;
02795 while (cur) {
02796 ret = strcasecmp(cur->action, act->action);
02797 if (ret == 0) {
02798 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
02799 ast_rwlock_unlock(&actionlock);
02800 return -1;
02801 } else if (ret > 0) {
02802
02803 if (prev) {
02804 act->next = prev->next;
02805 prev->next = act;
02806 } else {
02807 act->next = first_action;
02808 first_action = act;
02809 }
02810 break;
02811 }
02812 prev = cur;
02813 cur = cur->next;
02814 }
02815
02816 if (!cur) {
02817 if (prev)
02818 prev->next = act;
02819 else
02820 first_action = act;
02821 act->next = NULL;
02822 }
02823
02824 if (option_verbose > 1)
02825 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
02826 ast_rwlock_unlock(&actionlock);
02827 return 0;
02828 }
02829
02830
02831
02832 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
02833 {
02834 struct manager_action *cur;
02835
02836 cur = ast_malloc(sizeof(*cur));
02837 if (!cur)
02838 return -1;
02839
02840 cur->action = action;
02841 cur->authority = auth;
02842 cur->func = func;
02843 cur->synopsis = synopsis;
02844 cur->description = description;
02845 cur->next = NULL;
02846
02847 if (ast_manager_register_struct(cur)) {
02848 ast_free(cur);
02849 return -1;
02850 }
02851
02852 return 0;
02853 }
02854
02855
02856
02857 static struct mansession_session *find_session(uint32_t ident)
02858 {
02859 struct mansession_session *s;
02860
02861 AST_LIST_LOCK(&sessions);
02862 AST_LIST_TRAVERSE(&sessions, s, list) {
02863 ast_mutex_lock(&s->__lock);
02864 if (s->sessiontimeout && (s->managerid == ident) && !s->needdestroy) {
02865 s->inuse++;
02866 break;
02867 }
02868 ast_mutex_unlock(&s->__lock);
02869 }
02870 AST_LIST_UNLOCK(&sessions);
02871
02872 return s;
02873 }
02874
02875 int astman_verify_session_readpermissions(uint32_t ident, int perm)
02876 {
02877 int result = 0;
02878 struct mansession_session *s;
02879
02880 AST_LIST_LOCK(&sessions);
02881 AST_LIST_TRAVERSE(&sessions, s, list) {
02882 ast_mutex_lock(&s->__lock);
02883 if ((s->managerid == ident) && (s->readperm & perm)) {
02884 result = 1;
02885 ast_mutex_unlock(&s->__lock);
02886 break;
02887 }
02888 ast_mutex_unlock(&s->__lock);
02889 }
02890 AST_LIST_UNLOCK(&sessions);
02891 return result;
02892 }
02893
02894 int astman_verify_session_writepermissions(uint32_t ident, int perm)
02895 {
02896 int result = 0;
02897 struct mansession_session *s;
02898
02899 AST_LIST_LOCK(&sessions);
02900 AST_LIST_TRAVERSE(&sessions, s, list) {
02901 ast_mutex_lock(&s->__lock);
02902 if ((s->managerid == ident) && (s->writeperm & perm)) {
02903 result = 1;
02904 ast_mutex_unlock(&s->__lock);
02905 break;
02906 }
02907 ast_mutex_unlock(&s->__lock);
02908 }
02909 AST_LIST_UNLOCK(&sessions);
02910 return result;
02911 }
02912
02913 enum {
02914 FORMAT_RAW,
02915 FORMAT_HTML,
02916 FORMAT_XML,
02917 };
02918 static char *contenttype[] = { "plain", "html", "xml" };
02919
02920 static char *generic_http_callback(int format, struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
02921 {
02922 struct mansession_session *s = NULL;
02923 struct mansession ss = { .session = NULL, };
02924 uint32_t ident = 0;
02925 char workspace[512];
02926 char cookie[128];
02927 size_t len = sizeof(workspace);
02928 int blastaway = 0;
02929 char *c = workspace;
02930 char *retval = NULL;
02931 struct ast_variable *v;
02932
02933 for (v = params; v; v = v->next) {
02934 if (!strcasecmp(v->name, "mansession_id")) {
02935 sscanf(v->value, "%30x", &ident);
02936 break;
02937 }
02938 }
02939
02940 if (!(s = find_session(ident))) {
02941
02942 if (!(s = ast_calloc(1, sizeof(*s)))) {
02943 *status = 500;
02944 goto generic_callback_out;
02945 }
02946 memcpy(&s->sin, requestor, sizeof(s->sin));
02947 s->fd = -1;
02948 s->waiting_thread = AST_PTHREADT_NULL;
02949 s->send_events = 0;
02950 ast_mutex_init(&s->__lock);
02951 ast_mutex_lock(&s->__lock);
02952 s->inuse = 1;
02953
02954
02955
02956
02957
02958 while ((s->managerid = rand() ^ (unsigned long) s) == 0);
02959 AST_LIST_LOCK(&sessions);
02960 AST_LIST_INSERT_HEAD(&sessions, s, list);
02961
02962 s->eventq = master_eventq;
02963 while (s->eventq->next)
02964 s->eventq = s->eventq->next;
02965 ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
02966 ast_atomic_fetchadd_int(&num_sessions, 1);
02967 AST_LIST_UNLOCK(&sessions);
02968 }
02969
02970
02971 time(&s->sessiontimeout);
02972 if (!s->authenticated && (httptimeout > 5))
02973 s->sessiontimeout += 5;
02974 else
02975 s->sessiontimeout += httptimeout;
02976 ss.session = s;
02977 ast_mutex_unlock(&s->__lock);
02978
02979 ss.f = tmpfile();
02980 ss.fd = fileno(ss.f);
02981
02982 if (s) {
02983 struct message m = { 0 };
02984 char tmp[80];
02985 unsigned int x;
02986 size_t hdrlen;
02987
02988 for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
02989 hdrlen = strlen(v->name) + strlen(v->value) + 3;
02990 m.headers[m.hdrcount] = alloca(hdrlen);
02991 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
02992 m.hdrcount = x + 1;
02993 }
02994
02995 if (process_message(&ss, &m)) {
02996 if (s->authenticated) {
02997 if (option_verbose > 1) {
02998 if (displayconnects)
02999 ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
03000 }
03001 ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
03002 } else {
03003 if (option_verbose > 1) {
03004 if (displayconnects)
03005 ast_verbose(VERBOSE_PREFIX_2 "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
03006 }
03007 ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
03008 }
03009 s->needdestroy = 1;
03010 }
03011 ast_build_string(&c, &len, "Content-type: text/%s\r\n", contenttype[format]);
03012 sprintf(tmp, "%08x", s->managerid);
03013 ast_build_string(&c, &len, "%s\r\n", ast_http_setcookie("mansession_id", tmp, httptimeout, cookie, sizeof(cookie)));
03014 if (format == FORMAT_HTML)
03015 ast_build_string(&c, &len, "<title>Asterisk™ Manager Interface</title>");
03016 if (format == FORMAT_XML) {
03017 ast_build_string(&c, &len, "<ajax-response>\n");
03018 } else if (format == FORMAT_HTML) {
03019 ast_build_string(&c, &len, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
03020 ast_build_string(&c, &len, "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\"><h1> Manager Tester</h1></td></tr>\r\n");
03021 }
03022 ast_mutex_lock(&s->__lock);
03023 if (ss.fd > -1) {
03024 char *buf;
03025 size_t l;
03026
03027
03028 fprintf(ss.f, "%c", 0);
03029
03030 if ((l = lseek(ss.fd, 0, SEEK_END)) > 0) {
03031 if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, ss.fd, 0))) {
03032 ast_log(LOG_WARNING, "mmap failed. Manager request output was not processed\n");
03033 } else {
03034 char *tmpbuf;
03035 if (format == FORMAT_XML)
03036 tmpbuf = xml_translate(buf, params);
03037 else if (format == FORMAT_HTML)
03038 tmpbuf = html_translate(buf);
03039 else
03040 tmpbuf = buf;
03041 if (tmpbuf) {
03042 size_t wlen, tlen;
03043 if ((retval = malloc((wlen = strlen(workspace)) + (tlen = strlen(tmpbuf)) + 128))) {
03044 strcpy(retval, workspace);
03045 strcpy(retval + wlen, tmpbuf);
03046 c = retval + wlen + tlen;
03047
03048 len = 120;
03049 }
03050 }
03051 if (tmpbuf != buf)
03052 free(tmpbuf);
03053 free(s->outputstr);
03054 s->outputstr = NULL;
03055 munmap(buf, l);
03056 }
03057 }
03058 fclose(ss.f);
03059 ss.f = NULL;
03060 ss.fd = -1;
03061 } else if (s->outputstr) {
03062 char *tmp;
03063 if (format == FORMAT_XML)
03064 tmp = xml_translate(s->outputstr->str, params);
03065 else if (format == FORMAT_HTML)
03066 tmp = html_translate(s->outputstr->str);
03067 else
03068 tmp = s->outputstr->str;
03069 if (tmp) {
03070 retval = malloc(strlen(workspace) + strlen(tmp) + 128);
03071 if (retval) {
03072 strcpy(retval, workspace);
03073 strcpy(retval + strlen(retval), tmp);
03074 c = retval + strlen(retval);
03075 len = 120;
03076 }
03077 }
03078 if (tmp != s->outputstr->str)
03079 free(tmp);
03080 free(s->outputstr);
03081 s->outputstr = NULL;
03082 }
03083 ast_mutex_unlock(&s->__lock);
03084
03085
03086 if (format == FORMAT_XML) {
03087 ast_build_string(&c, &len, "</ajax-response>\n");
03088 } else if (format == FORMAT_HTML)
03089 ast_build_string(&c, &len, "</table></body>\r\n");
03090 } else {
03091 *status = 500;
03092 *title = strdup("Server Error");
03093 }
03094 ast_mutex_lock(&s->__lock);
03095 if (s->needdestroy) {
03096 if (s->inuse == 1) {
03097 ast_log(LOG_DEBUG, "Need destroy, doing it now!\n");
03098 blastaway = 1;
03099 } else {
03100 ast_log(LOG_DEBUG, "Need destroy, but can't do it yet!\n");
03101 if (s->waiting_thread != AST_PTHREADT_NULL)
03102 pthread_kill(s->waiting_thread, SIGURG);
03103 s->inuse--;
03104 }
03105 } else
03106 s->inuse--;
03107 ast_mutex_unlock(&s->__lock);
03108
03109 if (blastaway)
03110 destroy_session(s);
03111 generic_callback_out:
03112 if (*status != 200)
03113 return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n");
03114 return retval;
03115 }
03116
03117 static char *manager_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
03118 {
03119 return generic_http_callback(FORMAT_HTML, requestor, uri, params, status, title, contentlength);
03120 }
03121
03122 static char *mxml_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
03123 {
03124 return generic_http_callback(FORMAT_XML, requestor, uri, params, status, title, contentlength);
03125 }
03126
03127 static char *rawman_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
03128 {
03129 return generic_http_callback(FORMAT_RAW, requestor, uri, params, status, title, contentlength);
03130 }
03131
03132 struct ast_http_uri rawmanuri = {
03133 .description = "Raw HTTP Manager Event Interface",
03134 .uri = "rawman",
03135 .has_subtree = 0,
03136 .callback = rawman_http_callback,
03137 };
03138
03139 struct ast_http_uri manageruri = {
03140 .description = "HTML Manager Event Interface",
03141 .uri = "manager",
03142 .has_subtree = 0,
03143 .callback = manager_http_callback,
03144 };
03145
03146 struct ast_http_uri managerxmluri = {
03147 .description = "XML Manager Event Interface",
03148 .uri = "mxml",
03149 .has_subtree = 0,
03150 .callback = mxml_http_callback,
03151 };
03152
03153 static int registered = 0;
03154 static int webregged = 0;
03155
03156 int init_manager(void)
03157 {
03158 struct ast_config *cfg = NULL, *ucfg = NULL;
03159 const char *val;
03160 char *cat = NULL;
03161 int oldportno = portno;
03162 static struct sockaddr_in ba;
03163 int x = 1;
03164 int flags;
03165 int newhttptimeout = 60;
03166 struct ast_manager_user *user = NULL;
03167
03168 if (!registered) {
03169
03170 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
03171 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
03172 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
03173 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
03174 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
03175 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
03176 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
03177 ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
03178 ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
03179 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
03180 ast_manager_register2("Atxfer", EVENT_FLAG_CALL, action_atxfer, "Attended transfer", mandescr_atxfer );
03181 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
03182 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
03183 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
03184 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
03185 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
03186 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
03187 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
03188 ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent);
03189 ast_manager_register2("CoreSettings", EVENT_FLAG_SYSTEM, action_coresettings, "Show PBX core settings (version etc)", mandescr_coresettings);
03190 ast_manager_register2("CoreStatus", EVENT_FLAG_SYSTEM, action_corestatus, "Show PBX core status variables", mandescr_corestatus);
03191 ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent);
03192
03193 ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry));
03194 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
03195 registered = 1;
03196
03197 append_event("Event: Placeholder\r\n\r\n", 0);
03198 }
03199 portno = DEFAULT_MANAGER_PORT;
03200 displayconnects = 1;
03201 cfg = ast_config_load("manager.conf");
03202 if (!cfg) {
03203 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
03204 return 0;
03205 }
03206 if ((val = ast_variable_retrieve(cfg, "general", "enabled"))) {
03207 manager_enabled = ast_true(val);
03208 }
03209 if ((val = ast_variable_retrieve(cfg, "general", "block-sockets"))) {
03210 block_sockets = ast_true(val);
03211 }
03212 if((val = ast_variable_retrieve(cfg, "general", "webenabled"))) {
03213 webmanager_enabled = ast_true(val);
03214 }
03215 if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
03216 if (sscanf(val, "%5d", &portno) != 1) {
03217 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
03218 portno = DEFAULT_MANAGER_PORT;
03219 }
03220 }
03221
03222 if ((val = ast_variable_retrieve(cfg, "general", "displayconnects"))) {
03223 displayconnects = ast_true(val);
03224 }
03225 if ((val = ast_variable_retrieve(cfg, "general", "timestampevents"))) {
03226 timestampevents = ast_true(val);
03227 }
03228 if ((val = ast_variable_retrieve(cfg, "general", "httptimeout"))) {
03229 newhttptimeout = atoi(val);
03230 }
03231
03232 memset(&ba, 0, sizeof(ba));
03233 ba.sin_family = AF_INET;
03234 ba.sin_port = htons(portno);
03235
03236 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
03237 if (!inet_aton(val, &ba.sin_addr)) {
03238 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
03239 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
03240 }
03241 }
03242
03243
03244 if ((asock > -1) && ((portno != oldportno) || !manager_enabled)) {
03245 #if 0
03246
03247 close(asock);
03248 asock = -1;
03249 #else
03250 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
03251 #endif
03252 }
03253
03254 AST_LIST_LOCK(&users);
03255
03256 if ((ucfg = ast_config_load("users.conf"))) {
03257 while ((cat = ast_category_browse(ucfg, cat))) {
03258 int hasmanager = 0;
03259 struct ast_variable *var = NULL;
03260
03261 if (!strcasecmp(cat, "general")) {
03262 continue;
03263 }
03264
03265 if (!(hasmanager = ast_true(ast_variable_retrieve(ucfg, cat, "hasmanager")))) {
03266 continue;
03267 }
03268
03269
03270 if (!(user = ast_get_manager_by_name_locked(cat))) {
03271 if (!(user = ast_calloc(1, sizeof(*user)))) {
03272 break;
03273 }
03274
03275 ast_copy_string(user->username, cat, sizeof(user->username));
03276
03277 AST_LIST_INSERT_TAIL(&users, user, list);
03278 }
03279
03280
03281 user->keep = 1;
03282
03283 for (var = ast_variable_browse(ucfg, cat); var; var = var->next) {
03284 if (!strcasecmp(var->name, "secret")) {
03285 if (user->secret) {
03286 free(user->secret);
03287 }
03288 user->secret = ast_strdup(var->value);
03289 } else if (!strcasecmp(var->name, "deny") ) {
03290 if (user->deny) {
03291 free(user->deny);
03292 }
03293 user->deny = ast_strdup(var->value);
03294 } else if (!strcasecmp(var->name, "permit") ) {
03295 if (user->permit) {
03296 free(user->permit);
03297 }
03298 user->permit = ast_strdup(var->value);
03299 } else if (!strcasecmp(var->name, "read") ) {
03300 if (user->read) {
03301 free(user->read);
03302 }
03303 user->read = ast_strdup(var->value);
03304 } else if (!strcasecmp(var->name, "write") ) {
03305 if (user->write) {
03306 free(user->write);
03307 }
03308 user->write = ast_strdup(var->value);
03309 } else if (!strcasecmp(var->name, "displayconnects") ) {
03310 user->displayconnects = ast_true(var->value);
03311 } else if (!strcasecmp(var->name, "hasmanager")) {
03312
03313 } else {
03314 ast_log(LOG_DEBUG, "%s is an unknown option (to the manager module).\n", var->name);
03315 }
03316 }
03317 }
03318 ast_config_destroy(ucfg);
03319 }
03320
03321 while ((cat = ast_category_browse(cfg, cat))) {
03322 struct ast_variable *var = NULL;
03323
03324 if (!strcasecmp(cat, "general"))
03325 continue;
03326
03327
03328 if (!(user = ast_get_manager_by_name_locked(cat))) {
03329 if (!(user = ast_calloc(1, sizeof(*user))))
03330 break;
03331
03332 ast_copy_string(user->username, cat, sizeof(user->username));
03333
03334 AST_LIST_INSERT_TAIL(&users, user, list);
03335 }
03336
03337
03338 user->keep = 1;
03339
03340 var = ast_variable_browse(cfg, cat);
03341 while (var) {
03342 if (!strcasecmp(var->name, "secret")) {
03343 if (user->secret)
03344 free(user->secret);
03345 user->secret = ast_strdup(var->value);
03346 } else if (!strcasecmp(var->name, "deny") ) {
03347 if (user->deny)
03348 free(user->deny);
03349 user->deny = ast_strdup(var->value);
03350 } else if (!strcasecmp(var->name, "permit") ) {
03351 if (user->permit)
03352 free(user->permit);
03353 user->permit = ast_strdup(var->value);
03354 } else if (!strcasecmp(var->name, "read") ) {
03355 if (user->read)
03356 free(user->read);
03357 user->read = ast_strdup(var->value);
03358 } else if (!strcasecmp(var->name, "write") ) {
03359 if (user->write)
03360 free(user->write);
03361 user->write = ast_strdup(var->value);
03362 } else if (!strcasecmp(var->name, "displayconnects") )
03363 user->displayconnects = ast_true(var->value);
03364 else
03365 ast_log(LOG_DEBUG, "%s is an unknown option.\n", var->name);
03366 var = var->next;
03367 }
03368 }
03369
03370
03371 AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
03372 if (user->keep) {
03373 user->keep = 0;
03374 continue;
03375 }
03376
03377 AST_LIST_REMOVE_CURRENT(&users, list);
03378
03379 if (user->secret)
03380 free(user->secret);
03381 if (user->deny)
03382 free(user->deny);
03383 if (user->permit)
03384 free(user->permit);
03385 if (user->read)
03386 free(user->read);
03387 if (user->write)
03388 free(user->write);
03389 free(user);
03390 }
03391 AST_LIST_TRAVERSE_SAFE_END
03392
03393 AST_LIST_UNLOCK(&users);
03394
03395 ast_config_destroy(cfg);
03396
03397 if (webmanager_enabled && manager_enabled) {
03398 if (!webregged) {
03399 ast_http_uri_link(&rawmanuri);
03400 ast_http_uri_link(&manageruri);
03401 ast_http_uri_link(&managerxmluri);
03402 webregged = 1;
03403 }
03404 } else {
03405 if (webregged) {
03406 ast_http_uri_unlink(&rawmanuri);
03407 ast_http_uri_unlink(&manageruri);
03408 ast_http_uri_unlink(&managerxmluri);
03409 webregged = 0;
03410 }
03411 }
03412
03413 if (newhttptimeout > 0)
03414 httptimeout = newhttptimeout;
03415
03416
03417 if (!manager_enabled)
03418 return 0;
03419
03420 if (asock < 0) {
03421 asock = socket(AF_INET, SOCK_STREAM, 0);
03422 if (asock < 0) {
03423 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
03424 return -1;
03425 }
03426 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
03427 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
03428 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
03429 close(asock);
03430 asock = -1;
03431 return -1;
03432 }
03433 if (listen(asock, 2)) {
03434 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
03435 close(asock);
03436 asock = -1;
03437 return -1;
03438 }
03439 flags = fcntl(asock, F_GETFL);
03440 fcntl(asock, F_SETFL, flags | O_NONBLOCK);
03441 if (option_verbose)
03442 ast_verbose("Asterisk Management interface listening on port %d\n", portno);
03443 ast_pthread_create_background(&t, NULL, accept_thread, NULL);
03444 }
03445 return 0;
03446 }
03447
03448 int reload_manager(void)
03449 {
03450 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
03451 return init_manager();
03452 }