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: 211596 $")
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 = mkstemp(template);
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 astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
01875 if (!ast_strlen_zero(id))
01876 astman_append(s, "ActionID: %s\r\n", id);
01877
01878 ast_cli_command(fd, cmd);
01879 l = lseek(fd, 0, SEEK_END);
01880
01881
01882 buf = ast_calloc(1, l + 1);
01883 final_buf = ast_calloc(1, l + 1);
01884 if (buf) {
01885 lseek(fd, 0, SEEK_SET);
01886 if (read(fd, buf, l) < 0) {
01887 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01888 }
01889 buf[l] = '\0';
01890 if (final_buf) {
01891 term_strip(final_buf, buf, l);
01892 final_buf[l] = '\0';
01893 }
01894 astman_append(s, "%s", S_OR(final_buf, buf));
01895 ast_free(buf);
01896 }
01897 close(fd);
01898 unlink(template);
01899 astman_append(s, "--END COMMAND--\r\n\r\n");
01900 if (final_buf)
01901 ast_free(final_buf);
01902 return 0;
01903 }
01904
01905 static void *fast_originate(void *data)
01906 {
01907 struct fast_originate_helper *in = data;
01908 int res;
01909 int reason = 0;
01910 struct ast_channel *chan = NULL;
01911 char requested_channel[AST_CHANNEL_NAME];
01912
01913 if (!ast_strlen_zero(in->app)) {
01914 res = ast_pbx_outgoing_app(in->tech, in->format, in->data, in->timeout, in->app, in->appdata, &reason, 1,
01915 S_OR(in->cid_num, NULL),
01916 S_OR(in->cid_name, NULL),
01917 in->vars, in->account, &chan);
01918 } else {
01919 res = ast_pbx_outgoing_exten(in->tech, in->format, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
01920 S_OR(in->cid_num, NULL),
01921 S_OR(in->cid_name, NULL),
01922 in->vars, in->account, &chan);
01923 }
01924
01925 if (!chan)
01926 snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
01927
01928 manager_event(EVENT_FLAG_CALL, "OriginateResponse",
01929 "%s%s"
01930 "Response: %s\r\n"
01931 "Channel: %s\r\n"
01932 "Context: %s\r\n"
01933 "Exten: %s\r\n"
01934 "Reason: %d\r\n"
01935 "Uniqueid: %s\r\n"
01936 "CallerID: %s\r\n"
01937 "CallerIDNum: %s\r\n"
01938 "CallerIDName: %s\r\n",
01939 in->idtext, ast_strlen_zero(in->idtext) ? "" : "\r\n", res ? "Failure" : "Success",
01940 chan ? chan->name : requested_channel, in->context, in->exten, reason,
01941 chan ? chan->uniqueid : "<null>",
01942 S_OR(in->cid_num, "<unknown>"),
01943 S_OR(in->cid_num, "<unknown>"),
01944 S_OR(in->cid_name, "<unknown>")
01945 );
01946
01947
01948 if (chan)
01949 ast_channel_unlock(chan);
01950 free(in);
01951 return NULL;
01952 }
01953
01954 static char mandescr_originate[] =
01955 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
01956 " Application/Data\n"
01957 "Variables: (Names marked with * are required)\n"
01958 " *Channel: Channel name to call\n"
01959 " Exten: Extension to use (requires 'Context' and 'Priority')\n"
01960 " Context: Context to use (requires 'Exten' and 'Priority')\n"
01961 " Priority: Priority to use (requires 'Exten' and 'Context')\n"
01962 " Application: Application to use\n"
01963 " Data: Data to use (requires 'Application')\n"
01964 " Timeout: How long to wait for call to be answered (in ms)\n"
01965 " CallerID: Caller ID to be set on the outgoing channel\n"
01966 " Variable: Channel variable to set, multiple Variable: headers are allowed\n"
01967 " Account: Account code\n"
01968 " Async: Set to 'true' for fast origination\n";
01969
01970 static int action_originate(struct mansession *s, const struct message *m)
01971 {
01972 const char *name = astman_get_header(m, "Channel");
01973 const char *exten = astman_get_header(m, "Exten");
01974 const char *context = astman_get_header(m, "Context");
01975 const char *priority = astman_get_header(m, "Priority");
01976 const char *timeout = astman_get_header(m, "Timeout");
01977 const char *callerid = astman_get_header(m, "CallerID");
01978 const char *account = astman_get_header(m, "Account");
01979 const char *app = astman_get_header(m, "Application");
01980 const char *appdata = astman_get_header(m, "Data");
01981 const char *async = astman_get_header(m, "Async");
01982 const char *id = astman_get_header(m, "ActionID");
01983 const char *codecs = astman_get_header(m, "Codecs");
01984 struct ast_variable *vars = astman_get_variables(m);
01985 char *tech, *data;
01986 char *l = NULL, *n = NULL;
01987 int pi = 0;
01988 int res;
01989 int to = 30000;
01990 int reason = 0;
01991 char tmp[256];
01992 char tmp2[256];
01993 int format = AST_FORMAT_SLINEAR;
01994
01995 pthread_t th;
01996 pthread_attr_t attr;
01997 if (ast_strlen_zero(name)) {
01998 astman_send_error(s, m, "Channel not specified");
01999 return 0;
02000 }
02001 if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
02002 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
02003 astman_send_error(s, m, "Invalid priority");
02004 return 0;
02005 }
02006 }
02007 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%30d", &to) != 1)) {
02008 astman_send_error(s, m, "Invalid timeout");
02009 return 0;
02010 }
02011 ast_copy_string(tmp, name, sizeof(tmp));
02012 tech = tmp;
02013 data = strchr(tmp, '/');
02014 if (!data) {
02015 astman_send_error(s, m, "Invalid channel");
02016 return 0;
02017 }
02018 *data++ = '\0';
02019 ast_copy_string(tmp2, callerid, sizeof(tmp2));
02020 ast_callerid_parse(tmp2, &n, &l);
02021 if (n) {
02022 if (ast_strlen_zero(n))
02023 n = NULL;
02024 }
02025 if (l) {
02026 ast_shrink_phone_number(l);
02027 if (ast_strlen_zero(l))
02028 l = NULL;
02029 }
02030 if (!ast_strlen_zero(codecs)) {
02031 format = 0;
02032 ast_parse_allow_disallow(NULL, &format, codecs, 1);
02033 }
02034 if (ast_true(async)) {
02035 struct fast_originate_helper *fast = ast_calloc(1, sizeof(*fast));
02036 if (!fast) {
02037 res = -1;
02038 } else {
02039 if (!ast_strlen_zero(id))
02040 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s", id);
02041 ast_copy_string(fast->tech, tech, sizeof(fast->tech));
02042 ast_copy_string(fast->data, data, sizeof(fast->data));
02043 ast_copy_string(fast->app, app, sizeof(fast->app));
02044 ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
02045 if (l)
02046 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
02047 if (n)
02048 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
02049 fast->vars = vars;
02050 ast_copy_string(fast->context, context, sizeof(fast->context));
02051 ast_copy_string(fast->exten, exten, sizeof(fast->exten));
02052 ast_copy_string(fast->account, account, sizeof(fast->account));
02053 fast->format = format;
02054 fast->timeout = to;
02055 fast->priority = pi;
02056 pthread_attr_init(&attr);
02057 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02058 if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
02059 ast_free(fast);
02060 res = -1;
02061 } else {
02062 res = 0;
02063 }
02064 pthread_attr_destroy(&attr);
02065 }
02066 } else if (!ast_strlen_zero(app)) {
02067 res = ast_pbx_outgoing_app(tech, format, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
02068 } else {
02069 if (exten && context && pi)
02070 res = ast_pbx_outgoing_exten(tech, format, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
02071 else {
02072 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
02073 return 0;
02074 }
02075 }
02076 if (!res)
02077 astman_send_ack(s, m, "Originate successfully queued");
02078 else
02079 astman_send_error(s, m, "Originate failed");
02080 return 0;
02081 }
02082
02083
02084
02085 static char mandescr_mailboxstatus[] =
02086 "Description: Checks a voicemail account for status.\n"
02087 "Variables: (Names marked with * are required)\n"
02088 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
02089 " ActionID: Optional ActionID for message matching.\n"
02090 "Returns number of messages.\n"
02091 " Message: Mailbox Status\n"
02092 " Mailbox: <mailboxid>\n"
02093 " Waiting: <count>\n"
02094 "\n";
02095
02096 static int action_mailboxstatus(struct mansession *s, const struct message *m)
02097 {
02098 const char *mailbox = astman_get_header(m, "Mailbox");
02099 const char *id = astman_get_header(m,"ActionID");
02100 char idText[256] = "";
02101 int ret;
02102 if (ast_strlen_zero(mailbox)) {
02103 astman_send_error(s, m, "Mailbox not specified");
02104 return 0;
02105 }
02106 if (!ast_strlen_zero(id))
02107 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02108 ret = ast_app_has_voicemail(mailbox, NULL);
02109 astman_append(s, "Response: Success\r\n"
02110 "%s"
02111 "Message: Mailbox Status\r\n"
02112 "Mailbox: %s\r\n"
02113 "Waiting: %d\r\n\r\n", idText, mailbox, ret);
02114 return 0;
02115 }
02116
02117 static char mandescr_mailboxcount[] =
02118 "Description: Checks a voicemail account for new messages.\n"
02119 "Variables: (Names marked with * are required)\n"
02120 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
02121 " ActionID: Optional ActionID for message matching.\n"
02122 "Returns number of new and old messages.\n"
02123 " Message: Mailbox Message Count\n"
02124 " Mailbox: <mailboxid>\n"
02125 " NewMessages: <count>\n"
02126 " OldMessages: <count>\n"
02127 "\n";
02128 static int action_mailboxcount(struct mansession *s, const struct message *m)
02129 {
02130 const char *mailbox = astman_get_header(m, "Mailbox");
02131 const char *id = astman_get_header(m,"ActionID");
02132 char idText[256] = "";
02133 int newmsgs = 0, oldmsgs = 0;
02134 if (ast_strlen_zero(mailbox)) {
02135 astman_send_error(s, m, "Mailbox not specified");
02136 return 0;
02137 }
02138 ast_app_inboxcount(mailbox, &newmsgs, &oldmsgs);
02139 if (!ast_strlen_zero(id)) {
02140 snprintf(idText, sizeof(idText), "ActionID: %s\r\n",id);
02141 }
02142 astman_append(s, "Response: Success\r\n"
02143 "%s"
02144 "Message: Mailbox Message Count\r\n"
02145 "Mailbox: %s\r\n"
02146 "NewMessages: %d\r\n"
02147 "OldMessages: %d\r\n"
02148 "\r\n",
02149 idText,mailbox, newmsgs, oldmsgs);
02150 return 0;
02151 }
02152
02153 static char mandescr_extensionstate[] =
02154 "Description: Report the extension state for given extension.\n"
02155 " If the extension has a hint, will use devicestate to check\n"
02156 " the status of the device connected to the extension.\n"
02157 "Variables: (Names marked with * are required)\n"
02158 " *Exten: Extension to check state on\n"
02159 " *Context: Context for extension\n"
02160 " ActionId: Optional ID for this transaction\n"
02161 "Will return an \"Extension Status\" message.\n"
02162 "The response will include the hint for the extension and the status.\n";
02163
02164 static int action_extensionstate(struct mansession *s, const struct message *m)
02165 {
02166 const char *exten = astman_get_header(m, "Exten");
02167 const char *context = astman_get_header(m, "Context");
02168 const char *id = astman_get_header(m,"ActionID");
02169 char idText[256] = "";
02170 char hint[256] = "";
02171 int status;
02172 if (ast_strlen_zero(exten)) {
02173 astman_send_error(s, m, "Extension not specified");
02174 return 0;
02175 }
02176 if (ast_strlen_zero(context))
02177 context = "default";
02178 status = ast_extension_state(NULL, context, exten);
02179 ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
02180 if (!ast_strlen_zero(id)) {
02181 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02182 }
02183 astman_append(s, "Response: Success\r\n"
02184 "%s"
02185 "Message: Extension Status\r\n"
02186 "Exten: %s\r\n"
02187 "Context: %s\r\n"
02188 "Hint: %s\r\n"
02189 "Status: %d\r\n\r\n",
02190 idText,exten, context, hint, status);
02191 return 0;
02192 }
02193
02194 static char mandescr_timeout[] =
02195 "Description: Hangup a channel after a certain time.\n"
02196 "Variables: (Names marked with * are required)\n"
02197 " *Channel: Channel name to hangup\n"
02198 " *Timeout: Maximum duration of the call (sec)\n"
02199 "Acknowledges set time with 'Timeout Set' message\n";
02200
02201 static int action_timeout(struct mansession *s, const struct message *m)
02202 {
02203 struct ast_channel *c = NULL;
02204 const char *name = astman_get_header(m, "Channel");
02205 int timeout = atoi(astman_get_header(m, "Timeout"));
02206 if (ast_strlen_zero(name)) {
02207 astman_send_error(s, m, "No channel specified");
02208 return 0;
02209 }
02210 if (!timeout) {
02211 astman_send_error(s, m, "No timeout specified");
02212 return 0;
02213 }
02214 c = ast_get_channel_by_name_locked(name);
02215 if (!c) {
02216 astman_send_error(s, m, "No such channel");
02217 return 0;
02218 }
02219 ast_channel_setwhentohangup(c, timeout);
02220 ast_channel_unlock(c);
02221 astman_send_ack(s, m, "Timeout Set");
02222 return 0;
02223 }
02224
02225 static int process_events(struct mansession *s)
02226 {
02227 struct eventqent *eqe;
02228 int ret = 0;
02229 ast_mutex_lock(&s->session->__lock);
02230 if (!s->session->eventq)
02231 s->session->eventq = master_eventq;
02232 while(s->session->eventq->next) {
02233 eqe = s->session->eventq->next;
02234 if ((s->session->authenticated && (s->session->readperm & eqe->category) == eqe->category) &&
02235 ((s->session->send_events & eqe->category) == eqe->category)) {
02236 if (s->fd > -1) {
02237 if (!ret && ast_carefulwrite(s->fd, eqe->eventdata, strlen(eqe->eventdata), s->session->writetimeout) < 0)
02238 ret = -1;
02239 } else if (!s->session->outputstr && !(s->session->outputstr = ast_calloc(1, sizeof(*s->session->outputstr))))
02240 ret = -1;
02241 else
02242 ast_dynamic_str_append(&s->session->outputstr, 0, "%s", eqe->eventdata);
02243 }
02244 unuse_eventqent(s->session->eventq);
02245 s->session->eventq = eqe;
02246 }
02247 ast_mutex_unlock(&s->session->__lock);
02248 return ret;
02249 }
02250
02251 static char mandescr_userevent[] =
02252 "Description: Send an event to manager sessions.\n"
02253 "Variables: (Names marked with * are required)\n"
02254 " *UserEvent: EventStringToSend\n"
02255 " Header1: Content1\n"
02256 " HeaderN: ContentN\n";
02257
02258 static int action_userevent(struct mansession *s, const struct message *m)
02259 {
02260 const char *event = astman_get_header(m, "UserEvent");
02261 char body[2048] = "";
02262 int x, bodylen = 0, xlen;
02263 for (x = 0; x < m->hdrcount; x++) {
02264 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
02265 if (sizeof(body) < bodylen + (xlen = strlen(m->headers[x])) + 3) {
02266 ast_log(LOG_WARNING, "UserEvent exceeds our buffer length. Truncating.\n");
02267 break;
02268 }
02269 ast_copy_string(body + bodylen, m->headers[x], sizeof(body) - bodylen - 3);
02270 bodylen += xlen;
02271 ast_copy_string(body + bodylen, "\r\n", 3);
02272 bodylen += 2;
02273 }
02274 }
02275
02276 manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, body);
02277 return 0;
02278 }
02279
02280 static char mandescr_coresettings[] =
02281 "Description: Query for Core PBX settings.\n"
02282 "Variables: (Names marked with * are optional)\n"
02283 " *ActionID: ActionID of this transaction\n";
02284
02285
02286 static int action_coresettings(struct mansession *s, const struct message *m)
02287 {
02288 const char *actionid = astman_get_header(m, "ActionID");
02289 char idText[150] = "";
02290
02291 if (!ast_strlen_zero(actionid))
02292 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
02293
02294 astman_append(s, "Response: Success\r\n"
02295 "%s"
02296 "AMIversion: %s\r\n"
02297 "AsteriskVersion: %s\r\n"
02298 "SystemName: %s\r\n"
02299 "CoreMaxCalls: %d\r\n"
02300 "CoreMaxLoadAvg: %f\r\n"
02301 "CoreRunUser: %s\r\n"
02302 "CoreRunGroup: %s\r\n"
02303 "CoreMaxFilehandles: %d\r\n"
02304 "CoreRealTimeEnabled: %s\r\n"
02305 "CoreCDRenabled: %s\r\n"
02306 "CoreHTTPenabled: %s\r\n"
02307 "\r\n",
02308 idText,
02309 AMI_VERSION,
02310 ASTERISK_VERSION,
02311 ast_config_AST_SYSTEM_NAME,
02312 option_maxcalls,
02313 option_maxload,
02314 ast_config_AST_RUN_USER,
02315 ast_config_AST_RUN_GROUP,
02316 option_maxfiles,
02317 ast_realtime_enabled() ? "Yes" : "No",
02318 check_cdr_enabled() ? "Yes" : "No",
02319 check_webmanager_enabled() ? "Yes" : "No"
02320 );
02321 return 0;
02322 }
02323
02324 static char mandescr_corestatus[] =
02325 "Description: Query for Core PBX status.\n"
02326 "Variables: (Names marked with * are optional)\n"
02327 " *ActionID: ActionID of this transaction\n";
02328
02329
02330 static int action_corestatus(struct mansession *s, const struct message *m)
02331 {
02332 const char *actionid = astman_get_header(m, "ActionID");
02333 char idText[150];
02334 char startuptime[150];
02335 char reloadtime[150];
02336 struct tm tm;
02337
02338 if (!ast_strlen_zero(actionid))
02339 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
02340
02341 ast_localtime(&ast_startuptime, &tm, NULL);
02342 strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
02343 ast_localtime(&ast_lastreloadtime, &tm, NULL);
02344 strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
02345
02346 astman_append(s, "Response: Success\r\n"
02347 "%s"
02348 "CoreStartupTime: %s\r\n"
02349 "CoreReloadTime: %s\r\n"
02350 "CoreCurrentCalls: %d\r\n"
02351 "\r\n",
02352 idText,
02353 startuptime,
02354 reloadtime,
02355 ast_active_channels()
02356 );
02357 return 0;
02358 }
02359
02360 static int process_message(struct mansession *s, const struct message *m)
02361 {
02362 char action[80] = "";
02363 struct manager_action *tmp;
02364 const char *id = astman_get_header(m,"ActionID");
02365 char idText[256] = "";
02366 int ret = 0;
02367
02368 ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
02369 if (option_debug)
02370 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
02371
02372 if (ast_strlen_zero(action)) {
02373 astman_send_error(s, m, "Missing action in request");
02374 return 0;
02375 }
02376 if (!ast_strlen_zero(id)) {
02377 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02378 }
02379 if (!s->session->authenticated) {
02380 if (!strcasecmp(action, "Challenge")) {
02381 const char *authtype = astman_get_header(m, "AuthType");
02382
02383 if (!strcasecmp(authtype, "MD5")) {
02384 if (ast_strlen_zero(s->session->challenge))
02385 snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
02386 astman_append(s, "Response: Success\r\n"
02387 "%s"
02388 "Challenge: %s\r\n\r\n",
02389 idText, s->session->challenge);
02390 return 0;
02391 } else {
02392 astman_send_error(s, m, "Must specify AuthType");
02393 return 0;
02394 }
02395 } else if (!strcasecmp(action, "Login")) {
02396 if (authenticate(s, m)) {
02397 sleep(1);
02398 astman_send_error(s, m, "Authentication failed");
02399 return -1;
02400 } else {
02401 s->session->authenticated = 1;
02402 if (option_verbose > 1) {
02403 if (displayconnects) {
02404 ast_verbose(VERBOSE_PREFIX_2 "%sManager '%s' logged on from %s\n",
02405 (s->session->sessiontimeout ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
02406 }
02407 }
02408 ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n",
02409 (s->session->sessiontimeout ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
02410 astman_send_ack(s, m, "Authentication accepted");
02411 }
02412 } else if (!strcasecmp(action, "Logoff")) {
02413 astman_send_ack(s, m, "See ya");
02414 return -1;
02415 } else
02416 astman_send_error(s, m, "Authentication Required");
02417 } else {
02418 if (!strcasecmp(action, "Login"))
02419 astman_send_ack(s, m, "Already logged in");
02420 else {
02421 ast_rwlock_rdlock(&actionlock);
02422 for (tmp = first_action; tmp; tmp = tmp->next) {
02423 if (strcasecmp(action, tmp->action))
02424 continue;
02425 if ((s->session->writeperm & tmp->authority) == tmp->authority) {
02426 if (tmp->func(s, m))
02427 ret = -1;
02428 } else
02429 astman_send_error(s, m, "Permission denied");
02430 break;
02431 }
02432 ast_rwlock_unlock(&actionlock);
02433 if (!tmp)
02434 astman_send_error(s, m, "Invalid/unknown command");
02435 }
02436 }
02437 if (ret)
02438 return ret;
02439 return process_events(s);
02440 }
02441
02442 static int get_input(struct mansession_session *s, char *output)
02443 {
02444
02445 int res;
02446 int x;
02447 struct pollfd fds[1];
02448 for (x = 1; x < s->inlen; x++) {
02449 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
02450
02451 memcpy(output, s->inbuf, x + 1);
02452
02453 output[x+1] = '\0';
02454
02455 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
02456 s->inlen -= (x + 1);
02457 return 1;
02458 }
02459 }
02460 if (s->inlen >= sizeof(s->inbuf) - 1) {
02461 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->sin.sin_addr), s->inbuf);
02462 s->inlen = 0;
02463 }
02464 fds[0].fd = s->fd;
02465 fds[0].events = POLLIN;
02466 do {
02467 ast_mutex_lock(&s->__lock);
02468 if (s->pending_event) {
02469 s->pending_event = 0;
02470 ast_mutex_unlock(&s->__lock);
02471 return 0;
02472 }
02473 s->waiting_thread = pthread_self();
02474 ast_mutex_unlock(&s->__lock);
02475
02476 res = ast_poll(fds, 1, -1);
02477
02478 ast_mutex_lock(&s->__lock);
02479 s->waiting_thread = AST_PTHREADT_NULL;
02480 ast_mutex_unlock(&s->__lock);
02481 if (res < 0) {
02482 if (errno == EINTR || errno == EAGAIN) {
02483 return 0;
02484 }
02485 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
02486 return -1;
02487 } else if (res > 0) {
02488 ast_mutex_lock(&s->__lock);
02489 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
02490 ast_mutex_unlock(&s->__lock);
02491 if (res < 1)
02492 return -1;
02493 break;
02494 }
02495 } while(1);
02496 s->inlen += res;
02497 s->inbuf[s->inlen] = '\0';
02498 return 0;
02499 }
02500
02501 static int do_message(struct mansession *s)
02502 {
02503 struct message m = { 0 };
02504 char header_buf[sizeof(s->session->inbuf)] = { '\0' };
02505 int res;
02506
02507 for (;;) {
02508
02509 if (s->session->eventq->next) {
02510 if (process_events(s))
02511 return -1;
02512 }
02513 res = get_input(s->session, header_buf);
02514 if (res == 0) {
02515 continue;
02516 } else if (res > 0) {
02517
02518 if (strlen(header_buf) < 2)
02519 continue;
02520 header_buf[strlen(header_buf) - 2] = '\0';
02521 if (ast_strlen_zero(header_buf))
02522 return process_message(s, &m) ? -1 : 0;
02523 else if (m.hdrcount < (AST_MAX_MANHEADERS - 1))
02524 m.headers[m.hdrcount++] = ast_strdupa(header_buf);
02525 } else {
02526 return res;
02527 }
02528 }
02529 }
02530
02531 static void *session_do(void *data)
02532 {
02533 struct mansession_session *session = data;
02534 int res;
02535 struct mansession s = { .session = session, .fd = session->fd };
02536
02537 astman_append(&s, "Asterisk Call Manager/1.0\r\n");
02538 for (;;) {
02539 if ((res = do_message(&s)) < 0)
02540 break;
02541 }
02542 if (session->authenticated) {
02543 if (option_verbose > 1) {
02544 if (displayconnects)
02545 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
02546 }
02547 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
02548 } else {
02549 if (option_verbose > 1) {
02550 if (displayconnects)
02551 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
02552 }
02553 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(session->sin.sin_addr));
02554 }
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567 usleep(1);
02568
02569 destroy_session(session);
02570 return NULL;
02571 }
02572
02573 static void *accept_thread(void *ignore)
02574 {
02575 int as;
02576 struct sockaddr_in sin;
02577 socklen_t sinlen;
02578 struct eventqent *eqe;
02579 struct mansession_session *s;
02580 struct protoent *p;
02581 int arg = 1;
02582 int flags;
02583 pthread_attr_t attr;
02584 time_t now;
02585 struct pollfd pfds[1];
02586
02587 pthread_attr_init(&attr);
02588 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02589
02590 for (;;) {
02591 time(&now);
02592 AST_LIST_LOCK(&sessions);
02593 AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, s, list) {
02594 if (s->sessiontimeout && (now > s->sessiontimeout) && !s->inuse) {
02595 AST_LIST_REMOVE_CURRENT(&sessions, list);
02596 num_sessions--;
02597 if (s->authenticated && (option_verbose > 1) && displayconnects) {
02598 ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' timed out from %s\n",
02599 s->username, ast_inet_ntoa(s->sin.sin_addr));
02600 }
02601 free_session(s);
02602 break;
02603 }
02604 }
02605 AST_LIST_TRAVERSE_SAFE_END
02606
02607
02608 eqe = master_eventq;
02609 while (master_eventq->next && !master_eventq->usecount) {
02610 eqe = master_eventq;
02611 master_eventq = master_eventq->next;
02612 free(eqe);
02613 }
02614 AST_LIST_UNLOCK(&sessions);
02615
02616 sinlen = sizeof(sin);
02617 pfds[0].fd = asock;
02618 pfds[0].events = POLLIN;
02619
02620
02621 if (ast_poll(pfds, 1, 5000) < 1)
02622 continue;
02623 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
02624 if (as < 0) {
02625 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
02626 continue;
02627 }
02628 p = getprotobyname("tcp");
02629 if (p) {
02630 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
02631 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
02632 }
02633 }
02634 if (!(s = ast_calloc(1, sizeof(*s))))
02635 continue;
02636
02637 memcpy(&s->sin, &sin, sizeof(sin));
02638 s->writetimeout = 100;
02639 s->waiting_thread = AST_PTHREADT_NULL;
02640
02641 if (!block_sockets) {
02642
02643 flags = fcntl(as, F_GETFL);
02644 fcntl(as, F_SETFL, flags | O_NONBLOCK);
02645 } else {
02646 flags = fcntl(as, F_GETFL);
02647 fcntl(as, F_SETFL, flags & ~O_NONBLOCK);
02648 }
02649 ast_mutex_init(&s->__lock);
02650 s->fd = as;
02651 s->send_events = -1;
02652 AST_LIST_LOCK(&sessions);
02653 AST_LIST_INSERT_HEAD(&sessions, s, list);
02654 num_sessions++;
02655
02656
02657 s->eventq = master_eventq;
02658 while(s->eventq->next)
02659 s->eventq = s->eventq->next;
02660 ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
02661 AST_LIST_UNLOCK(&sessions);
02662 if (ast_pthread_create_background(&s->t, &attr, session_do, s))
02663 destroy_session(s);
02664 }
02665 pthread_attr_destroy(&attr);
02666 return NULL;
02667 }
02668
02669 static int append_event(const char *str, int category)
02670 {
02671 struct eventqent *tmp, *prev = NULL;
02672 tmp = ast_malloc(sizeof(*tmp) + strlen(str));
02673
02674 if (!tmp)
02675 return -1;
02676
02677 tmp->next = NULL;
02678 tmp->category = category;
02679 strcpy(tmp->eventdata, str);
02680
02681 if (master_eventq) {
02682 prev = master_eventq;
02683 while (prev->next)
02684 prev = prev->next;
02685 prev->next = tmp;
02686 } else {
02687 master_eventq = tmp;
02688 }
02689
02690 tmp->usecount = num_sessions;
02691
02692 return 0;
02693 }
02694
02695
02696 int manager_event(int category, const char *event, const char *fmt, ...)
02697 {
02698 struct mansession_session *s;
02699 char auth[80];
02700 va_list ap;
02701 struct timeval now;
02702 struct ast_dynamic_str *buf;
02703
02704
02705 if (!num_sessions)
02706 return 0;
02707
02708 if (!(buf = ast_dynamic_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE)))
02709 return -1;
02710
02711 ast_dynamic_str_thread_set(&buf, 0, &manager_event_buf,
02712 "Event: %s\r\nPrivilege: %s\r\n",
02713 event, authority_to_str(category, auth, sizeof(auth)));
02714
02715 if (timestampevents) {
02716 now = ast_tvnow();
02717 ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf,
02718 "Timestamp: %ld.%06lu\r\n",
02719 now.tv_sec, (unsigned long) now.tv_usec);
02720 }
02721
02722 va_start(ap, fmt);
02723 ast_dynamic_str_thread_append_va(&buf, 0, &manager_event_buf, fmt, ap);
02724 va_end(ap);
02725
02726 ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf, "\r\n");
02727
02728
02729 AST_LIST_LOCK(&sessions);
02730 append_event(buf->str, category);
02731 AST_LIST_TRAVERSE(&sessions, s, list) {
02732 ast_mutex_lock(&s->__lock);
02733 if (s->waiting_thread != AST_PTHREADT_NULL)
02734 pthread_kill(s->waiting_thread, SIGURG);
02735 else
02736
02737
02738
02739
02740
02741 s->pending_event = 1;
02742 ast_mutex_unlock(&s->__lock);
02743 }
02744 AST_LIST_UNLOCK(&sessions);
02745
02746 return 0;
02747 }
02748
02749 int ast_manager_unregister(char *action)
02750 {
02751 struct manager_action *cur, *prev;
02752 struct timespec tv = { 5, };
02753
02754 if (ast_rwlock_timedwrlock(&actionlock, &tv)) {
02755 ast_log(LOG_ERROR, "Could not obtain lock on manager list\n");
02756 return -1;
02757 }
02758 cur = prev = first_action;
02759 while (cur) {
02760 if (!strcasecmp(action, cur->action)) {
02761 prev->next = cur->next;
02762 free(cur);
02763 if (option_verbose > 1)
02764 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
02765 ast_rwlock_unlock(&actionlock);
02766 return 0;
02767 }
02768 prev = cur;
02769 cur = cur->next;
02770 }
02771 ast_rwlock_unlock(&actionlock);
02772 return 0;
02773 }
02774
02775 static int manager_state_cb(char *context, char *exten, int state, void *data)
02776 {
02777
02778 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
02779 return 0;
02780 }
02781
02782 static int ast_manager_register_struct(struct manager_action *act)
02783 {
02784 struct manager_action *cur, *prev = NULL;
02785 int ret;
02786 struct timespec tv = { 5, };
02787
02788 if (ast_rwlock_timedwrlock(&actionlock, &tv)) {
02789 ast_log(LOG_ERROR, "Could not obtain lock on manager list\n");
02790 return -1;
02791 }
02792 cur = first_action;
02793 while (cur) {
02794 ret = strcasecmp(cur->action, act->action);
02795 if (ret == 0) {
02796 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
02797 ast_rwlock_unlock(&actionlock);
02798 return -1;
02799 } else if (ret > 0) {
02800
02801 if (prev) {
02802 act->next = prev->next;
02803 prev->next = act;
02804 } else {
02805 act->next = first_action;
02806 first_action = act;
02807 }
02808 break;
02809 }
02810 prev = cur;
02811 cur = cur->next;
02812 }
02813
02814 if (!cur) {
02815 if (prev)
02816 prev->next = act;
02817 else
02818 first_action = act;
02819 act->next = NULL;
02820 }
02821
02822 if (option_verbose > 1)
02823 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
02824 ast_rwlock_unlock(&actionlock);
02825 return 0;
02826 }
02827
02828
02829
02830 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
02831 {
02832 struct manager_action *cur;
02833
02834 cur = ast_malloc(sizeof(*cur));
02835 if (!cur)
02836 return -1;
02837
02838 cur->action = action;
02839 cur->authority = auth;
02840 cur->func = func;
02841 cur->synopsis = synopsis;
02842 cur->description = description;
02843 cur->next = NULL;
02844
02845 if (ast_manager_register_struct(cur)) {
02846 ast_free(cur);
02847 return -1;
02848 }
02849
02850 return 0;
02851 }
02852
02853
02854
02855 static struct mansession_session *find_session(uint32_t ident)
02856 {
02857 struct mansession_session *s;
02858
02859 AST_LIST_LOCK(&sessions);
02860 AST_LIST_TRAVERSE(&sessions, s, list) {
02861 ast_mutex_lock(&s->__lock);
02862 if (s->sessiontimeout && (s->managerid == ident) && !s->needdestroy) {
02863 s->inuse++;
02864 break;
02865 }
02866 ast_mutex_unlock(&s->__lock);
02867 }
02868 AST_LIST_UNLOCK(&sessions);
02869
02870 return s;
02871 }
02872
02873 int astman_verify_session_readpermissions(uint32_t ident, int perm)
02874 {
02875 int result = 0;
02876 struct mansession_session *s;
02877
02878 AST_LIST_LOCK(&sessions);
02879 AST_LIST_TRAVERSE(&sessions, s, list) {
02880 ast_mutex_lock(&s->__lock);
02881 if ((s->managerid == ident) && (s->readperm & perm)) {
02882 result = 1;
02883 ast_mutex_unlock(&s->__lock);
02884 break;
02885 }
02886 ast_mutex_unlock(&s->__lock);
02887 }
02888 AST_LIST_UNLOCK(&sessions);
02889 return result;
02890 }
02891
02892 int astman_verify_session_writepermissions(uint32_t ident, int perm)
02893 {
02894 int result = 0;
02895 struct mansession_session *s;
02896
02897 AST_LIST_LOCK(&sessions);
02898 AST_LIST_TRAVERSE(&sessions, s, list) {
02899 ast_mutex_lock(&s->__lock);
02900 if ((s->managerid == ident) && (s->writeperm & perm)) {
02901 result = 1;
02902 ast_mutex_unlock(&s->__lock);
02903 break;
02904 }
02905 ast_mutex_unlock(&s->__lock);
02906 }
02907 AST_LIST_UNLOCK(&sessions);
02908 return result;
02909 }
02910
02911 enum {
02912 FORMAT_RAW,
02913 FORMAT_HTML,
02914 FORMAT_XML,
02915 };
02916 static char *contenttype[] = { "plain", "html", "xml" };
02917
02918 static char *generic_http_callback(int format, struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
02919 {
02920 struct mansession_session *s = NULL;
02921 struct mansession ss = { .session = NULL, };
02922 uint32_t ident = 0;
02923 char workspace[512];
02924 char cookie[128];
02925 size_t len = sizeof(workspace);
02926 int blastaway = 0;
02927 char *c = workspace;
02928 char *retval = NULL;
02929 struct ast_variable *v;
02930
02931 for (v = params; v; v = v->next) {
02932 if (!strcasecmp(v->name, "mansession_id")) {
02933 sscanf(v->value, "%30x", &ident);
02934 break;
02935 }
02936 }
02937
02938 if (!(s = find_session(ident))) {
02939
02940 if (!(s = ast_calloc(1, sizeof(*s)))) {
02941 *status = 500;
02942 goto generic_callback_out;
02943 }
02944 memcpy(&s->sin, requestor, sizeof(s->sin));
02945 s->fd = -1;
02946 s->waiting_thread = AST_PTHREADT_NULL;
02947 s->send_events = 0;
02948 ast_mutex_init(&s->__lock);
02949 ast_mutex_lock(&s->__lock);
02950 s->inuse = 1;
02951
02952
02953
02954
02955
02956 while ((s->managerid = rand() ^ (unsigned long) s) == 0);
02957 AST_LIST_LOCK(&sessions);
02958 AST_LIST_INSERT_HEAD(&sessions, s, list);
02959
02960 s->eventq = master_eventq;
02961 while (s->eventq->next)
02962 s->eventq = s->eventq->next;
02963 ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
02964 ast_atomic_fetchadd_int(&num_sessions, 1);
02965 AST_LIST_UNLOCK(&sessions);
02966 }
02967
02968
02969 time(&s->sessiontimeout);
02970 if (!s->authenticated && (httptimeout > 5))
02971 s->sessiontimeout += 5;
02972 else
02973 s->sessiontimeout += httptimeout;
02974 ss.session = s;
02975 ast_mutex_unlock(&s->__lock);
02976
02977 ss.f = tmpfile();
02978 ss.fd = fileno(ss.f);
02979
02980 if (s) {
02981 struct message m = { 0 };
02982 char tmp[80];
02983 unsigned int x;
02984 size_t hdrlen;
02985
02986 for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
02987 hdrlen = strlen(v->name) + strlen(v->value) + 3;
02988 m.headers[m.hdrcount] = alloca(hdrlen);
02989 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
02990 m.hdrcount = x + 1;
02991 }
02992
02993 if (process_message(&ss, &m)) {
02994 if (s->authenticated) {
02995 if (option_verbose > 1) {
02996 if (displayconnects)
02997 ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
02998 }
02999 ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
03000 } else {
03001 if (option_verbose > 1) {
03002 if (displayconnects)
03003 ast_verbose(VERBOSE_PREFIX_2 "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
03004 }
03005 ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
03006 }
03007 s->needdestroy = 1;
03008 }
03009 ast_build_string(&c, &len, "Content-type: text/%s\r\n", contenttype[format]);
03010 sprintf(tmp, "%08x", s->managerid);
03011 ast_build_string(&c, &len, "%s\r\n", ast_http_setcookie("mansession_id", tmp, httptimeout, cookie, sizeof(cookie)));
03012 if (format == FORMAT_HTML)
03013 ast_build_string(&c, &len, "<title>Asterisk™ Manager Interface</title>");
03014 if (format == FORMAT_XML) {
03015 ast_build_string(&c, &len, "<ajax-response>\n");
03016 } else if (format == FORMAT_HTML) {
03017 ast_build_string(&c, &len, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
03018 ast_build_string(&c, &len, "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\"><h1> Manager Tester</h1></td></tr>\r\n");
03019 }
03020 ast_mutex_lock(&s->__lock);
03021 if (ss.fd > -1) {
03022 char *buf;
03023 size_t l = lseek(ss.fd, 0, SEEK_END);
03024 if (l) {
03025 if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, ss.fd, 0))) {
03026 ast_log(LOG_WARNING, "mmap failed. Manager request output was not processed\n");
03027 } else {
03028 char *tmpbuf;
03029 if (format == FORMAT_XML)
03030 tmpbuf = xml_translate(buf, params);
03031 else if (format == FORMAT_HTML)
03032 tmpbuf = html_translate(buf);
03033 else
03034 tmpbuf = buf;
03035 if (tmpbuf) {
03036 size_t wlen, tlen;
03037 if ((retval = malloc((wlen = strlen(workspace)) + (tlen = strlen(tmpbuf)) + 128))) {
03038 strcpy(retval, workspace);
03039 strcpy(retval + wlen, tmpbuf);
03040 c = retval + wlen + tlen;
03041
03042 len = 120;
03043 }
03044 }
03045 if (tmpbuf != buf)
03046 free(tmpbuf);
03047 free(s->outputstr);
03048 s->outputstr = NULL;
03049 munmap(buf, l);
03050 }
03051 }
03052 fclose(ss.f);
03053 ss.f = NULL;
03054 ss.fd = -1;
03055 } else if (s->outputstr) {
03056 char *tmp;
03057 if (format == FORMAT_XML)
03058 tmp = xml_translate(s->outputstr->str, params);
03059 else if (format == FORMAT_HTML)
03060 tmp = html_translate(s->outputstr->str);
03061 else
03062 tmp = s->outputstr->str;
03063 if (tmp) {
03064 retval = malloc(strlen(workspace) + strlen(tmp) + 128);
03065 if (retval) {
03066 strcpy(retval, workspace);
03067 strcpy(retval + strlen(retval), tmp);
03068 c = retval + strlen(retval);
03069 len = 120;
03070 }
03071 }
03072 if (tmp != s->outputstr->str)
03073 free(tmp);
03074 free(s->outputstr);
03075 s->outputstr = NULL;
03076 }
03077 ast_mutex_unlock(&s->__lock);
03078
03079
03080 if (format == FORMAT_XML) {
03081 ast_build_string(&c, &len, "</ajax-response>\n");
03082 } else if (format == FORMAT_HTML)
03083 ast_build_string(&c, &len, "</table></body>\r\n");
03084 } else {
03085 *status = 500;
03086 *title = strdup("Server Error");
03087 }
03088 ast_mutex_lock(&s->__lock);
03089 if (s->needdestroy) {
03090 if (s->inuse == 1) {
03091 ast_log(LOG_DEBUG, "Need destroy, doing it now!\n");
03092 blastaway = 1;
03093 } else {
03094 ast_log(LOG_DEBUG, "Need destroy, but can't do it yet!\n");
03095 if (s->waiting_thread != AST_PTHREADT_NULL)
03096 pthread_kill(s->waiting_thread, SIGURG);
03097 s->inuse--;
03098 }
03099 } else
03100 s->inuse--;
03101 ast_mutex_unlock(&s->__lock);
03102
03103 if (blastaway)
03104 destroy_session(s);
03105 generic_callback_out:
03106 if (*status != 200)
03107 return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n");
03108 return retval;
03109 }
03110
03111 static char *manager_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
03112 {
03113 return generic_http_callback(FORMAT_HTML, requestor, uri, params, status, title, contentlength);
03114 }
03115
03116 static char *mxml_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
03117 {
03118 return generic_http_callback(FORMAT_XML, requestor, uri, params, status, title, contentlength);
03119 }
03120
03121 static char *rawman_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
03122 {
03123 return generic_http_callback(FORMAT_RAW, requestor, uri, params, status, title, contentlength);
03124 }
03125
03126 struct ast_http_uri rawmanuri = {
03127 .description = "Raw HTTP Manager Event Interface",
03128 .uri = "rawman",
03129 .has_subtree = 0,
03130 .callback = rawman_http_callback,
03131 };
03132
03133 struct ast_http_uri manageruri = {
03134 .description = "HTML Manager Event Interface",
03135 .uri = "manager",
03136 .has_subtree = 0,
03137 .callback = manager_http_callback,
03138 };
03139
03140 struct ast_http_uri managerxmluri = {
03141 .description = "XML Manager Event Interface",
03142 .uri = "mxml",
03143 .has_subtree = 0,
03144 .callback = mxml_http_callback,
03145 };
03146
03147 static int registered = 0;
03148 static int webregged = 0;
03149
03150 int init_manager(void)
03151 {
03152 struct ast_config *cfg = NULL, *ucfg = NULL;
03153 const char *val;
03154 char *cat = NULL;
03155 int oldportno = portno;
03156 static struct sockaddr_in ba;
03157 int x = 1;
03158 int flags;
03159 int newhttptimeout = 60;
03160 struct ast_manager_user *user = NULL;
03161
03162 if (!registered) {
03163
03164 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
03165 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
03166 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
03167 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
03168 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
03169 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
03170 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
03171 ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
03172 ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
03173 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
03174 ast_manager_register2("Atxfer", EVENT_FLAG_CALL, action_atxfer, "Attended transfer", mandescr_atxfer );
03175 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
03176 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
03177 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
03178 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
03179 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
03180 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
03181 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
03182 ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent);
03183 ast_manager_register2("CoreSettings", EVENT_FLAG_SYSTEM, action_coresettings, "Show PBX core settings (version etc)", mandescr_coresettings);
03184 ast_manager_register2("CoreStatus", EVENT_FLAG_SYSTEM, action_corestatus, "Show PBX core status variables", mandescr_corestatus);
03185 ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent);
03186
03187 ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry));
03188 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
03189 registered = 1;
03190
03191 append_event("Event: Placeholder\r\n\r\n", 0);
03192 }
03193 portno = DEFAULT_MANAGER_PORT;
03194 displayconnects = 1;
03195 cfg = ast_config_load("manager.conf");
03196 if (!cfg) {
03197 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
03198 return 0;
03199 }
03200 if ((val = ast_variable_retrieve(cfg, "general", "enabled"))) {
03201 manager_enabled = ast_true(val);
03202 }
03203 if ((val = ast_variable_retrieve(cfg, "general", "block-sockets"))) {
03204 block_sockets = ast_true(val);
03205 }
03206 if((val = ast_variable_retrieve(cfg, "general", "webenabled"))) {
03207 webmanager_enabled = ast_true(val);
03208 }
03209 if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
03210 if (sscanf(val, "%5d", &portno) != 1) {
03211 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
03212 portno = DEFAULT_MANAGER_PORT;
03213 }
03214 }
03215
03216 if ((val = ast_variable_retrieve(cfg, "general", "displayconnects"))) {
03217 displayconnects = ast_true(val);
03218 }
03219 if ((val = ast_variable_retrieve(cfg, "general", "timestampevents"))) {
03220 timestampevents = ast_true(val);
03221 }
03222 if ((val = ast_variable_retrieve(cfg, "general", "httptimeout"))) {
03223 newhttptimeout = atoi(val);
03224 }
03225
03226 memset(&ba, 0, sizeof(ba));
03227 ba.sin_family = AF_INET;
03228 ba.sin_port = htons(portno);
03229
03230 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
03231 if (!inet_aton(val, &ba.sin_addr)) {
03232 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
03233 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
03234 }
03235 }
03236
03237
03238 if ((asock > -1) && ((portno != oldportno) || !manager_enabled)) {
03239 #if 0
03240
03241 close(asock);
03242 asock = -1;
03243 #else
03244 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
03245 #endif
03246 }
03247
03248 AST_LIST_LOCK(&users);
03249
03250 if ((ucfg = ast_config_load("users.conf"))) {
03251 while ((cat = ast_category_browse(ucfg, cat))) {
03252 int hasmanager = 0;
03253 struct ast_variable *var = NULL;
03254
03255 if (!strcasecmp(cat, "general")) {
03256 continue;
03257 }
03258
03259 if (!(hasmanager = ast_true(ast_variable_retrieve(ucfg, cat, "hasmanager")))) {
03260 continue;
03261 }
03262
03263
03264 if (!(user = ast_get_manager_by_name_locked(cat))) {
03265 if (!(user = ast_calloc(1, sizeof(*user)))) {
03266 break;
03267 }
03268
03269 ast_copy_string(user->username, cat, sizeof(user->username));
03270
03271 AST_LIST_INSERT_TAIL(&users, user, list);
03272 }
03273
03274
03275 user->keep = 1;
03276
03277 for (var = ast_variable_browse(ucfg, cat); var; var = var->next) {
03278 if (!strcasecmp(var->name, "secret")) {
03279 if (user->secret) {
03280 free(user->secret);
03281 }
03282 user->secret = ast_strdup(var->value);
03283 } else if (!strcasecmp(var->name, "deny") ) {
03284 if (user->deny) {
03285 free(user->deny);
03286 }
03287 user->deny = ast_strdup(var->value);
03288 } else if (!strcasecmp(var->name, "permit") ) {
03289 if (user->permit) {
03290 free(user->permit);
03291 }
03292 user->permit = ast_strdup(var->value);
03293 } else if (!strcasecmp(var->name, "read") ) {
03294 if (user->read) {
03295 free(user->read);
03296 }
03297 user->read = ast_strdup(var->value);
03298 } else if (!strcasecmp(var->name, "write") ) {
03299 if (user->write) {
03300 free(user->write);
03301 }
03302 user->write = ast_strdup(var->value);
03303 } else if (!strcasecmp(var->name, "displayconnects") ) {
03304 user->displayconnects = ast_true(var->value);
03305 } else if (!strcasecmp(var->name, "hasmanager")) {
03306
03307 } else {
03308 ast_log(LOG_DEBUG, "%s is an unknown option (to the manager module).\n", var->name);
03309 }
03310 }
03311 }
03312 ast_config_destroy(ucfg);
03313 }
03314
03315 while ((cat = ast_category_browse(cfg, cat))) {
03316 struct ast_variable *var = NULL;
03317
03318 if (!strcasecmp(cat, "general"))
03319 continue;
03320
03321
03322 if (!(user = ast_get_manager_by_name_locked(cat))) {
03323 if (!(user = ast_calloc(1, sizeof(*user))))
03324 break;
03325
03326 ast_copy_string(user->username, cat, sizeof(user->username));
03327
03328 AST_LIST_INSERT_TAIL(&users, user, list);
03329 }
03330
03331
03332 user->keep = 1;
03333
03334 var = ast_variable_browse(cfg, cat);
03335 while (var) {
03336 if (!strcasecmp(var->name, "secret")) {
03337 if (user->secret)
03338 free(user->secret);
03339 user->secret = ast_strdup(var->value);
03340 } else if (!strcasecmp(var->name, "deny") ) {
03341 if (user->deny)
03342 free(user->deny);
03343 user->deny = ast_strdup(var->value);
03344 } else if (!strcasecmp(var->name, "permit") ) {
03345 if (user->permit)
03346 free(user->permit);
03347 user->permit = ast_strdup(var->value);
03348 } else if (!strcasecmp(var->name, "read") ) {
03349 if (user->read)
03350 free(user->read);
03351 user->read = ast_strdup(var->value);
03352 } else if (!strcasecmp(var->name, "write") ) {
03353 if (user->write)
03354 free(user->write);
03355 user->write = ast_strdup(var->value);
03356 } else if (!strcasecmp(var->name, "displayconnects") )
03357 user->displayconnects = ast_true(var->value);
03358 else
03359 ast_log(LOG_DEBUG, "%s is an unknown option.\n", var->name);
03360 var = var->next;
03361 }
03362 }
03363
03364
03365 AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
03366 if (user->keep) {
03367 user->keep = 0;
03368 continue;
03369 }
03370
03371 AST_LIST_REMOVE_CURRENT(&users, list);
03372
03373 if (user->secret)
03374 free(user->secret);
03375 if (user->deny)
03376 free(user->deny);
03377 if (user->permit)
03378 free(user->permit);
03379 if (user->read)
03380 free(user->read);
03381 if (user->write)
03382 free(user->write);
03383 free(user);
03384 }
03385 AST_LIST_TRAVERSE_SAFE_END
03386
03387 AST_LIST_UNLOCK(&users);
03388
03389 ast_config_destroy(cfg);
03390
03391 if (webmanager_enabled && manager_enabled) {
03392 if (!webregged) {
03393 ast_http_uri_link(&rawmanuri);
03394 ast_http_uri_link(&manageruri);
03395 ast_http_uri_link(&managerxmluri);
03396 webregged = 1;
03397 }
03398 } else {
03399 if (webregged) {
03400 ast_http_uri_unlink(&rawmanuri);
03401 ast_http_uri_unlink(&manageruri);
03402 ast_http_uri_unlink(&managerxmluri);
03403 webregged = 0;
03404 }
03405 }
03406
03407 if (newhttptimeout > 0)
03408 httptimeout = newhttptimeout;
03409
03410
03411 if (!manager_enabled)
03412 return 0;
03413
03414 if (asock < 0) {
03415 asock = socket(AF_INET, SOCK_STREAM, 0);
03416 if (asock < 0) {
03417 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
03418 return -1;
03419 }
03420 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
03421 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
03422 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
03423 close(asock);
03424 asock = -1;
03425 return -1;
03426 }
03427 if (listen(asock, 2)) {
03428 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
03429 close(asock);
03430 asock = -1;
03431 return -1;
03432 }
03433 flags = fcntl(asock, F_GETFL);
03434 fcntl(asock, F_SETFL, flags | O_NONBLOCK);
03435 if (option_verbose)
03436 ast_verbose("Asterisk Management interface listening on port %d\n", portno);
03437 ast_pthread_create_background(&t, NULL, accept_thread, NULL);
03438 }
03439 return 0;
03440 }
03441
03442 int reload_manager(void)
03443 {
03444 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
03445 return init_manager();
03446 }