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