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