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