Let's repair the SIP attack shield :-)
[asterisk/asterisk.git] / main / manager.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief The Asterisk Management Interface - AMI
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * At the moment this file contains a number of functions, namely:
26  *
27  * - data structures storing AMI state
28  * - AMI-related API functions, used by internal asterisk components
29  * - handlers for AMI-related CLI functions
30  * - handlers for AMI functions (available through the AMI socket)
31  * - the code for the main AMI listener thread and individual session threads
32  * - the http handlers invoked for AMI-over-HTTP by the threads in main/http.c
33  *
34  * \ref amiconf
35  */
36
37 /*! \addtogroup Group_AMI AMI functions
38 */
39 /*! @{
40  Doxygen group */
41
42 #include "asterisk.h"
43
44 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <ctype.h>
50 #include <sys/time.h>
51 #include <sys/types.h>
52 #include <netdb.h>
53 #include <sys/socket.h>
54 #include <netinet/in.h>
55 #include <netinet/tcp.h>
56 #include <arpa/inet.h>
57 #include <signal.h>
58 #include <errno.h>
59 #include <unistd.h>
60
61 #include "asterisk/channel.h"
62 #include "asterisk/file.h"
63 #include "asterisk/manager.h"
64 #include "asterisk/config.h"
65 #include "asterisk/callerid.h"
66 #include "asterisk/lock.h"
67 #include "asterisk/logger.h"
68 #include "asterisk/options.h"
69 #include "asterisk/cli.h"
70 #include "asterisk/app.h"
71 #include "asterisk/pbx.h"
72 #include "asterisk/md5.h"
73 #include "asterisk/acl.h"
74 #include "asterisk/utils.h"
75 #include "asterisk/http.h"
76 #include "asterisk/threadstorage.h"
77 #include "asterisk/linkedlists.h"
78
79 struct eventqent {
80         int usecount;           /*!< # of clients who still need the event */
81         int category;
82         struct eventqent *next;
83         char eventdata[1];      /*!< really variable size, allocated by append_event() */
84 };
85 struct eventqent *master_eventq = NULL; /*!< Protected by the sessions list lock */
86
87 static int enabled = 0;
88 static int portno = DEFAULT_MANAGER_PORT;
89 static int asock = -1;  /* the accept socket */
90 static int displayconnects = 1;
91 static int timestampevents = 0;
92 static int httptimeout = 60;
93
94 static pthread_t accept_thread_ptr;     /*!< the accept thread */
95 static int block_sockets = 0;
96 static int num_sessions = 0;
97
98 AST_THREADSTORAGE(manager_event_buf);
99 #define MANAGER_EVENT_BUF_INITSIZE   256
100
101 AST_THREADSTORAGE(astman_append_buf);
102 #define ASTMAN_APPEND_BUF_INITSIZE   256
103
104 /*! \brief Descriptor for an AMI session, either a regular one
105  * or one over http.
106  * For AMI sessions, the entry is created upon a connect, and destroyed
107  * with the socket.
108  */
109 struct mansession {
110         pthread_t ms_t;         /*!< Execution thread, basically useless */
111         ast_mutex_t __lock;     /*!< Thread lock -- don't use in action callbacks, it's already taken care of  */
112                                 /* XXX need to document which fields it is protecting */
113         struct sockaddr_in sin; /*!< address we are connecting from */
114         int fd;                 /*!< descriptor used for output. Either the socket (AMI) or a temporary file (HTTP) */
115         int inuse;              /*!< number of HTTP sessions using this entry */
116         int needdestroy;        /*!< Whether an HTTP session should be destroyed */
117         pthread_t waiting_thread;       /*!< Whether an HTTP session has someone waiting on events */
118         unsigned long managerid;        /*!< Unique manager identifer, 0 for AMI sessions */
119         time_t sessiontimeout;  /*!< Session timeout if HTTP */
120         struct ast_dynamic_str *outputstr;      /*!< Output from manager interface */
121         char username[80];      /*!< Logged in username */
122         char challenge[10];     /*!< Authentication challenge */
123         int authenticated;      /*!< Authentication status */
124         int readperm;           /*!< Authorization for reading */
125         int writeperm;          /*!< Authorization for writing */
126         char inbuf[AST_MAX_MANHEADER_LEN];      /*!< Buffer */
127         int inlen;              /*!< number of buffered bytes */
128         int send_events;        /*!<  XXX what ? */
129         struct eventqent *eventq;       /*!< last event processed. */
130         int writetimeout;       /*!< Timeout for ast_carefulwrite() */
131         AST_LIST_ENTRY(mansession) list;
132 };
133
134 static AST_LIST_HEAD_STATIC(sessions, mansession);
135
136 /*! \brief user descriptor, as read from the config file.
137  * \note It is still missing some fields -- e.g. we can have multiple permit and deny
138  * lines which are not supported here, and readperm/writeperm/writetimeout
139  * are not stored.
140  */
141 struct ast_manager_user {
142         char username[80];
143         char *secret;
144         char *deny;
145         char *permit;
146         char *read;
147         char *write;
148         int displayconnects;    /*!< XXX unused */
149         int keep;       /*!< mark entries created on a reload */
150         AST_LIST_ENTRY(ast_manager_user) list;
151 };
152
153 /*! \brief list of users found in the config file */
154 static AST_LIST_HEAD_STATIC(users, ast_manager_user);
155
156 /*! \brief list of actions registered */
157 static struct manager_action *first_action = NULL;
158 AST_MUTEX_DEFINE_STATIC(actionlock);
159
160 /*! \brief
161  * helper functions to convert back and forth between
162  * string and numeric representation of set of flags
163  */
164 static struct permalias {
165         int num;
166         char *label;
167 } perms[] = {
168         { EVENT_FLAG_SYSTEM, "system" },
169         { EVENT_FLAG_CALL, "call" },
170         { EVENT_FLAG_LOG, "log" },
171         { EVENT_FLAG_VERBOSE, "verbose" },
172         { EVENT_FLAG_COMMAND, "command" },
173         { EVENT_FLAG_AGENT, "agent" },
174         { EVENT_FLAG_USER, "user" },
175         { EVENT_FLAG_CONFIG, "config" },
176         { -1, "all" },
177         { 0, "none" },
178 };
179
180 /*! \brief Convert authority code to a list of options */
181 static char *authority_to_str(int authority, char *res, int reslen)
182 {
183         int i;
184         char *dst = res, *sep = "";
185         size_t len = reslen;
186
187         res[0] = '\0';
188         for (i = 0; i < (sizeof(perms) / sizeof(perms[0])) - 1; i++) {
189                 if (authority & perms[i].num) {
190                         ast_build_string(&dst, &len, "%s%s", sep, perms[i].label);
191                         sep = ",";
192                 }
193         }
194
195         if (ast_strlen_zero(res))       /* replace empty string with something sensible */
196                 ast_copy_string(res, "<none>", reslen);
197
198         return res;
199 }
200
201 /*! Tells you if smallstr exists inside bigstr
202    which is delim by delim and uses no buf or stringsep
203    ast_instring("this|that|more","this",'|') == 1;
204
205    feel free to move this to app.c -anthm */
206 static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
207 {
208         const char *val = bigstr, *next;
209
210         do {
211                 if ((next = strchr(val, delim))) {
212                         if (!strncmp(val, smallstr, (next - val)))
213                                 return 1;
214                         else
215                                 continue;
216                 } else
217                         return !strcmp(smallstr, val);
218
219         } while (*(val = (next + 1)));
220
221         return 0;
222 }
223
224 static int get_perm(const char *instr)
225 {
226         int x = 0, ret = 0;
227
228         if (!instr)
229                 return 0;
230
231         for (x = 0; x < (sizeof(perms) / sizeof(perms[0])); x++) {
232                 if (ast_instring(instr, perms[x].label, ','))
233                         ret |= perms[x].num;
234         }
235
236         return ret;
237 }
238
239 /*!
240  * A number returns itself, false returns 0, true returns all flags,
241  * other strings return the flags that are set.
242  */
243 static int ast_strings_to_mask(const char *string)
244 {
245         const char *p;
246
247         if (ast_strlen_zero(string))
248                 return -1;
249
250         for (p = string; *p; p++)
251                 if (*p < '0' || *p > '9')
252                         break;
253         if (!p) /* all digits */
254                 return atoi(string);
255         if (ast_false(string))
256                 return 0;
257         if (ast_true(string)) { /* all permissions */
258                 int x, ret = 0;
259                 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
260                         ret |= perms[x].num;
261                 return ret;
262         }
263         return get_perm(string);
264 }
265
266 static char *complete_show_mancmd(const char *line, const char *word, int pos, int state)
267 {
268         struct manager_action *cur;
269         int l = strlen(word), which = 0;
270         char *ret = NULL;
271
272         ast_mutex_lock(&actionlock);
273         for (cur = first_action; cur; cur = cur->next) { /* Walk the list of actions */
274                 if (!strncasecmp(word, cur->action, l) && ++which > state) {
275                         ret = ast_strdup(cur->action);
276                         break;  /* make sure we exit even if ast_strdup() returns NULL */
277                 }
278         }
279         ast_mutex_unlock(&actionlock);
280
281         return ret;
282 }
283
284 /*!
285  * lookup an entry in the list of registered users.
286  * must be called with the list lock held.
287  */
288 static struct ast_manager_user *get_manager_by_name_locked(const char *name)
289 {
290         struct ast_manager_user *user = NULL;
291
292         AST_LIST_TRAVERSE(&users, user, list)
293                 if (!strcasecmp(user->username, name))
294                         break;
295         return user;
296 }
297
298
299 static int handle_showmancmd(int fd, int argc, char *argv[])
300 {
301         struct manager_action *cur;
302         char authority[80];
303         int num;
304
305         if (argc != 4)
306                 return RESULT_SHOWUSAGE;
307
308         ast_mutex_lock(&actionlock);
309         for (cur = first_action; cur; cur = cur->next) { /* Walk the list of actions */
310                 for (num = 3; num < argc; num++) {
311                         if (!strcasecmp(cur->action, argv[num])) {
312                                 ast_cli(fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
313                                         cur->action, cur->synopsis,
314                                         authority_to_str(cur->authority, authority, sizeof(authority) -1),
315                                         S_OR(cur->description, "") );
316                         }
317                 }
318         }
319         ast_mutex_unlock(&actionlock);
320
321         return RESULT_SUCCESS;
322 }
323
324 static int handle_showmanager(int fd, int argc, char *argv[])
325 {
326         struct ast_manager_user *user = NULL;
327
328         if (argc != 4)
329                 return RESULT_SHOWUSAGE;
330
331         AST_LIST_LOCK(&users);
332
333         if (!(user = get_manager_by_name_locked(argv[3]))) {
334                 ast_cli(fd, "There is no manager called %s\n", argv[3]);
335                 AST_LIST_UNLOCK(&users);
336                 return -1;
337         }
338
339         ast_cli(fd,"\n");
340         ast_cli(fd,
341                 "       username: %s\n"
342                 "         secret: %s\n"
343                 "           deny: %s\n"
344                 "         permit: %s\n"
345                 "           read: %s\n"
346                 "          write: %s\n"
347                 "displayconnects: %s\n",
348                 (user->username ? user->username : "(N/A)"),
349                 (user->secret ? user->secret : "(N/A)"),
350                 (user->deny ? user->deny : "(N/A)"),
351                 (user->permit ? user->permit : "(N/A)"),
352                 (user->read ? user->read : "(N/A)"),
353                 (user->write ? user->write : "(N/A)"),
354                 (user->displayconnects ? "yes" : "no"));
355
356         AST_LIST_UNLOCK(&users);
357
358         return RESULT_SUCCESS;
359 }
360
361
362 static int handle_showmanagers(int fd, int argc, char *argv[])
363 {
364         struct ast_manager_user *user = NULL;
365         int count_amu = 0;
366
367         if (argc != 3)
368                 return RESULT_SHOWUSAGE;
369
370         AST_LIST_LOCK(&users);
371
372         /* If there are no users, print out something along those lines */
373         if (AST_LIST_EMPTY(&users)) {
374                 ast_cli(fd, "There are no manager users.\n");
375                 AST_LIST_UNLOCK(&users);
376                 return RESULT_SUCCESS;
377         }
378
379         ast_cli(fd, "\nusername\n--------\n");
380
381         AST_LIST_TRAVERSE(&users, user, list) {
382                 ast_cli(fd, "%s\n", user->username);
383                 count_amu++;
384         }
385
386         AST_LIST_UNLOCK(&users);
387
388         ast_cli(fd,"-------------------\n");
389         ast_cli(fd,"%d manager users configured.\n", count_amu);
390
391         return RESULT_SUCCESS;
392 }
393
394
395 /*! \brief  CLI command  manager list commands */
396 static int handle_showmancmds(int fd, int argc, char *argv[])
397 {
398         struct manager_action *cur;
399         char authority[80];
400         char *format = "  %-15.15s  %-15.15s  %-55.55s\n";
401
402         ast_cli(fd, format, "Action", "Privilege", "Synopsis");
403         ast_cli(fd, format, "------", "---------", "--------");
404
405         ast_mutex_lock(&actionlock);
406         for (cur = first_action; cur; cur = cur->next) /* Walk the list of actions */
407                 ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
408         ast_mutex_unlock(&actionlock);
409
410         return RESULT_SUCCESS;
411 }
412
413 /*! \brief CLI command manager list connected */
414 static int handle_showmanconn(int fd, int argc, char *argv[])
415 {
416         struct mansession *s;
417         char *format = "  %-15.15s  %-15.15s\n";
418
419         ast_cli(fd, format, "Username", "IP Address");
420
421         AST_LIST_LOCK(&sessions);
422         AST_LIST_TRAVERSE(&sessions, s, list)
423                 ast_cli(fd, format,s->username, ast_inet_ntoa(s->sin.sin_addr));
424         AST_LIST_UNLOCK(&sessions);
425
426         return RESULT_SUCCESS;
427 }
428
429 /*! \brief CLI command manager list eventq */
430 /* Should change to "manager show connected" */
431 static int handle_showmaneventq(int fd, int argc, char *argv[])
432 {
433         struct eventqent *s;
434
435         AST_LIST_LOCK(&sessions);
436         for (s = master_eventq; s; s = s->next) {
437                 ast_cli(fd, "Usecount: %d\n",s->usecount);
438                 ast_cli(fd, "Category: %d\n", s->category);
439                 ast_cli(fd, "Event:\n%s", s->eventdata);
440         }
441         AST_LIST_UNLOCK(&sessions);
442
443         return RESULT_SUCCESS;
444 }
445
446 static char showmancmd_help[] =
447 "Usage: manager show command <actionname>\n"
448 "       Shows the detailed description for a specific Asterisk manager interface command.\n";
449
450 static char showmancmds_help[] =
451 "Usage: manager list commands\n"
452 "       Prints a listing of all the available Asterisk manager interface commands.\n";
453
454 static char showmanconn_help[] =
455 "Usage: manager list connected\n"
456 "       Prints a listing of the users that are currently connected to the\n"
457 "Asterisk manager interface.\n";
458
459 static char showmaneventq_help[] =
460 "Usage: manager list eventq\n"
461 "       Prints a listing of all events pending in the Asterisk manger\n"
462 "event queue.\n";
463
464 static char showmanagers_help[] =
465 "Usage: manager list users\n"
466 "       Prints a listing of all managers that are currently configured on that\n"
467 " system.\n";
468
469 static char showmanager_help[] =
470 " Usage: manager show user <user>\n"
471 "        Display all information related to the manager user specified.\n";
472
473 static struct ast_cli_entry cli_manager[] = {
474         { { "manager", "show", "command", NULL },
475         handle_showmancmd, "Show a manager interface command",
476         showmancmd_help, complete_show_mancmd },
477
478         { { "manager", "list", "commands", NULL },
479         handle_showmancmds, "List manager interface commands",
480         showmancmds_help },
481
482         { { "manager", "list", "connected", NULL },
483         handle_showmanconn, "List connected manager interface users",
484         showmanconn_help },
485
486         { { "manager", "list", "eventq", NULL },
487         handle_showmaneventq, "List manager interface queued events",
488         showmaneventq_help },
489
490         { { "manager", "list", "users", NULL },
491         handle_showmanagers, "List configured manager users",
492         showmanagers_help, NULL, NULL },
493
494         { { "manager", "show", "user", NULL },
495         handle_showmanager, "Display information on a specific manager user",
496         showmanager_help, NULL, NULL },
497 };
498
499 /*
500  * Decrement the usecount for the event; if it goes to zero,
501  * (why check for e->next ?) wakeup the
502  * main thread, which is in charge of freeing the record.
503  * Returns the next record.
504  */
505 static struct eventqent *unref_event(struct eventqent *e)
506 {
507         struct eventqent *ret = e->next;
508         if (ast_atomic_dec_and_test(&e->usecount) && ret)
509                 pthread_kill(accept_thread_ptr, SIGURG);
510         return ret;
511 }
512
513 static void free_session(struct mansession *s)
514 {
515         struct eventqent *eqe = s->eventq;
516         if (s->fd > -1)
517                 close(s->fd);
518         if (s->outputstr)
519                 free(s->outputstr);
520         ast_mutex_destroy(&s->__lock);
521         free(s);
522         while ( eqe )
523                 eqe = unref_event(eqe);
524 }
525
526 static void destroy_session(struct mansession *s)
527 {
528         AST_LIST_LOCK(&sessions);
529         ast_verbose("destroy session %lx\n", s->managerid);
530         AST_LIST_REMOVE(&sessions, s, list);
531         AST_LIST_UNLOCK(&sessions);
532
533         ast_atomic_fetchadd_int(&num_sessions, -1);
534         free_session(s);
535 }
536
537 char *astman_get_header(struct message *m, char *var)
538 {
539         int x, l = strlen(var);
540
541         for (x = 0; x < m->hdrcount; x++) {
542                 char *h = m->headers[x];
543                 if (!strncasecmp(var, h, l) && h[l] == ':' && h[l+1] == ' ')
544                         return h + l + 2;
545         }
546
547         return "";
548 }
549
550 struct ast_variable *astman_get_variables(struct message *m)
551 {
552         int varlen, x, y;
553         struct ast_variable *head = NULL, *cur;
554
555         AST_DECLARE_APP_ARGS(args,
556                 AST_APP_ARG(vars)[32];
557         );
558
559         varlen = strlen("Variable: ");
560
561         for (x = 0; x < m->hdrcount; x++) {
562                 char *parse, *var, *val;
563
564                 if (strncasecmp("Variable: ", m->headers[x], varlen))
565                         continue;
566                 parse = ast_strdupa(m->headers[x] + varlen);
567
568                 AST_STANDARD_APP_ARGS(args, parse);
569                 if (!args.argc)
570                         continue;
571                 for (y = 0; y < args.argc; y++) {
572                         if (!args.vars[y])
573                                 continue;
574                         var = val = ast_strdupa(args.vars[y]);
575                         strsep(&val, "=");
576                         if (!val || ast_strlen_zero(var))
577                                 continue;
578                         cur = ast_variable_new(var, val);
579                         cur->next = head;
580                         head = cur;
581                 }
582         }
583
584         return head;
585 }
586
587 /*
588  * utility functions for creating AMI replies
589  */
590 void astman_append(struct mansession *s, const char *fmt, ...)
591 {
592         va_list ap;
593         struct ast_dynamic_str *buf;
594
595         if (!(buf = ast_dynamic_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE)))
596                 return;
597
598         va_start(ap, fmt);
599         ast_dynamic_str_thread_set_va(&buf, 0, &astman_append_buf, fmt, ap);
600         va_end(ap);
601
602         if (s->fd > -1)
603                 ast_carefulwrite(s->fd, buf->str, strlen(buf->str), s->writetimeout);
604         else {
605                 if (!s->outputstr && !(s->outputstr = ast_calloc(1, sizeof(*s->outputstr))))
606                         return;
607
608                 ast_dynamic_str_append(&s->outputstr, 0, "%s", buf->str);
609         }
610 }
611
612 /*! \note NOTE: XXX this comment is unclear and possibly wrong.
613    Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
614    hold the session lock _or_ be running in an action callback (in which case s->busy will
615    be non-zero). In either of these cases, there is no need to lock-protect the session's
616    fd, since no other output will be sent (events will be queued), and no input will
617    be read until either the current action finishes or get_input() obtains the session
618    lock.
619  */
620
621 /*! \brief send a response with an optional message,
622  * and terminate it with an empty line.
623  * m is used only to grab the 'ActionID' field.
624  *
625  * Use the explicit constant MSG_MOREDATA to remove the empty line.
626  * XXX MSG_MOREDATA should go to a header file.
627  */
628 #define MSG_MOREDATA    ((char *)astman_send_response)
629 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
630 {
631         char *id = astman_get_header(m,"ActionID");
632
633         astman_append(s, "Response: %s\r\n", resp);
634         if (!ast_strlen_zero(id))
635                 astman_append(s, "ActionID: %s\r\n", id);
636         if (msg == MSG_MOREDATA)
637                 return;
638         else if (msg)
639                 astman_append(s, "Message: %s\r\n\r\n", msg);
640         else
641                 astman_append(s, "\r\n");
642 }
643
644 void astman_send_error(struct mansession *s, struct message *m, char *error)
645 {
646         astman_send_response(s, m, "Error", error);
647 }
648
649 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
650 {
651         astman_send_response(s, m, "Success", msg);
652 }
653
654 static void astman_start_ack(struct mansession *s, struct message *m)
655 {
656         astman_send_response(s, m, "Success", MSG_MOREDATA);
657 }
658
659
660
661 /*! \brief
662    Rather than braindead on,off this now can also accept a specific int mask value
663    or a ',' delim list of mask strings (the same as manager.conf) -anthm
664 */
665 static int set_eventmask(struct mansession *s, char *eventmask)
666 {
667         int maskint = ast_strings_to_mask(eventmask);
668
669         ast_mutex_lock(&s->__lock);
670         if (maskint >= 0)
671                 s->send_events = maskint;
672         ast_mutex_unlock(&s->__lock);
673
674         return maskint;
675 }
676
677 /*
678  * Here we start with action_ handlers for AMI actions,
679  * and the internal functions used by them.
680  * Generally, the handlers are called action_foo()
681  */
682
683 /* helper function for action_login() */
684 static int authenticate(struct mansession *s, struct message *m)
685 {
686         char *user = astman_get_header(m, "Username");
687         int error = -1;
688         struct ast_ha *ha = NULL;
689         char *password = NULL;
690         int readperm = 0, writeperm = 0;
691
692         if (ast_strlen_zero(user))      /* missing username */
693                 return -1;
694
695     {
696         /*
697          * XXX there should be no need to scan the config file again here,
698          * suffices to call get_manager_by_name_locked() to fetch
699          * the user's entry.
700          */
701         struct ast_config *cfg = ast_config_load("manager.conf");
702         char *cat = NULL;
703         struct ast_variable *v;
704
705         if (!cfg)
706                 return -1;
707         while ( (cat = ast_category_browse(cfg, cat)) ) {
708                 /* "general" is not a valid user */
709                 if (!strcasecmp(cat, user) && strcasecmp(cat, "general"))
710                         break;
711         }
712         if (!cat) {
713                 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->sin.sin_addr), user);
714                 ast_config_destroy(cfg);
715                 return -1;
716         }
717
718         /* collect parameters for the user's entry */
719         for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
720                 if (!strcasecmp(v->name, "secret"))
721                         password = ast_strdupa(v->value);
722                 else if (!strcasecmp(v->name, "read"))
723                         readperm = get_perm(v->value);
724                 else if (!strcasecmp(v->name, "write"))
725                         writeperm = get_perm(v->value);
726                 else if (!strcasecmp(v->name, "permit") ||
727                            !strcasecmp(v->name, "deny")) {
728                         ha = ast_append_ha(v->name, v->value, ha);
729                 } else if (!strcasecmp(v->name, "writetimeout")) {
730                         int val = atoi(v->value);
731
732                         if (val < 100)
733                                 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
734                         else
735                                 s->writetimeout = val;
736                 }
737         }
738         ast_config_destroy(cfg);
739     }
740
741         if (ha) {
742                 int good = ast_apply_ha(ha, &(s->sin));
743                 ast_free_ha(ha);
744                 if (!good) {
745                         ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), user);
746                         return -1;
747                 }
748         }
749         if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
750                 char *key = astman_get_header(m, "Key");
751                 if (!ast_strlen_zero(key) && !ast_strlen_zero(s->challenge)) {
752                         int x;
753                         int len = 0;
754                         char md5key[256] = "";
755                         struct MD5Context md5;
756                         unsigned char digest[16];
757
758                         MD5Init(&md5);
759                         MD5Update(&md5, (unsigned char *) s->challenge, strlen(s->challenge));
760                         MD5Update(&md5, (unsigned char *) password, strlen(password));
761                         MD5Final(digest, &md5);
762                         for (x=0; x<16; x++)
763                                 len += sprintf(md5key + len, "%2.2x", digest[x]);
764                         if (!strcmp(md5key, key))
765                                 error = 0;
766                 }
767         } else if (password) {
768                 char *pass = astman_get_header(m, "Secret");
769                 if (!strcmp(password, pass))
770                         error = 0;
771         }
772         if (error) {
773                 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), user);
774                 return -1;
775         }
776         ast_copy_string(s->username, user, sizeof(s->username));
777         s->readperm = readperm;
778         s->writeperm = writeperm;
779         set_eventmask(s, astman_get_header(m, "Events"));
780         return 0;
781 }
782
783 /*! \brief Manager PING */
784 static char mandescr_ping[] =
785 "Description: A 'Ping' action will ellicit a 'Pong' response.  Used to keep the\n"
786 "  manager connection open.\n"
787 "Variables: NONE\n";
788
789 static int action_ping(struct mansession *s, struct message *m)
790 {
791         astman_send_response(s, m, "Pong", NULL);
792         return 0;
793 }
794
795 static char mandescr_getconfig[] =
796 "Description: A 'GetConfig' action will dump the contents of a configuration\n"
797 "file by category and contents.\n"
798 "Variables:\n"
799 "   Filename: Configuration filename (e.g. foo.conf)\n";
800
801 static int action_getconfig(struct mansession *s, struct message *m)
802 {
803         struct ast_config *cfg;
804         char *fn = astman_get_header(m, "Filename");
805         int catcount = 0;
806         int lineno = 0;
807         char *category=NULL;
808         struct ast_variable *v;
809
810         if (ast_strlen_zero(fn)) {
811                 astman_send_error(s, m, "Filename not specified");
812                 return 0;
813         }
814         if (!(cfg = ast_config_load(fn))) {
815                 astman_send_error(s, m, "Config file not found");
816                 return 0;
817         }
818         astman_start_ack(s, m);
819         while ((category = ast_category_browse(cfg, category))) {
820                 lineno = 0;
821                 astman_append(s, "Category-%06d: %s\r\n", catcount, category);
822                 for (v = ast_variable_browse(cfg, category); v; v = v->next)
823                         astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
824                 catcount++;
825         }
826         ast_config_destroy(cfg);
827         astman_append(s, "\r\n");
828
829         return 0;
830 }
831
832 /* helper function for action_updateconfig */
833 static void handle_updates(struct mansession *s, struct message *m, struct ast_config *cfg)
834 {
835         int x;
836         char hdr[40];
837         char *action, *cat, *var, *value, *match;
838         struct ast_category *category;
839         struct ast_variable *v;
840
841         for (x=0;x<100000;x++) {
842                 snprintf(hdr, sizeof(hdr), "Action-%06d", x);
843                 action = astman_get_header(m, hdr);
844                 if (ast_strlen_zero(action))
845                         break;
846                 snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
847                 cat = astman_get_header(m, hdr);
848                 snprintf(hdr, sizeof(hdr), "Var-%06d", x);
849                 var = astman_get_header(m, hdr);
850                 snprintf(hdr, sizeof(hdr), "Value-%06d", x);
851                 value = astman_get_header(m, hdr);
852                 snprintf(hdr, sizeof(hdr), "Match-%06d", x);
853                 match = astman_get_header(m, hdr);
854                 if (!strcasecmp(action, "newcat")) {
855                         if (!ast_strlen_zero(cat)) {
856                                 category = ast_category_new(cat);
857                                 if (category) {
858                                         ast_category_append(cfg, category);
859                                 }
860                         }
861                 } else if (!strcasecmp(action, "renamecat")) {
862                         if (!ast_strlen_zero(cat) && !ast_strlen_zero(value)) {
863                                 category = ast_category_get(cfg, cat);
864                                 if (category)
865                                         ast_category_rename(category, value);
866                         }
867                 } else if (!strcasecmp(action, "delcat")) {
868                         if (!ast_strlen_zero(cat))
869                                 ast_category_delete(cfg, cat);
870                 } else if (!strcasecmp(action, "update")) {
871                         if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) && (category = ast_category_get(cfg, cat)))
872                                 ast_variable_update(category, var, value, match);
873                 } else if (!strcasecmp(action, "delete")) {
874                         if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) && (category = ast_category_get(cfg, cat)))
875                                 ast_variable_delete(category, var, match);
876                 } else if (!strcasecmp(action, "append")) {
877                         if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) &&
878                                 (category = ast_category_get(cfg, cat)) &&
879                                 (v = ast_variable_new(var, value))){
880                                 if (match && !strcasecmp(match, "object"))
881                                         v->object = 1;
882                                 ast_variable_append(category, v);
883                         }
884                 }
885         }
886 }
887
888 static char mandescr_updateconfig[] =
889 "Description: A 'UpdateConfig' action will dump the contents of a configuration\n"
890 "file by category and contents.\n"
891 "Variables (X's represent 6 digit number beginning with 000000):\n"
892 "   SrcFilename:   Configuration filename to read(e.g. foo.conf)\n"
893 "   DstFilename:   Configuration filename to write(e.g. foo.conf)\n"
894 "   Reload:        Whether or not a reload should take place (or name of specific module)\n"
895 "   Action-XXXXXX: Action to Take (NewCat,RenameCat,DelCat,Update,Delete,Append)\n"
896 "   Cat-XXXXXX:    Category to operate on\n"
897 "   Var-XXXXXX:    Variable to work on\n"
898 "   Value-XXXXXX:  Value to work on\n"
899 "   Match-XXXXXX:  Extra match required to match line\n";
900
901 static int action_updateconfig(struct mansession *s, struct message *m)
902 {
903         struct ast_config *cfg;
904         char *sfn = astman_get_header(m, "SrcFilename");
905         char *dfn = astman_get_header(m, "DstFilename");
906         int res;
907         char *rld = astman_get_header(m, "Reload");
908
909         if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
910                 astman_send_error(s, m, "Filename not specified");
911                 return 0;
912         }
913         if (!(cfg = ast_config_load(sfn))) {
914                 astman_send_error(s, m, "Config file not found");
915                 return 0;
916         }
917         handle_updates(s, m, cfg);
918         res = config_text_file_save(dfn, cfg, "Manager");
919         ast_config_destroy(cfg);
920         if (res) {
921                 astman_send_error(s, m, "Save of config failed");
922                 return 0;
923         }
924         astman_send_ack(s, m, NULL);
925         if (!ast_strlen_zero(rld)) {
926                 if (ast_true(rld))
927                         rld = NULL;
928                 ast_module_reload(rld);
929         }
930         return 0;
931 }
932
933 /*! \brief Manager WAITEVENT */
934 static char mandescr_waitevent[] =
935 "Description: A 'WaitEvent' action will ellicit a 'Success' response.  Whenever\n"
936 "a manager event is queued.  Once WaitEvent has been called on an HTTP manager\n"
937 "session, events will be generated and queued.\n"
938 "Variables: \n"
939 "   Timeout: Maximum time to wait for events\n";
940
941 static int action_waitevent(struct mansession *s, struct message *m)
942 {
943         char *timeouts = astman_get_header(m, "Timeout");
944         int timeout = -1, max;
945         int x;
946         int needexit = 0;
947         time_t now;
948         struct eventqent *eqe;
949         char *id = astman_get_header(m,"ActionID");
950         char idText[256] = "";
951
952         if (!ast_strlen_zero(id))
953                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
954
955         if (!ast_strlen_zero(timeouts)) {
956                 sscanf(timeouts, "%i", &timeout);
957         }
958
959         ast_mutex_lock(&s->__lock);
960         if (s->waiting_thread != AST_PTHREADT_NULL) {
961                 pthread_kill(s->waiting_thread, SIGURG);
962         }
963         if (s->sessiontimeout) {
964                 time(&now);
965                 max = s->sessiontimeout - now - 10;
966                 if (max < 0)
967                         max = 0;
968                 if ((timeout < 0) || (timeout > max))
969                         timeout = max;
970                 if (!s->send_events)
971                         s->send_events = -1;
972                 /* Once waitevent is called, always queue events from now on */
973         }
974         ast_mutex_unlock(&s->__lock);
975         s->waiting_thread = pthread_self();
976         if (option_debug)
977                 ast_log(LOG_DEBUG, "Starting waiting for an event!\n");
978         for (x=0; ((x < timeout) || (timeout < 0)); x++) {
979                 ast_mutex_lock(&s->__lock);
980                 if (s->eventq && s->eventq->next)
981                         needexit = 1;
982                 if (s->waiting_thread != pthread_self())
983                         needexit = 1;
984                 if (s->needdestroy)
985                         needexit = 1;
986                 ast_mutex_unlock(&s->__lock);
987                 if (needexit)
988                         break;
989                 if (!s->inuse && s->fd > 0) {   /* AMI session */
990                         if (ast_wait_for_input(s->fd, 1000))
991                                 break;
992                 } else {        /* HTTP session */
993                         sleep(1);
994                 }
995         }
996         if (option_debug)
997                 ast_log(LOG_DEBUG, "Finished waiting for an event!\n");
998         ast_mutex_lock(&s->__lock);
999         if (s->waiting_thread == pthread_self()) {
1000                 astman_send_response(s, m, "Success", "Waiting for Event...");
1001                 /* Only show events if we're the most recent waiter */
1002                 while(s->eventq->next) {
1003                         eqe = s->eventq->next;
1004                         if (((s->readperm & eqe->category) == eqe->category) &&
1005                             ((s->send_events & eqe->category) == eqe->category)) {
1006                                 astman_append(s, "%s", eqe->eventdata);
1007                         }
1008                         unref_event(s->eventq);
1009                         s->eventq = eqe;
1010                 }
1011                 astman_append(s,
1012                         "Event: WaitEventComplete\r\n"
1013                         "%s"
1014                         "\r\n", idText);
1015                 s->waiting_thread = AST_PTHREADT_NULL;
1016         } else {
1017                 if (option_debug)
1018                         ast_log(LOG_DEBUG, "Abandoning event request!\n");
1019         }
1020         ast_mutex_unlock(&s->__lock);
1021         return 0;
1022 }
1023
1024 static char mandescr_listcommands[] =
1025 "Description: Returns the action name and synopsis for every\n"
1026 "  action that is available to the user\n"
1027 "Variables: NONE\n";
1028
1029 static int action_listcommands(struct mansession *s, struct message *m)
1030 {
1031         struct manager_action *cur;
1032         char temp[BUFSIZ];
1033
1034         astman_start_ack(s, m);
1035         ast_mutex_lock(&actionlock);
1036         for (cur = first_action; cur; cur = cur->next) { /* Walk the list of actions */
1037                 if ((s->writeperm & cur->authority) == cur->authority)
1038                         astman_append(s, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)));
1039         }
1040         ast_mutex_unlock(&actionlock);
1041         astman_append(s, "\r\n");
1042
1043         return 0;
1044 }
1045
1046 static char mandescr_events[] =
1047 "Description: Enable/Disable sending of events to this manager\n"
1048 "  client.\n"
1049 "Variables:\n"
1050 "       EventMask: 'on' if all events should be sent,\n"
1051 "               'off' if no events should be sent,\n"
1052 "               'system,call,log' to select which flags events should have to be sent.\n";
1053
1054 static int action_events(struct mansession *s, struct message *m)
1055 {
1056         char *mask = astman_get_header(m, "EventMask");
1057         int res;
1058
1059         res = set_eventmask(s, mask);
1060         if (res > 0)
1061                 astman_send_response(s, m, "Events On", NULL);
1062         else if (res == 0)
1063                 astman_send_response(s, m, "Events Off", NULL);
1064
1065         return 0;
1066 }
1067
1068 static char mandescr_logoff[] =
1069 "Description: Logoff this manager session\n"
1070 "Variables: NONE\n";
1071
1072 static int action_logoff(struct mansession *s, struct message *m)
1073 {
1074         astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
1075         return -1;
1076 }
1077
1078 static int action_login(struct mansession *s, struct message *m)
1079 {
1080         if (authenticate(s, m)) {
1081                 sleep(1);
1082                 astman_send_error(s, m, "Authentication failed");
1083                 return -1;
1084         }
1085         s->authenticated = 1;
1086         if (option_verbose > 1) {
1087                 if (displayconnects) {
1088                         ast_verbose(VERBOSE_PREFIX_2 "%sManager '%s' logged on from %s\n", (s->sessiontimeout ? "HTTP " : ""), s->username, ast_inet_ntoa(s->sin.sin_addr));
1089                 }
1090         }
1091         ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n", (s->sessiontimeout ? "HTTP " : ""), s->username, ast_inet_ntoa(s->sin.sin_addr));
1092         astman_send_ack(s, m, "Authentication accepted");
1093         return 0;
1094 }
1095
1096 static int action_challenge(struct mansession *s, struct message *m)
1097 {
1098         char *authtype = astman_get_header(m, "AuthType");
1099
1100         if (!strcasecmp(authtype, "MD5")) {
1101                 if (ast_strlen_zero(s->challenge))
1102                         snprintf(s->challenge, sizeof(s->challenge), "%ld", ast_random());
1103                 ast_mutex_lock(&s->__lock);
1104                 astman_start_ack(s, m);
1105                 astman_append(s, "Challenge: %s\r\n\r\n", s->challenge);
1106                 ast_mutex_unlock(&s->__lock);
1107         } else {
1108                 astman_send_error(s, m, "Must specify AuthType");
1109         }
1110         return 0;
1111 }
1112
1113 static char mandescr_hangup[] =
1114 "Description: Hangup a channel\n"
1115 "Variables: \n"
1116 "       Channel: The channel name to be hungup\n";
1117
1118 static int action_hangup(struct mansession *s, struct message *m)
1119 {
1120         struct ast_channel *c = NULL;
1121         char *name = astman_get_header(m, "Channel");
1122         if (ast_strlen_zero(name)) {
1123                 astman_send_error(s, m, "No channel specified");
1124                 return 0;
1125         }
1126         c = ast_get_channel_by_name_locked(name);
1127         if (!c) {
1128                 astman_send_error(s, m, "No such channel");
1129                 return 0;
1130         }
1131         ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
1132         ast_channel_unlock(c);
1133         astman_send_ack(s, m, "Channel Hungup");
1134         return 0;
1135 }
1136
1137 static char mandescr_setvar[] =
1138 "Description: Set a global or local channel variable.\n"
1139 "Variables: (Names marked with * are required)\n"
1140 "       Channel: Channel to set variable for\n"
1141 "       *Variable: Variable name\n"
1142 "       *Value: Value\n";
1143
1144 static int action_setvar(struct mansession *s, struct message *m)
1145 {
1146         struct ast_channel *c = NULL;
1147         char *name = astman_get_header(m, "Channel");
1148         char *varname = astman_get_header(m, "Variable");
1149         char *varval = astman_get_header(m, "Value");
1150
1151         if (ast_strlen_zero(varname)) {
1152                 astman_send_error(s, m, "No variable specified");
1153                 return 0;
1154         }
1155
1156         if (ast_strlen_zero(varval)) {
1157                 astman_send_error(s, m, "No value specified");
1158                 return 0;
1159         }
1160
1161         if (!ast_strlen_zero(name)) {
1162                 c = ast_get_channel_by_name_locked(name);
1163                 if (!c) {
1164                         astman_send_error(s, m, "No such channel");
1165                         return 0;
1166                 }
1167         }
1168
1169         pbx_builtin_setvar_helper(c, varname, varval);
1170
1171         if (c)
1172                 ast_channel_unlock(c);
1173
1174         astman_send_ack(s, m, "Variable Set");
1175
1176         return 0;
1177 }
1178
1179 static char mandescr_getvar[] =
1180 "Description: Get the value of a global or local channel variable.\n"
1181 "Variables: (Names marked with * are required)\n"
1182 "       Channel: Channel to read variable from\n"
1183 "       *Variable: Variable name\n"
1184 "       ActionID: Optional Action id for message matching.\n";
1185
1186 static int action_getvar(struct mansession *s, struct message *m)
1187 {
1188         struct ast_channel *c = NULL;
1189         char *name = astman_get_header(m, "Channel");
1190         char *varname = astman_get_header(m, "Variable");
1191         char *varval;
1192         char workspace[1024];
1193
1194         if (ast_strlen_zero(varname)) {
1195                 astman_send_error(s, m, "No variable specified");
1196                 return 0;
1197         }
1198
1199         if (!ast_strlen_zero(name)) {
1200                 c = ast_get_channel_by_name_locked(name);
1201                 if (!c) {
1202                         astman_send_error(s, m, "No such channel");
1203                         return 0;
1204                 }
1205         }
1206
1207         if (varname[strlen(varname) - 1] == ')') {
1208                 ast_func_read(c, varname, workspace, sizeof(workspace));
1209         } else {
1210                 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
1211         }
1212
1213         if (c)
1214                 ast_channel_unlock(c);
1215         astman_start_ack(s, m);
1216         astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, varval);
1217
1218         return 0;
1219 }
1220
1221
1222 /*! \brief Manager "status" command to show channels */
1223 /* Needs documentation... */
1224 static int action_status(struct mansession *s, struct message *m)
1225 {
1226         char *name = astman_get_header(m,"Channel");
1227         struct ast_channel *c;
1228         char bridge[256];
1229         struct timeval now = ast_tvnow();
1230         long elapsed_seconds = 0;
1231         int all = ast_strlen_zero(name); /* set if we want all channels */
1232         char *id = astman_get_header(m,"ActionID");
1233         char idText[256] = "";
1234
1235         if (!ast_strlen_zero(id))
1236                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
1237
1238         astman_send_ack(s, m, "Channel status will follow");
1239         if (all)
1240                 c = ast_channel_walk_locked(NULL);
1241         else {
1242                 c = ast_get_channel_by_name_locked(name);
1243                 if (!c) {
1244                         astman_send_error(s, m, "No such channel");
1245                         return 0;
1246                 }
1247         }
1248         /* if we look by name, we break after the first iteration */
1249         while (c) {
1250                 if (c->_bridge)
1251                         snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->_bridge->name);
1252                 else
1253                         bridge[0] = '\0';
1254                 if (c->pbx) {
1255                         if (c->cdr) {
1256                                 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
1257                         }
1258                         astman_append(s,
1259                         "Event: Status\r\n"
1260                         "Privilege: Call\r\n"
1261                         "Channel: %s\r\n"
1262                         "CallerIDNum: %s\r\n"
1263                         "CallerIDName: %s\r\n"
1264                         "Account: %s\r\n"
1265                         "State: %s\r\n"
1266                         "Context: %s\r\n"
1267                         "Extension: %s\r\n"
1268                         "Priority: %d\r\n"
1269                         "Seconds: %ld\r\n"
1270                         "%s"
1271                         "Uniqueid: %s\r\n"
1272                         "%s"
1273                         "\r\n",
1274                         c->name,
1275                         S_OR(c->cid.cid_num, "<unknown>"),
1276                         S_OR(c->cid.cid_name, "<unknown>"),
1277                         c->accountcode,
1278                         ast_state2str(c->_state), c->context,
1279                         c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
1280                 } else {
1281                         astman_append(s,
1282                         "Event: Status\r\n"
1283                         "Privilege: Call\r\n"
1284                         "Channel: %s\r\n"
1285                         "CallerIDNum: %s\r\n"
1286                         "CallerIDName: %s\r\n"
1287                         "Account: %s\r\n"
1288                         "State: %s\r\n"
1289                         "%s"
1290                         "Uniqueid: %s\r\n"
1291                         "%s"
1292                         "\r\n",
1293                         c->name,
1294                         S_OR(c->cid.cid_num, "<unknown>"),
1295                         S_OR(c->cid.cid_name, "<unknown>"),
1296                         c->accountcode,
1297                         ast_state2str(c->_state), bridge, c->uniqueid, idText);
1298                 }
1299                 ast_channel_unlock(c);
1300                 if (!all)
1301                         break;
1302                 c = ast_channel_walk_locked(c);
1303         }
1304         astman_append(s,
1305         "Event: StatusComplete\r\n"
1306         "%s"
1307         "\r\n",idText);
1308         return 0;
1309 }
1310
1311 static char mandescr_redirect[] =
1312 "Description: Redirect (transfer) a call.\n"
1313 "Variables: (Names marked with * are required)\n"
1314 "       *Channel: Channel to redirect\n"
1315 "       ExtraChannel: Second call leg to transfer (optional)\n"
1316 "       *Exten: Extension to transfer to\n"
1317 "       *Context: Context to transfer to\n"
1318 "       *Priority: Priority to transfer to\n"
1319 "       ActionID: Optional Action id for message matching.\n";
1320
1321 /*! \brief  action_redirect: The redirect manager command */
1322 static int action_redirect(struct mansession *s, struct message *m)
1323 {
1324         char *name = astman_get_header(m, "Channel");
1325         char *name2 = astman_get_header(m, "ExtraChannel");
1326         char *exten = astman_get_header(m, "Exten");
1327         char *context = astman_get_header(m, "Context");
1328         char *priority = astman_get_header(m, "Priority");
1329         struct ast_channel *chan, *chan2 = NULL;
1330         int pi = 0;
1331         int res;
1332
1333         if (ast_strlen_zero(name)) {
1334                 astman_send_error(s, m, "Channel not specified");
1335                 return 0;
1336         }
1337         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
1338                 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
1339                         astman_send_error(s, m, "Invalid priority\n");
1340                         return 0;
1341                 }
1342         }
1343         /* XXX watch out, possible deadlock - we are trying to get two channels!!! */
1344         chan = ast_get_channel_by_name_locked(name);
1345         if (!chan) {
1346                 char buf[BUFSIZ];
1347                 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
1348                 astman_send_error(s, m, buf);
1349                 return 0;
1350         }
1351         if (!ast_strlen_zero(name2))
1352                 chan2 = ast_get_channel_by_name_locked(name2);
1353         res = ast_async_goto(chan, context, exten, pi);
1354         if (!res) {
1355                 if (!ast_strlen_zero(name2)) {
1356                         if (chan2)
1357                                 res = ast_async_goto(chan2, context, exten, pi);
1358                         else
1359                                 res = -1;
1360                         if (!res)
1361                                 astman_send_ack(s, m, "Dual Redirect successful");
1362                         else
1363                                 astman_send_error(s, m, "Secondary redirect failed");
1364                 } else
1365                         astman_send_ack(s, m, "Redirect successful");
1366         } else
1367                 astman_send_error(s, m, "Redirect failed");
1368         if (chan)
1369                 ast_channel_unlock(chan);
1370         if (chan2)
1371                 ast_channel_unlock(chan2);
1372         return 0;
1373 }
1374
1375 static char mandescr_command[] =
1376 "Description: Run a CLI command.\n"
1377 "Variables: (Names marked with * are required)\n"
1378 "       *Command: Asterisk CLI command to run\n"
1379 "       ActionID: Optional Action id for message matching.\n";
1380
1381 /*! \brief  Manager command "command" - execute CLI command */
1382 static int action_command(struct mansession *s, struct message *m)
1383 {
1384         char *cmd = astman_get_header(m, "Command");
1385         char *id = astman_get_header(m, "ActionID");
1386         astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
1387         if (!ast_strlen_zero(id))
1388                 astman_append(s, "ActionID: %s\r\n", id);
1389         /* FIXME: Wedge a ActionID response in here, waiting for later changes */
1390         ast_cli_command(s->fd, cmd);
1391         astman_append(s, "--END COMMAND--\r\n\r\n");
1392         return 0;
1393 }
1394
1395 /* helper function for originate */
1396 struct fast_originate_helper {
1397         char tech[AST_MAX_MANHEADER_LEN];
1398         char data[AST_MAX_MANHEADER_LEN];
1399         int timeout;
1400         char app[AST_MAX_APP];
1401         char appdata[AST_MAX_MANHEADER_LEN];
1402         char cid_name[AST_MAX_MANHEADER_LEN];
1403         char cid_num[AST_MAX_MANHEADER_LEN];
1404         char context[AST_MAX_CONTEXT];
1405         char exten[AST_MAX_EXTENSION];
1406         char idtext[AST_MAX_MANHEADER_LEN];
1407         char account[AST_MAX_ACCOUNT_CODE];
1408         int priority;
1409         struct ast_variable *vars;
1410 };
1411
1412 static void *fast_originate(void *data)
1413 {
1414         struct fast_originate_helper *in = data;
1415         int res;
1416         int reason = 0;
1417         struct ast_channel *chan = NULL;
1418
1419         if (!ast_strlen_zero(in->app)) {
1420                 res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1,
1421                         S_OR(in->cid_num, NULL),
1422                         S_OR(in->cid_name, NULL),
1423                         in->vars, in->account, &chan);
1424         } else {
1425                 res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
1426                         S_OR(in->cid_num, NULL),
1427                         S_OR(in->cid_name, NULL),
1428                         in->vars, in->account, &chan);
1429         }
1430
1431         /* Tell the manager what happened with the channel */
1432         manager_event(EVENT_FLAG_CALL,
1433                 res ? "OriginateFailure" : "OriginateSuccess",
1434                 "%s"
1435                 "Channel: %s/%s\r\n"
1436                 "Context: %s\r\n"
1437                 "Exten: %s\r\n"
1438                 "Reason: %d\r\n"
1439                 "Uniqueid: %s\r\n"
1440                 "CallerIDNum: %s\r\n"
1441                 "CallerIDName: %s\r\n",
1442                 in->idtext, in->tech, in->data, in->context, in->exten, reason,
1443                 chan ? chan->uniqueid : "<null>",
1444                 S_OR(in->cid_num, "<unknown>"),
1445                 S_OR(in->cid_name, "<unknown>")
1446                 );
1447
1448         /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
1449         if (chan)
1450                 ast_channel_unlock(chan);
1451         free(in);
1452         return NULL;
1453 }
1454
1455 static char mandescr_originate[] =
1456 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
1457 "  Application/Data\n"
1458 "Variables: (Names marked with * are required)\n"
1459 "       *Channel: Channel name to call\n"
1460 "       Exten: Extension to use (requires 'Context' and 'Priority')\n"
1461 "       Context: Context to use (requires 'Exten' and 'Priority')\n"
1462 "       Priority: Priority to use (requires 'Exten' and 'Context')\n"
1463 "       Application: Application to use\n"
1464 "       Data: Data to use (requires 'Application')\n"
1465 "       Timeout: How long to wait for call to be answered (in ms)\n"
1466 "       CallerID: Caller ID to be set on the outgoing channel\n"
1467 "       Variable: Channel variable to set, multiple Variable: headers are allowed\n"
1468 "       Account: Account code\n"
1469 "       Async: Set to 'true' for fast origination\n";
1470
1471 static int action_originate(struct mansession *s, struct message *m)
1472 {
1473         char *name = astman_get_header(m, "Channel");
1474         char *exten = astman_get_header(m, "Exten");
1475         char *context = astman_get_header(m, "Context");
1476         char *priority = astman_get_header(m, "Priority");
1477         char *timeout = astman_get_header(m, "Timeout");
1478         char *callerid = astman_get_header(m, "CallerID");
1479         char *account = astman_get_header(m, "Account");
1480         char *app = astman_get_header(m, "Application");
1481         char *appdata = astman_get_header(m, "Data");
1482         char *async = astman_get_header(m, "Async");
1483         char *id = astman_get_header(m, "ActionID");
1484         struct ast_variable *vars = astman_get_variables(m);
1485         char *tech, *data;
1486         char *l = NULL, *n = NULL;
1487         int pi = 0;
1488         int res;
1489         int to = 30000;
1490         int reason = 0;
1491         char tmp[256];
1492         char tmp2[256];
1493
1494         pthread_t th;
1495         pthread_attr_t attr;
1496         if (!name) {
1497                 astman_send_error(s, m, "Channel not specified");
1498                 return 0;
1499         }
1500         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
1501                 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
1502                         astman_send_error(s, m, "Invalid priority\n");
1503                         return 0;
1504                 }
1505         }
1506         if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
1507                 astman_send_error(s, m, "Invalid timeout\n");
1508                 return 0;
1509         }
1510         ast_copy_string(tmp, name, sizeof(tmp));
1511         tech = tmp;
1512         data = strchr(tmp, '/');
1513         if (!data) {
1514                 astman_send_error(s, m, "Invalid channel\n");
1515                 return 0;
1516         }
1517         *data++ = '\0';
1518         ast_copy_string(tmp2, callerid, sizeof(tmp2));
1519         ast_callerid_parse(tmp2, &n, &l);
1520         if (n) {
1521                 if (ast_strlen_zero(n))
1522                         n = NULL;
1523         }
1524         if (l) {
1525                 ast_shrink_phone_number(l);
1526                 if (ast_strlen_zero(l))
1527                         l = NULL;
1528         }
1529         if (ast_true(async)) {
1530                 struct fast_originate_helper *fast = ast_calloc(1, sizeof(*fast));
1531                 if (!fast) {
1532                         res = -1;
1533                 } else {
1534                         if (!ast_strlen_zero(id))
1535                                 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
1536                         ast_copy_string(fast->tech, tech, sizeof(fast->tech));
1537                         ast_copy_string(fast->data, data, sizeof(fast->data));
1538                         ast_copy_string(fast->app, app, sizeof(fast->app));
1539                         ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
1540                         if (l)
1541                                 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
1542                         if (n)
1543                                 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
1544                         fast->vars = vars;
1545                         ast_copy_string(fast->context, context, sizeof(fast->context));
1546                         ast_copy_string(fast->exten, exten, sizeof(fast->exten));
1547                         ast_copy_string(fast->account, account, sizeof(fast->account));
1548                         fast->timeout = to;
1549                         fast->priority = pi;
1550                         pthread_attr_init(&attr);
1551                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1552                         if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
1553                                 res = -1;
1554                         } else {
1555                                 res = 0;
1556                         }
1557                 }
1558         } else if (!ast_strlen_zero(app)) {
1559                 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
1560         } else {
1561                 if (exten && context && pi)
1562                         res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
1563                 else {
1564                         astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
1565                         return 0;
1566                 }
1567         }
1568         if (!res)
1569                 astman_send_ack(s, m, "Originate successfully queued");
1570         else
1571                 astman_send_error(s, m, "Originate failed");
1572         return 0;
1573 }
1574
1575 /*! \brief Help text for manager command mailboxstatus
1576  */
1577 static char mandescr_mailboxstatus[] =
1578 "Description: Checks a voicemail account for status.\n"
1579 "Variables: (Names marked with * are required)\n"
1580 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1581 "       ActionID: Optional ActionID for message matching.\n"
1582 "Returns number of messages.\n"
1583 "       Message: Mailbox Status\n"
1584 "       Mailbox: <mailboxid>\n"
1585 "       Waiting: <count>\n"
1586 "\n";
1587
1588 static int action_mailboxstatus(struct mansession *s, struct message *m)
1589 {
1590         char *mailbox = astman_get_header(m, "Mailbox");
1591         int ret;
1592
1593         if (ast_strlen_zero(mailbox)) {
1594                 astman_send_error(s, m, "Mailbox not specified");
1595                 return 0;
1596         }
1597         ret = ast_app_has_voicemail(mailbox, NULL);
1598         astman_start_ack(s, m);
1599         astman_append(s, "Message: Mailbox Status\r\n"
1600                          "Mailbox: %s\r\n"
1601                          "Waiting: %d\r\n\r\n", mailbox, ret);
1602         return 0;
1603 }
1604
1605 static char mandescr_mailboxcount[] =
1606 "Description: Checks a voicemail account for new messages.\n"
1607 "Variables: (Names marked with * are required)\n"
1608 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1609 "       ActionID: Optional ActionID for message matching.\n"
1610 "Returns number of new and old messages.\n"
1611 "       Message: Mailbox Message Count\n"
1612 "       Mailbox: <mailboxid>\n"
1613 "       NewMessages: <count>\n"
1614 "       OldMessages: <count>\n"
1615 "\n";
1616 static int action_mailboxcount(struct mansession *s, struct message *m)
1617 {
1618         char *mailbox = astman_get_header(m, "Mailbox");
1619         int newmsgs = 0, oldmsgs = 0;
1620
1621         if (ast_strlen_zero(mailbox)) {
1622                 astman_send_error(s, m, "Mailbox not specified");
1623                 return 0;
1624         }
1625         ast_app_inboxcount(mailbox, &newmsgs, &oldmsgs);
1626         astman_start_ack(s, m);
1627         astman_append(s,   "Message: Mailbox Message Count\r\n"
1628                            "Mailbox: %s\r\n"
1629                            "NewMessages: %d\r\n"
1630                            "OldMessages: %d\r\n"
1631                            "\r\n",
1632                            mailbox, newmsgs, oldmsgs);
1633         return 0;
1634 }
1635
1636 static char mandescr_extensionstate[] =
1637 "Description: Report the extension state for given extension.\n"
1638 "  If the extension has a hint, will use devicestate to check\n"
1639 "  the status of the device connected to the extension.\n"
1640 "Variables: (Names marked with * are required)\n"
1641 "       *Exten: Extension to check state on\n"
1642 "       *Context: Context for extension\n"
1643 "       ActionId: Optional ID for this transaction\n"
1644 "Will return an \"Extension Status\" message.\n"
1645 "The response will include the hint for the extension and the status.\n";
1646
1647 static int action_extensionstate(struct mansession *s, struct message *m)
1648 {
1649         char *exten = astman_get_header(m, "Exten");
1650         char *context = astman_get_header(m, "Context");
1651         char hint[256] = "";
1652         int status;
1653         if (ast_strlen_zero(exten)) {
1654                 astman_send_error(s, m, "Extension not specified");
1655                 return 0;
1656         }
1657         if (ast_strlen_zero(context))
1658                 context = "default";
1659         status = ast_extension_state(NULL, context, exten);
1660         ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
1661         astman_start_ack(s, m);
1662         astman_append(s,   "Message: Extension Status\r\n"
1663                            "Exten: %s\r\n"
1664                            "Context: %s\r\n"
1665                            "Hint: %s\r\n"
1666                            "Status: %d\r\n\r\n",
1667                            exten, context, hint, status);
1668         return 0;
1669 }
1670
1671 static char mandescr_timeout[] =
1672 "Description: Hangup a channel after a certain time.\n"
1673 "Variables: (Names marked with * are required)\n"
1674 "       *Channel: Channel name to hangup\n"
1675 "       *Timeout: Maximum duration of the call (sec)\n"
1676 "Acknowledges set time with 'Timeout Set' message\n";
1677
1678 static int action_timeout(struct mansession *s, struct message *m)
1679 {
1680         struct ast_channel *c;
1681         char *name = astman_get_header(m, "Channel");
1682         int timeout = atoi(astman_get_header(m, "Timeout"));
1683
1684         if (ast_strlen_zero(name)) {
1685                 astman_send_error(s, m, "No channel specified");
1686                 return 0;
1687         }
1688         if (!timeout) {
1689                 astman_send_error(s, m, "No timeout specified");
1690                 return 0;
1691         }
1692         c = ast_get_channel_by_name_locked(name);
1693         if (!c) {
1694                 astman_send_error(s, m, "No such channel");
1695                 return 0;
1696         }
1697         ast_channel_setwhentohangup(c, timeout);
1698         ast_channel_unlock(c);
1699         astman_send_ack(s, m, "Timeout Set");
1700         return 0;
1701 }
1702
1703 static int process_events(struct mansession *s)
1704 {
1705         int ret = 0;
1706
1707         ast_mutex_lock(&s->__lock);
1708         if (s->fd > -1) {
1709                 struct eventqent *eqe;
1710
1711                 if (!s->eventq)
1712                         s->eventq = master_eventq;
1713                 while( (eqe = s->eventq->next) ) {
1714                         if ((s->authenticated && (s->readperm & eqe->category) == eqe->category) &&
1715                             ((s->send_events & eqe->category) == eqe->category)) {
1716                                 if (!ret && ast_carefulwrite(s->fd, eqe->eventdata, strlen(eqe->eventdata), s->writetimeout) < 0)
1717                                         ret = -1;
1718                         }
1719                         unref_event(s->eventq); /* XXX why not eqe ? */
1720                         s->eventq = eqe;
1721                 }
1722         }
1723         ast_mutex_unlock(&s->__lock);
1724         return ret;
1725 }
1726
1727 static char mandescr_userevent[] =
1728 "Description: Send an event to manager sessions.\n"
1729 "Variables: (Names marked with * are required)\n"
1730 "       *UserEvent: EventStringToSend\n"
1731 "       Header1: Content1\n"
1732 "       HeaderN: ContentN\n";
1733
1734 static int action_userevent(struct mansession *s, struct message *m)
1735 {
1736         char *event = astman_get_header(m, "UserEvent");
1737         char body[2048] = "";
1738         int x, bodylen = 0;
1739         for (x = 0; x < m->hdrcount; x++) {
1740                 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
1741                         ast_copy_string(body + bodylen, m->headers[x], sizeof(body) - bodylen - 3);
1742                         bodylen += strlen(m->headers[x]);
1743                         ast_copy_string(body + bodylen, "\r\n", 3);
1744                         bodylen += 2;
1745                 }
1746         }
1747
1748         manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, body);
1749         return 0;
1750 }
1751
1752 /*
1753  * Done with the action handlers here, we start with the code in charge
1754  * of accepting connections and serving them.
1755  * accept_thread() forks a new thread for each connection, session_do(),
1756  * which in turn calls get_input() repeatedly until a full message has
1757  * been accumulated, and then invokes process_message() to pass it to
1758  * the appropriate handler.
1759  */
1760
1761 /*
1762  * Process an AMI message, performing desired action.
1763  * Return 0 on success, -1 on error that require the session to be destroyed.
1764  */
1765 static int process_message(struct mansession *s, struct message *m)
1766 {
1767         char action[80] = "";
1768         int ret = 0;
1769         struct manager_action *tmp;
1770
1771         ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
1772         if (option_debug)
1773                 ast_log(LOG_DEBUG, "Manager received command '%s'\n", action);
1774
1775         if (ast_strlen_zero(action)) {
1776                 astman_send_error(s, m, "Missing action in request");
1777                 return 0;
1778         }
1779
1780         /* XXX should we protect the list navigation ? */
1781         for (tmp = first_action ; tmp; tmp = tmp->next) {
1782                 if (!strcasecmp(action, tmp->action)) {
1783                         if ((s->writeperm & tmp->authority) == tmp->authority) {
1784                                 if (tmp->func(s, m))    /* error */
1785                                         return -1;
1786                         } else {
1787                                 astman_send_error(s, m, "Permission denied");
1788                         }
1789                         break;
1790                 }
1791         }
1792         if (!tmp)
1793                 astman_send_error(s, m, "Invalid/unknown command");
1794         if (ret)
1795                 return ret;
1796         return process_events(s);
1797 }
1798
1799 /*
1800  * Read one full line (including crlf) from the manager socket.
1801  */
1802 static int get_input(struct mansession *s, char *output)
1803 {
1804         /* output must have at least sizeof(s->inbuf) space */
1805         struct pollfd fds[1];
1806         char *crlf;
1807
1808         if (s->inlen >= sizeof(s->inbuf) - 1) {
1809                 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->sin.sin_addr), s->inbuf);
1810                 s->inlen = 0;
1811         }
1812         s->inbuf[s->inlen] = '\0';      /* terminate, just in case */
1813         crlf = strstr(s->inbuf, "\r\n");
1814         if (crlf) {
1815                 /* Copy output data up to and including \r\n */
1816                 int x = crlf - s->inbuf + 2;
1817                 memcpy(output, s->inbuf, x);
1818                 output[x] = '\0'; /* Add trailing \0 */
1819                 /* Move remaining data back to the front */
1820                 memmove(s->inbuf, s->inbuf + x, s->inlen - x);
1821                 s->inlen -= x;
1822                 return 1;
1823         }
1824         fds[0].fd = s->fd;
1825         fds[0].events = POLLIN;
1826         for (;;) {
1827                 int res;
1828                 /* XXX do we really need this locking ? */
1829                 ast_mutex_lock(&s->__lock);
1830                 s->waiting_thread = pthread_self();
1831                 ast_mutex_unlock(&s->__lock);
1832
1833                 res = poll(fds, 1, -1);
1834
1835                 ast_mutex_lock(&s->__lock);
1836                 s->waiting_thread = AST_PTHREADT_NULL;
1837                 ast_mutex_unlock(&s->__lock);
1838
1839                 if (res == 0)   /* timeout ? */
1840                         continue;
1841                 if (res < 0) {
1842                         if (errno == EINTR)
1843                                 return 0;
1844                         ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
1845                         return -1;
1846                 }
1847                 ast_mutex_lock(&s->__lock);
1848                 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
1849                 if (res < 1)
1850                         res = -1;       /* error return */
1851                 else {
1852                         s->inlen += res;
1853                         s->inbuf[s->inlen] = '\0';
1854                         res = 0;
1855                 }
1856                 ast_mutex_unlock(&s->__lock);
1857                 return res;
1858         }
1859 }
1860
1861 /*! \brief The body of the individual manager session.
1862  */
1863 static void *session_do(void *data)
1864 {
1865         struct mansession *s = data;
1866         struct message m;       /* XXX watch out, this is 20k of memory! */
1867
1868         ast_mutex_lock(&s->__lock);
1869         astman_append(s, "Asterisk Call Manager/1.0\r\n");      /* welcome prompt */
1870         ast_mutex_unlock(&s->__lock);
1871         memset(&m, 0, sizeof(m));
1872         for (;;) {
1873                 char *buf = m.headers[m.hdrcount];
1874                 int res = get_input(s, buf);
1875                 if (res < 0)    /* error */
1876                         break;
1877                 if (res > 0) {  /* got one line */
1878                         res = strlen(buf);
1879                         if (res < 2)
1880                                 continue;
1881                         /* Strip trailing \r\n (which must be there) */
1882                         buf[res - 2] = '\0';
1883                         if (ast_strlen_zero(buf)) {     /* empty line, terminator */
1884                                 if (process_message(s, &m))
1885                                         break;
1886                                 memset(&m, 0, sizeof(m));
1887                         } else if (m.hdrcount < AST_MAX_MANHEADERS - 1)
1888                                 m.hdrcount++;
1889                 } else if (s->eventq->next) {
1890                         if (process_events(s))
1891                                 break;
1892                 }
1893         }
1894         /* session is over, explain why and terminate */
1895         if (s->authenticated) {
1896                 if (option_verbose > 1) {
1897                         if (displayconnects)
1898                                 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
1899                 }
1900                 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
1901         } else {
1902                 if (option_verbose > 1) {
1903                         if (displayconnects)
1904                                 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
1905                 }
1906                 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
1907         }
1908         destroy_session(s);
1909         return NULL;
1910 }
1911
1912 /*! \brief The thread accepting connections on the manager interface port.
1913  * As a side effect, it purges stale sessions, one per each iteration,
1914  * which is at least every 5 seconds.
1915  */
1916 static void *accept_thread(void *ignore)
1917 {
1918         pthread_attr_t attr;
1919
1920         pthread_attr_init(&attr);
1921         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1922
1923         for (;;) {
1924                 struct mansession *s;
1925                 time_t now = time(NULL);
1926                 int as;
1927                 struct sockaddr_in sin;
1928                 socklen_t sinlen;
1929                 struct protoent *p;
1930                 int flags;
1931                 struct pollfd pfds[1];
1932
1933                 AST_LIST_LOCK(&sessions);
1934                 AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, s, list) {
1935                         if (s->sessiontimeout && (now > s->sessiontimeout) && !s->inuse) {
1936                                 ast_verbose("destroy session[2] %lx now %lu to %lu\n",
1937                                         s->managerid, (unsigned long)now, (unsigned long)s->sessiontimeout);
1938                                 AST_LIST_REMOVE_CURRENT(&sessions, list);
1939                                 ast_atomic_fetchadd_int(&num_sessions, -1);
1940                                 if (s->authenticated && (option_verbose > 1) && displayconnects) {
1941                                         ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' timed out from %s\n",
1942                                                 s->username, ast_inet_ntoa(s->sin.sin_addr));
1943                                 }
1944                                 free_session(s);
1945                                 break;
1946                         }
1947                 }
1948                 AST_LIST_TRAVERSE_SAFE_END
1949                 /* Purge master event queue of old, unused events, but make sure we
1950                    always keep at least one in the queue */
1951                 /* XXX why do we need one entry in the queue ? */
1952                 while (master_eventq->next && !master_eventq->usecount) {
1953                         struct eventqent *eqe = master_eventq;
1954                         master_eventq = master_eventq->next;
1955                         free(eqe);
1956                 }
1957                 AST_LIST_UNLOCK(&sessions);
1958
1959                 sinlen = sizeof(sin);
1960                 pfds[0].fd = asock;
1961                 pfds[0].events = POLLIN;
1962                 /* Wait for something to happen, but timeout every few seconds so
1963                    we can ditch any old manager sessions */
1964                 if (poll(pfds, 1, 5000) < 1)
1965                         continue;
1966                 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
1967                 if (as < 0) {
1968                         ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
1969                         continue;
1970                 }
1971                 p = getprotobyname("tcp");
1972                 if (p) {
1973                         int arg = 1;
1974                         if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
1975                                 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
1976                         }
1977                 }
1978                 s = ast_calloc(1, sizeof(*s));  /* allocate a new record */
1979                 if (!s) {
1980                         close(as);
1981                         continue;
1982                 }
1983
1984
1985                 s->sin = sin;
1986                 s->writetimeout = 100;
1987                 s->waiting_thread = AST_PTHREADT_NULL;
1988
1989                 flags = fcntl(as, F_GETFL);
1990                 if (!block_sockets) /* For safety, make sure socket is non-blocking */
1991                         flags |= O_NONBLOCK;
1992                 else
1993                         flags &= ~O_NONBLOCK;
1994                 fcntl(as, F_SETFL, flags);
1995
1996                 ast_mutex_init(&s->__lock);
1997                 s->fd = as;
1998                 s->send_events = -1;
1999
2000                 ast_atomic_fetchadd_int(&num_sessions, 1);
2001                 AST_LIST_LOCK(&sessions);
2002                 AST_LIST_INSERT_HEAD(&sessions, s, list);
2003                 /* Find the last place in the master event queue and hook ourselves
2004                    in there */
2005                 s->eventq = master_eventq;
2006                 while(s->eventq->next)
2007                         s->eventq = s->eventq->next;
2008                 AST_LIST_UNLOCK(&sessions);
2009                 ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
2010                 if (ast_pthread_create_background(&s->ms_t, &attr, session_do, s))
2011                         destroy_session(s);
2012         }
2013         pthread_attr_destroy(&attr);
2014         return NULL;
2015 }
2016
2017 /*
2018  * events are appended to a queue from where they
2019  * can be dispatched to clients.
2020  */
2021 static int append_event(const char *str, int category)
2022 {
2023         struct eventqent *prev = NULL;
2024         struct eventqent *tmp = ast_malloc(sizeof(*tmp) + strlen(str));
2025
2026         if (!tmp)
2027                 return -1;
2028
2029         /* need to init all fields, because ast_malloc() does not */
2030         tmp->next = NULL;
2031         tmp->category = category;
2032         strcpy(tmp->eventdata, str);
2033
2034         if (master_eventq) {
2035                 prev = master_eventq;
2036                 while (prev->next)
2037                         prev = prev->next;
2038                 prev->next = tmp;
2039         } else {
2040                 master_eventq = tmp;
2041         }
2042
2043         tmp->usecount = num_sessions;
2044
2045         return 0;
2046 }
2047
2048 /*! \brief  manager_event: Send AMI event to client */
2049 int manager_event(int category, const char *event, const char *fmt, ...)
2050 {
2051         struct mansession *s;
2052         char auth[80];
2053         va_list ap;
2054         struct timeval now;
2055         struct ast_dynamic_str *buf;
2056
2057         /* Abort if there aren't any manager sessions */
2058         if (!num_sessions)
2059                 return 0;
2060
2061         if (!(buf = ast_dynamic_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE)))
2062                 return -1;
2063
2064         ast_dynamic_str_thread_set(&buf, 0, &manager_event_buf,
2065                         "Event: %s\r\nPrivilege: %s\r\n",
2066                          event, authority_to_str(category, auth, sizeof(auth)));
2067
2068         if (timestampevents) {
2069                 now = ast_tvnow();
2070                 ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf,
2071                                 "Timestamp: %ld.%06lu\r\n",
2072                                  now.tv_sec, (unsigned long) now.tv_usec);
2073         }
2074
2075         va_start(ap, fmt);
2076         ast_dynamic_str_thread_append_va(&buf, 0, &manager_event_buf, fmt, ap);
2077         va_end(ap);
2078
2079         ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf, "\r\n");
2080
2081         /* Append event to master list and wake up any sleeping sessions */
2082         AST_LIST_LOCK(&sessions);
2083         append_event(buf->str, category);
2084         AST_LIST_TRAVERSE(&sessions, s, list) {
2085                 ast_mutex_lock(&s->__lock);
2086                 if (s->waiting_thread != AST_PTHREADT_NULL)
2087                         pthread_kill(s->waiting_thread, SIGURG);
2088                 ast_mutex_unlock(&s->__lock);
2089         }
2090         AST_LIST_UNLOCK(&sessions);
2091
2092         return 0;
2093 }
2094
2095 /*
2096  * support functions to register/unregister AMI action handlers,
2097  */
2098 int ast_manager_unregister(char *action)
2099 {
2100         struct manager_action *cur = first_action, *prev = first_action;
2101
2102         ast_mutex_lock(&actionlock);
2103         for (cur = first_action, prev = NULL; cur; prev = cur, cur = cur->next) {
2104                 if (!strcasecmp(action, cur->action)) {
2105                         if (prev)
2106                                 prev->next = cur->next;
2107                         else
2108                                 first_action = cur->next;
2109                         free(cur);
2110                         if (option_verbose > 1)
2111                                 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
2112                         break;
2113                 }
2114         }
2115         ast_mutex_unlock(&actionlock);
2116         return 0;
2117 }
2118
2119 static int manager_state_cb(char *context, char *exten, int state, void *data)
2120 {
2121         /* Notify managers of change */
2122         manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
2123         return 0;
2124 }
2125
2126 static int ast_manager_register_struct(struct manager_action *act)
2127 {
2128         struct manager_action *cur, *prev = NULL;
2129         int ret;
2130
2131         ast_mutex_lock(&actionlock);
2132         for (cur = first_action; cur; prev = cur, cur = cur->next) {
2133                 ret = strcasecmp(cur->action, act->action);
2134                 if (ret == 0) {
2135                         ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
2136                         ast_mutex_unlock(&actionlock);
2137                         return -1;
2138                 }
2139                 if (ret > 0)    /* Insert these alphabetically */
2140                         break;
2141         }
2142         if (prev)
2143                 prev->next = act;
2144         else
2145                 first_action = act;
2146         act->next = cur;
2147
2148         if (option_verbose > 1)
2149                 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
2150         ast_mutex_unlock(&actionlock);
2151         return 0;
2152 }
2153
2154 /*! \brief register a new command with manager, including online help. This is
2155         the preferred way to register a manager command */
2156 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, struct message *m), const char *synopsis, const char *description)
2157 {
2158         struct manager_action *cur;
2159
2160         cur = ast_malloc(sizeof(*cur));
2161         if (!cur)
2162                 return -1;
2163
2164         cur->action = action;
2165         cur->authority = auth;
2166         cur->func = func;
2167         cur->synopsis = synopsis;
2168         cur->description = description;
2169         cur->next = NULL;
2170
2171         ast_manager_register_struct(cur);
2172
2173         return 0;
2174 }
2175 /*! @}
2176  END Doxygen group */
2177
2178 /*
2179  * The following are support functions for AMI-over-http.
2180  * The common entry point is generic_http_callback(),
2181  * which extracts HTTP header and URI fields and reformats
2182  * them into AMI messages, locates a proper session
2183  * (using the mansession_id Cookie or GET variable),
2184  * and calls process_message() as for regular AMI clients.
2185  * When done, the output (which goes to a temporary file)
2186  * is read back into a buffer and reformatted as desired,
2187  * then fed back to the client over the original socket.
2188  */
2189
2190 enum output_format {
2191         FORMAT_RAW,
2192         FORMAT_HTML,
2193         FORMAT_XML,
2194 };
2195
2196 static char *contenttype[] = {
2197         [FORMAT_RAW] = "plain",
2198         [FORMAT_HTML] = "html",
2199         [FORMAT_XML] =  "xml",
2200 };
2201
2202 /* locate an http session in the list using the cookie as a key */
2203 static struct mansession *find_session(unsigned long ident)
2204 {
2205         struct mansession *s;
2206
2207         if (ident == 0)
2208                 return NULL;
2209
2210         AST_LIST_LOCK(&sessions);
2211         AST_LIST_TRAVERSE(&sessions, s, list) {
2212                 ast_mutex_lock(&s->__lock);
2213                 if (s->sessiontimeout && (s->managerid == ident) && !s->needdestroy) {
2214                         ast_atomic_fetchadd_int(&s->inuse, 1);
2215                         break;
2216                 }
2217                 ast_mutex_unlock(&s->__lock);
2218         }
2219         AST_LIST_UNLOCK(&sessions);
2220
2221         return s;
2222 }
2223
2224 static void vars2msg(struct message *m, struct ast_variable *vars)
2225 {
2226         int x;
2227         for (x = 0; vars && (x < AST_MAX_MANHEADERS); x++, vars = vars->next) {
2228                 if (!vars)
2229                         break;
2230                 m->hdrcount = x + 1;
2231                 snprintf(m->headers[x], sizeof(m->headers[x]), "%s: %s", vars->name, vars->value);
2232         }
2233 }
2234
2235 /*
2236  * convert to xml with various conversion:
2237  * mode & 1     -> lowercase;
2238  * mode & 2     -> replace non-alphanumeric chars with underscore
2239  */
2240 static void xml_copy_escape(char **dst, size_t *maxlen, const char *src, int mode)
2241 {
2242         for ( ; *src && *maxlen > 6; src++) {
2243                 if ( (mode & 2) && !isalnum(*src)) {
2244                         *(*dst)++ = '_';
2245                         (*maxlen)--;
2246                         continue;
2247                 }
2248                 switch (*src) {
2249                 case '<':
2250                         strcpy(*dst, "&lt;");
2251                         (*dst) += 4;
2252                         *maxlen -= 4;
2253                         break;
2254                 case '>':
2255                         strcpy(*dst, "&gt;");
2256                         (*dst) += 4;
2257                         *maxlen -= 4;
2258                         break;
2259                 case '\"':
2260                         strcpy(*dst, "&quot;");
2261                         (*dst) += 6;
2262                         *maxlen -= 6;
2263                         break;
2264                 case '\'':
2265                         strcpy(*dst, "&apos;");
2266                         (*dst) += 6;
2267                         *maxlen -= 6;
2268                         break;
2269                 case '&':
2270                         strcpy(*dst, "&amp;");
2271                         (*dst) += 5;
2272                         *maxlen -= 5;
2273                         break;
2274
2275                 default:
2276                         *(*dst)++ = mode ? tolower(*src) : *src;
2277                         (*maxlen)--;
2278                 }
2279         }
2280 }
2281
2282 /*! \brief Convert the input into XML or HTML.
2283  * The input is supposed to be a sequence of lines of the form
2284  *      Name: value
2285  * optionally followed by a blob of unformatted text.
2286  * A blank line is a section separator. Basically, this is a
2287  * mixture of the format of Manager Interface and CLI commands.
2288  * The unformatted text is considered as a single value of a field
2289  * named 'Opaque-data'.
2290  *
2291  * At the moment the output format is the following (but it may
2292  * change depending on future requirements so don't count too
2293  * much on it when writing applications):
2294  *
2295  * General: the unformatted text is used as a value of
2296  * XML output:  to be completed
2297  *   Each section is within <response type="object" id="xxx">
2298  *   where xxx is taken from ajaxdest variable or defaults to unknown
2299  *   Each row is reported as an attribute Name="value" of an XML
2300  *   entity named from the variable ajaxobjtype, default to "generic"
2301  *
2302  * HTML output:
2303  *   each Name-value pair is output as a single row of a two-column table.
2304  *   Sections (blank lines in the input) are separated by a <HR>
2305  *
2306  */
2307 static char *xml_translate(char *in, struct ast_variable *vars, enum output_format format)
2308 {
2309         struct ast_variable *v;
2310         char *dest = NULL;
2311         char *out, *tmp, *var, *val;
2312         char *objtype = NULL;
2313         int colons = 0;
2314         int breaks = 0;
2315         size_t len;
2316         int in_data = 0;        /* parsing data */
2317         int escaped = 0;
2318         int inobj = 0;
2319         int x;
2320         int xml = (format == FORMAT_XML);
2321
2322         for (v = vars; v; v = v->next) {
2323                 if (!dest && !strcasecmp(v->name, "ajaxdest"))
2324                         dest = v->value;
2325                 else if (!objtype && !strcasecmp(v->name, "ajaxobjtype"))
2326                         objtype = v->value;
2327         }
2328         if (!dest)
2329                 dest = "unknown";
2330         if (!objtype)
2331                 objtype = "generic";
2332
2333         /* determine how large is the response.
2334          * This is a heuristic - counting colons (for headers),
2335          * newlines (for extra arguments), and escaped chars.
2336          * XXX needs to be checked carefully for overflows.
2337          * Even better, use some code that allows extensible strings.
2338          */
2339         for (x = 0; in[x]; x++) {
2340                 if (in[x] == ':')
2341                         colons++;
2342                 else if (in[x] == '\n')
2343                         breaks++;
2344                 else if (strchr("&\"<>", in[x]))
2345                         escaped++;
2346         }
2347         len = (size_t) (strlen(in) + colons * 5 + breaks * (40 + strlen(dest) + strlen(objtype)) + escaped * 10); /* foo="bar", "<response type=\"object\" id=\"dest\"", "&amp;" */
2348         out = ast_malloc(len);
2349         if (!out)
2350                 return NULL;
2351         tmp = out;
2352         /* we want to stop when we find an empty line */
2353         while (in && *in) {
2354                 val = strsep(&in, "\r\n");      /* mark start and end of line */
2355                 if (in && *in == '\n')          /* remove trailing \n if any */
2356                         in++;
2357                 ast_trim_blanks(val);
2358                 ast_verbose("inobj %d in_data %d line <%s>\n", inobj, in_data, val);
2359                 if (ast_strlen_zero(val)) {
2360                         if (in_data) { /* close data */
2361                                 ast_build_string(&tmp, &len, xml ? "'" : "</td></tr>\n");
2362                                 in_data = 0;
2363                         }
2364                         ast_build_string(&tmp, &len, xml ? " /></response>\n" :
2365                                 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
2366                         inobj = 0;
2367                         continue;
2368                 }
2369                 /* we expect Name: value lines */
2370                 if (in_data) {
2371                         var = NULL;
2372                 } else {
2373                         var = strsep(&val, ":");
2374                         if (val) {      /* found the field name */
2375                                 val = ast_skip_blanks(val);
2376                                 ast_trim_blanks(var);
2377                         } else {                /* field name not found, move to opaque mode */
2378                                 val = var;
2379                                 var = "Opaque-data";
2380                         }
2381                 }
2382                 if (!inobj) {
2383                         if (xml)
2384                                 ast_build_string(&tmp, &len, "<response type='object' id='%s'><%s", dest, objtype);
2385                         else
2386                                 ast_build_string(&tmp, &len, "<body>\n");
2387                         inobj = 1;
2388                 }
2389                 if (!in_data) { /* build appropriate line start */
2390                         ast_build_string(&tmp, &len, xml ? " " : "<tr><td>");
2391                         xml_copy_escape(&tmp, &len, var, xml ? 1 | 2 : 0);
2392                         ast_build_string(&tmp, &len, xml ? "='" : "</td><td>");
2393                         if (!strcmp(var, "Opaque-data"))
2394                                 in_data = 1;
2395                 }
2396                 xml_copy_escape(&tmp, &len, val, 0);    /* data field */
2397                 if (!in_data)
2398                         ast_build_string(&tmp, &len, xml ? "'" : "</td></tr>\n");
2399                 else
2400                         ast_build_string(&tmp, &len, xml ? "\n" : "<br>\n");
2401         }
2402         if (inobj)
2403                 ast_build_string(&tmp, &len, xml ? " /></response>\n" :
2404                         "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
2405         return out;
2406 }
2407
2408 static char *generic_http_callback(enum output_format format,
2409         struct sockaddr_in *requestor, const char *uri,
2410         struct ast_variable *params, int *status,
2411         char **title, int *contentlength)
2412 {
2413         struct mansession *s = NULL;
2414         unsigned long ident = 0;
2415         char workspace[1024];
2416         size_t len = sizeof(workspace);
2417         int blastaway = 0;
2418         char *c = workspace;
2419         char *retval = NULL;
2420         struct message m;
2421         struct ast_variable *v;
2422         char template[] = "/tmp/ast-http-XXXXXX";       /* template for temporary file */
2423
2424         for (v = params; v; v = v->next) {
2425                 if (!strcasecmp(v->name, "mansession_id")) {
2426                         sscanf(v->value, "%lx", &ident);
2427                         break;
2428                 }
2429         }
2430
2431         if (!(s = find_session(ident))) {
2432                 /* Create new session.
2433                  * While it is not in the list we don't need any locking
2434                  */
2435                 if (!(s = ast_calloc(1, sizeof(*s)))) {
2436                         *status = 500;
2437                         goto generic_callback_out;
2438                 }
2439                 s->sin = *requestor;
2440                 s->fd = -1;
2441                 s->waiting_thread = AST_PTHREADT_NULL;
2442                 s->send_events = 0;
2443                 ast_mutex_init(&s->__lock);
2444                 ast_mutex_lock(&s->__lock);
2445                 s->inuse = 1;
2446                 s->managerid = rand() | 1;      /* make sure it is non-zero */
2447                 AST_LIST_LOCK(&sessions);
2448                 AST_LIST_INSERT_HEAD(&sessions, s, list);
2449                 /* Hook into the last spot in the event queue */
2450                 s->eventq = master_eventq;
2451                 while (s->eventq->next)
2452                         s->eventq = s->eventq->next;
2453                 AST_LIST_UNLOCK(&sessions);
2454                 ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
2455                 ast_atomic_fetchadd_int(&num_sessions, 1);
2456         }
2457
2458         ast_mutex_unlock(&s->__lock);
2459         memset(&m, 0, sizeof(m));
2460         {
2461                 char tmp[80];
2462                 char cookie[128];
2463
2464                 ast_build_string(&c, &len, "Content-type: text/%s\r\n", contenttype[format]);
2465                 sprintf(tmp, "%08lx", s->managerid);
2466                 ast_build_string(&c, &len, "%s\r\n", ast_http_setcookie("mansession_id", tmp, httptimeout, cookie, sizeof(cookie)));
2467         }
2468
2469         if (format == FORMAT_HTML)
2470                 ast_build_string(&c, &len, "<title>Asterisk&trade; Manager Test Interface</title>");
2471         vars2msg(&m, params);
2472
2473         if (format == FORMAT_XML) {
2474                 ast_build_string(&c, &len, "<ajax-response>\n");
2475         } else if (format == FORMAT_HTML) {
2476
2477 #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
2478 #define TEST_STRING \
2479         "<form action=\"manager\">action: <input name=\"action\"> cmd <input name=\"command\"><br> \
2480         user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br> \
2481         <input type=\"submit\"></form>"
2482
2483                 ast_build_string(&c, &len, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
2484                 ast_build_string(&c, &len, ROW_FMT, "<h1>Manager Tester</h1>");
2485                 ast_build_string(&c, &len, ROW_FMT, TEST_STRING);
2486         }
2487
2488         s->fd = mkstemp(template);      /* create a temporary file for command output */
2489
2490         if (process_message(s, &m)) {
2491                 if (s->authenticated) {
2492                         if (option_verbose > 1) {
2493                                 if (displayconnects)
2494                                         ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
2495                         }
2496                         ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
2497                 } else {
2498                         if (option_verbose > 1) {
2499                                 if (displayconnects)
2500                                         ast_verbose(VERBOSE_PREFIX_2 "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
2501                         }
2502                         ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
2503                 }
2504                 s->needdestroy = 1;
2505         }
2506         if (s->fd > -1) {       /* have temporary output */
2507                 char *buf;
2508                 off_t len = lseek(s->fd, 0, SEEK_END);  /* how many chars available */
2509
2510                 if (len > 0 && (buf = ast_calloc(1, len+1))) {
2511                         if (!s->outputstr)
2512                                 s->outputstr = ast_calloc(1, sizeof(*s->outputstr));
2513                         if (s->outputstr) {
2514                                 lseek(s->fd, 0, SEEK_SET);
2515                                 read(s->fd, buf, len);
2516                                 ast_verbose("--- fd %d has %d bytes ---\n%s\n---\n", s->fd, (int)len, buf);
2517                                 ast_dynamic_str_append(&s->outputstr, 0, "%s", buf);
2518                         }
2519                         free(buf);
2520                 }
2521                 close(s->fd);
2522                 s->fd = -1;
2523                 unlink(template);
2524         }
2525
2526         if (s->outputstr) {
2527                 char *tmp;
2528                 if (format == FORMAT_XML || format == FORMAT_HTML)
2529                         tmp = xml_translate(s->outputstr->str, params, format);
2530                 else
2531                         tmp = s->outputstr->str;
2532                 if (tmp) {
2533                         retval = malloc(strlen(workspace) + strlen(tmp) + 128);
2534                         if (retval) {
2535                                 strcpy(retval, workspace);
2536                                 strcpy(retval + strlen(retval), tmp);
2537                                 c = retval + strlen(retval);
2538                                 len = 120;
2539                         }
2540                 }
2541                 if (tmp != s->outputstr->str)
2542                         free(tmp);
2543                 free(s->outputstr);
2544                 s->outputstr = NULL;
2545         }
2546         /* Still okay because c would safely be pointing to workspace even
2547            if retval failed to allocate above */
2548         if (format == FORMAT_XML) {
2549                 ast_build_string(&c, &len, "</ajax-response>\n");
2550         } else if (format == FORMAT_HTML)
2551                 ast_build_string(&c, &len, "</table></body>\r\n");
2552
2553         ast_mutex_lock(&s->__lock);
2554         /* Reset HTTP timeout.  If we're not authenticated, keep it extremely short */
2555         s->sessiontimeout = time(NULL) + ((s->authenticated || httptimeout < 5) ? httptimeout : 5);
2556         ast_verbose("die in %d seconds\n",
2557                 (int)(s->sessiontimeout - time(NULL)) );
2558         if (s->needdestroy) {
2559                 if (s->inuse == 1) {
2560                         if (option_debug)
2561                                 ast_log(LOG_DEBUG, "Need destroy, doing it now!\n");
2562                         blastaway = 1;
2563                 } else {
2564                         if (option_debug)
2565                                 ast_log(LOG_DEBUG, "Need destroy, but can't do it yet!\n");
2566                         if (s->waiting_thread != AST_PTHREADT_NULL)
2567                                 pthread_kill(s->waiting_thread, SIGURG);
2568                         s->inuse--;
2569                 }
2570         } else
2571                 s->inuse--;
2572         ast_mutex_unlock(&s->__lock);
2573
2574         if (blastaway)
2575                 destroy_session(s);
2576 generic_callback_out:
2577         if (*status != 200)
2578                 return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n");
2579         return retval;
2580 }
2581
2582 static char *manager_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
2583 {
2584         return generic_http_callback(FORMAT_HTML, requestor, uri, params, status, title, contentlength);
2585 }
2586
2587 static char *mxml_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
2588 {
2589         return generic_http_callback(FORMAT_XML, requestor, uri, params, status, title, contentlength);
2590 }
2591
2592 static char *rawman_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
2593 {
2594         return generic_http_callback(FORMAT_RAW, requestor, uri, params, status, title, contentlength);
2595 }
2596
2597 struct ast_http_uri rawmanuri = {
2598         .description = "Raw HTTP Manager Event Interface",
2599         .uri = "rawman",
2600         .has_subtree = 0,
2601         .callback = rawman_http_callback,
2602 };
2603
2604 struct ast_http_uri manageruri = {
2605         .description = "HTML Manager Event Interface",
2606         .uri = "manager",
2607         .has_subtree = 0,
2608         .callback = manager_http_callback,
2609 };
2610
2611 struct ast_http_uri managerxmluri = {
2612         .description = "XML Manager Event Interface",
2613         .uri = "mxml",
2614         .has_subtree = 0,
2615         .callback = mxml_http_callback,
2616 };
2617
2618 static int registered = 0;
2619 static int webregged = 0;
2620
2621 int init_manager(void)
2622 {
2623         struct ast_config *cfg = NULL;
2624         const char *val;
2625         char *cat = NULL;
2626         int oldportno = portno;
2627         static struct sockaddr_in ba;
2628         int x = 1;
2629         int flags;
2630         int webenabled = 0;
2631         int newhttptimeout = 60;
2632         struct ast_manager_user *user = NULL;
2633
2634         if (!registered) {
2635                 /* Register default actions */
2636                 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
2637                 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
2638                 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
2639                 ast_manager_register2("Login", 0, action_login, "Login Manager", NULL);
2640                 ast_manager_register2("Challenge", 0, action_challenge, "Generate Challenge for MD5 Auth", NULL);
2641                 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
2642                 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
2643                 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
2644                 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
2645                 ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
2646                 ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
2647                 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
2648                 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
2649                 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
2650                 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
2651                 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
2652                 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
2653                 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
2654                 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
2655                 ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent);
2656                 ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent);
2657
2658                 ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry));
2659                 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
2660                 registered = 1;
2661                 /* Append placeholder event so master_eventq never runs dry */
2662                 append_event("Event: Placeholder\r\n\r\n", 0);
2663         }
2664         portno = DEFAULT_MANAGER_PORT;
2665         displayconnects = 1;
2666         cfg = ast_config_load("manager.conf");
2667         if (!cfg) {
2668                 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf.  Call management disabled.\n");
2669                 return 0;
2670         }
2671         val = ast_variable_retrieve(cfg, "general", "enabled");
2672         if (val)
2673                 enabled = ast_true(val);
2674
2675         val = ast_variable_retrieve(cfg, "general", "block-sockets");
2676         if (val)
2677                 block_sockets = ast_true(val);
2678
2679         val = ast_variable_retrieve(cfg, "general", "webenabled");
2680         if (val)
2681                 webenabled = ast_true(val);
2682
2683         if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
2684                 if (sscanf(val, "%d", &portno) != 1) {
2685                         ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
2686                         portno = DEFAULT_MANAGER_PORT;
2687                 }
2688         }
2689
2690         if ((val = ast_variable_retrieve(cfg, "general", "displayconnects")))
2691                 displayconnects = ast_true(val);
2692
2693         if ((val = ast_variable_retrieve(cfg, "general", "timestampevents")))
2694                 timestampevents = ast_true(val);
2695
2696         if ((val = ast_variable_retrieve(cfg, "general", "httptimeout")))
2697                 newhttptimeout = atoi(val);
2698
2699         memset(&ba, 0, sizeof(ba));
2700         ba.sin_family = AF_INET;
2701         ba.sin_port = htons(portno);
2702
2703         if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
2704                 if (!inet_aton(val, &ba.sin_addr)) {
2705                         ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
2706                         memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
2707                 }
2708         }
2709
2710
2711         if ((asock > -1) && ((portno != oldportno) || !enabled)) {
2712 #if 0
2713                 /* Can't be done yet */
2714                 close(asock);
2715                 asock = -1;
2716 #else
2717                 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
2718 #endif
2719         }
2720
2721         AST_LIST_LOCK(&users);
2722
2723         while ((cat = ast_category_browse(cfg, cat))) {
2724                 struct ast_variable *var = NULL;
2725
2726                 if (!strcasecmp(cat, "general"))
2727                         continue;
2728
2729                 /* Look for an existing entry, if none found - create one and add it to the list */
2730                 if (!(user = get_manager_by_name_locked(cat))) {
2731                         if (!(user = ast_calloc(1, sizeof(*user))))
2732                                 break;
2733                         /* Copy name over */
2734                         ast_copy_string(user->username, cat, sizeof(user->username));
2735                         /* Insert into list */
2736                         AST_LIST_INSERT_TAIL(&users, user, list);
2737                 }
2738
2739                 /* Make sure we keep this user and don't destroy it during cleanup */
2740                 user->keep = 1;
2741
2742                 var = ast_variable_browse(cfg, cat);
2743                 while (var) {
2744                         if (!strcasecmp(var->name, "secret")) {
2745                                 if (user->secret)
2746                                         free(user->secret);
2747                                 user->secret = ast_strdup(var->value);
2748                         } else if (!strcasecmp(var->name, "deny") ) {
2749                                 if (user->deny)
2750                                         free(user->deny);
2751                                 user->deny = ast_strdup(var->value);
2752                         } else if (!strcasecmp(var->name, "permit") ) {
2753                                 if (user->permit)
2754                                         free(user->permit);
2755                                 user->permit = ast_strdup(var->value);
2756                         }  else if (!strcasecmp(var->name, "read") ) {
2757                                 if (user->read)
2758                                         free(user->read);
2759                                 user->read = ast_strdup(var->value);
2760                         }  else if (!strcasecmp(var->name, "write") ) {
2761                                 if (user->write)
2762                                         free(user->write);
2763                                 user->write = ast_strdup(var->value);
2764                         }  else if (!strcasecmp(var->name, "displayconnects") )
2765                                 user->displayconnects = ast_true(var->value);
2766                         else {
2767                                 if (option_debug)
2768                                         ast_log(LOG_DEBUG, "%s is an unknown option.\n", var->name);
2769                         }
2770                         var = var->next;
2771                 }
2772         }
2773
2774         /* Perform cleanup - essentially prune out old users that no longer exist */
2775         AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
2776                 if (user->keep) {       /* valid record. clear flag for the next round */
2777                         user->keep = 0;
2778                         continue;
2779                 }
2780                 /* We do not need to keep this user so take them out of the list */
2781                 AST_LIST_REMOVE_CURRENT(&users, list);
2782                 /* Free their memory now */
2783                 if (user->secret)
2784                         free(user->secret);
2785                 if (user->deny)
2786                         free(user->deny);
2787                 if (user->permit)
2788                         free(user->permit);
2789                 if (user->read)
2790                         free(user->read);
2791                 if (user->write)
2792                         free(user->write);
2793                 free(user);
2794         }
2795         AST_LIST_TRAVERSE_SAFE_END
2796
2797         AST_LIST_UNLOCK(&users);
2798
2799         ast_config_destroy(cfg);
2800
2801         if (webenabled && enabled) {
2802                 if (!webregged) {
2803                         ast_http_uri_link(&rawmanuri);
2804                         ast_http_uri_link(&manageruri);
2805                         ast_http_uri_link(&managerxmluri);
2806                         webregged = 1;
2807                 }
2808         } else {
2809                 if (webregged) {
2810                         ast_http_uri_unlink(&rawmanuri);
2811                         ast_http_uri_unlink(&manageruri);
2812                         ast_http_uri_unlink(&managerxmluri);
2813                         webregged = 0;
2814                 }
2815         }
2816
2817         if (newhttptimeout > 0)
2818                 httptimeout = newhttptimeout;
2819
2820         /* If not enabled, do nothing */
2821         if (!enabled)
2822                 return 0;
2823
2824         if (asock < 0) {
2825                 asock = socket(AF_INET, SOCK_STREAM, 0);
2826                 if (asock < 0) {
2827                         ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
2828                         return -1;
2829                 }
2830                 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
2831                 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
2832                         ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
2833                         close(asock);
2834                         asock = -1;
2835                         return -1;
2836                 }
2837                 if (listen(asock, 2)) {
2838                         ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
2839                         close(asock);
2840                         asock = -1;
2841                         return -1;
2842                 }
2843                 flags = fcntl(asock, F_GETFL);
2844                 fcntl(asock, F_SETFL, flags | O_NONBLOCK);
2845                 if (option_verbose)
2846                         ast_verbose("Asterisk Management interface listening on port %d\n", portno);
2847                 ast_pthread_create_background(&accept_thread_ptr, NULL, accept_thread, NULL);
2848         }
2849         return 0;
2850 }
2851
2852 int reload_manager(void)
2853 {
2854         manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
2855         return init_manager();
2856 }