Remove rarely-used event_log/LOG_EVENT support
[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  * \extref OpenSSL http://www.openssl.org - for AMI/SSL
26  *
27  * At the moment this file contains a number of functions, namely:
28  *
29  * - data structures storing AMI state
30  * - AMI-related API functions, used by internal asterisk components
31  * - handlers for AMI-related CLI functions
32  * - handlers for AMI functions (available through the AMI socket)
33  * - the code for the main AMI listener thread and individual session threads
34  * - the http handlers invoked for AMI-over-HTTP by the threads in main/http.c
35  *
36  * \ref amiconf
37  */
38
39 /*! \addtogroup Group_AMI AMI functions
40 */
41 /*! @{
42  Doxygen group */
43
44 #include "asterisk.h"
45
46 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
47
48 #include "asterisk/_private.h"
49 #include "asterisk/paths.h"     /* use various ast_config_AST_* */
50 #include <ctype.h>
51 #include <sys/time.h>
52 #include <signal.h>
53 #include <sys/mman.h>
54
55 #include "asterisk/channel.h"
56 #include "asterisk/file.h"
57 #include "asterisk/manager.h"
58 #include "asterisk/module.h"
59 #include "asterisk/config.h"
60 #include "asterisk/callerid.h"
61 #include "asterisk/lock.h"
62 #include "asterisk/cli.h"
63 #include "asterisk/app.h"
64 #include "asterisk/pbx.h"
65 #include "asterisk/md5.h"
66 #include "asterisk/acl.h"
67 #include "asterisk/utils.h"
68 #include "asterisk/tcptls.h"
69 #include "asterisk/http.h"
70 #include "asterisk/ast_version.h"
71 #include "asterisk/threadstorage.h"
72 #include "asterisk/linkedlists.h"
73 #include "asterisk/version.h"
74 #include "asterisk/term.h"
75 #include "asterisk/astobj2.h"
76 #include "asterisk/features.h"
77
78 enum error_type {
79         UNKNOWN_ACTION = 1,
80         UNKNOWN_CATEGORY,
81         UNSPECIFIED_CATEGORY,
82         UNSPECIFIED_ARGUMENT,
83         FAILURE_ALLOCATION,
84         FAILURE_NEWCAT,
85         FAILURE_DELCAT,
86         FAILURE_EMPTYCAT,
87         FAILURE_UPDATE,
88         FAILURE_DELETE,
89         FAILURE_APPEND
90 };
91
92
93 /*!
94  * Linked list of events.
95  * Global events are appended to the list by append_event().
96  * The usecount is the number of stored pointers to the element,
97  * excluding the list pointers. So an element that is only in
98  * the list has a usecount of 0, not 1.
99  *
100  * Clients have a pointer to the last event processed, and for each
101  * of these clients we track the usecount of the elements.
102  * If we have a pointer to an entry in the list, it is safe to navigate
103  * it forward because elements will not be deleted, but only appended.
104  * The worst that can happen is seeing the pointer still NULL.
105  *
106  * When the usecount of an element drops to 0, and the element is the
107  * first in the list, we can remove it. Removal is done within the
108  * main thread, which is woken up for the purpose.
109  *
110  * For simplicity of implementation, we make sure the list is never empty.
111  */
112 struct eventqent {
113         int usecount;           /*!< # of clients who still need the event */
114         int category;
115         unsigned int seq;       /*!< sequence number */
116         AST_LIST_ENTRY(eventqent) eq_next;
117         char eventdata[1];      /*!< really variable size, allocated by append_event() */
118 };
119
120 static AST_LIST_HEAD_STATIC(all_events, eventqent);
121
122 static int displayconnects = 1;
123 static int allowmultiplelogin = 1;
124 static int timestampevents;
125 static int httptimeout = 60;
126 static int manager_enabled = 0;
127 static int webmanager_enabled = 0;
128
129 #define DEFAULT_REALM           "asterisk"
130 static char global_realm[MAXHOSTNAMELEN];       /*!< Default realm */
131
132 static int block_sockets;
133
134 static int manager_debug;       /*!< enable some debugging code in the manager */
135
136 /*! \brief
137  * Descriptor for a manager session, either on the AMI socket or over HTTP.
138  *
139  * \note
140  * AMI session have managerid == 0; the entry is created upon a connect,
141  * and destroyed with the socket.
142  * HTTP sessions have managerid != 0, the value is used as a search key
143  * to lookup sessions (using the mansession_id cookie, or nonce key from
144  * Digest Authentication http header).
145  */
146 #define MAX_BLACKLIST_CMD_LEN 2
147 static struct {
148         char *words[AST_MAX_CMD_LEN];
149 } command_blacklist[] = {
150         {{ "module", "load", NULL }},
151         {{ "module", "unload", NULL }},
152         {{ "restart", "gracefully", NULL }},
153 };
154
155 /* In order to understand what the heck is going on with the
156  * mansession_session and mansession structs, we need to have a bit of a history
157  * lesson.
158  *
159  * In the beginning, there was the mansession. The mansession contained data that was
160  * intrinsic to a manager session, such as the time that it started, the name of the logged-in
161  * user, etc. In addition to these parameters were the f and fd parameters. For typical manager
162  * sessions, these were used to represent the TCP socket over which the AMI session was taking
163  * place. It makes perfect sense for these fields to be a part of the session-specific data since
164  * the session actually defines this information.
165  *
166  * Then came the HTTP AMI sessions. With these, the f and fd fields need to be opened and closed
167  * for every single action that occurs. Thus the f and fd fields aren't really specific to the session
168  * but rather to the action that is being executed. Because a single session may execute many commands
169  * at once, some sort of safety needed to be added in order to be sure that we did not end up with fd
170  * leaks from one action overwriting the f and fd fields used by a previous action before the previous action
171  * has had a chance to properly close its handles.
172  *
173  * The initial idea to solve this was to use thread synchronization, but this prevented multiple actions
174  * from being run at the same time in a single session. Some manager actions may block for a long time, thus
175  * creating a large queue of actions to execute. In addition, this fix did not address the basic architectural
176  * issue that for HTTP manager sessions, the f and fd variables are not really a part of the session, but are
177  * part of the action instead.
178  *
179  * The new idea was to create a structure on the stack for each HTTP Manager action. This structure would
180  * contain the action-specific information, such as which file to write to. In order to maintain expectations
181  * of action handlers and not have to change the public API of the manager code, we would need to name this
182  * new stacked structure 'mansession' and contain within it the old mansession struct that we used to use.
183  * We renamed the old mansession struct 'mansession_session' to hopefully convey that what is in this structure
184  * is session-specific data. The structure that it is wrapped in, called a 'mansession' really contains action-specific
185  * data.
186  */
187 struct mansession_session {
188         pthread_t ms_t;         /*!< Execution thread, basically useless */
189                                 /* XXX need to document which fields it is protecting */
190         struct sockaddr_in sin; /*!< address we are connecting from */
191         FILE *f;                /*!< fdopen() on the underlying fd */
192         int fd;                 /*!< descriptor used for output. Either the socket (AMI) or a temporary file (HTTP) */
193         int inuse;              /*!< number of HTTP sessions using this entry */
194         int needdestroy;        /*!< Whether an HTTP session should be destroyed */
195         pthread_t waiting_thread;       /*!< Sleeping thread using this descriptor */
196         uint32_t managerid;     /*!< Unique manager identifier, 0 for AMI sessions */
197         time_t sessionstart;    /*!< Session start time */
198         time_t sessiontimeout;  /*!< Session timeout if HTTP */
199         char username[80];      /*!< Logged in username */
200         char challenge[10];     /*!< Authentication challenge */
201         int authenticated;      /*!< Authentication status */
202         int readperm;           /*!< Authorization for reading */
203         int writeperm;          /*!< Authorization for writing */
204         char inbuf[1025];       /*!< Buffer */
205                                 /* we use the extra byte to add a '\0' and simplify parsing */
206         int inlen;              /*!< number of buffered bytes */
207         int send_events;        /*!<  XXX what ? */
208         struct eventqent *last_ev;      /*!< last event processed. */
209         int writetimeout;       /*!< Timeout for ast_carefulwrite() */
210         int pending_event;         /*!< Pending events indicator in case when waiting_thread is NULL */
211         time_t noncetime;       /*!< Timer for nonce value expiration */
212         unsigned long oldnonce; /*!< Stale nonce value */
213         unsigned long nc;       /*!< incremental  nonce counter */
214         AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore) datastores; /*!< Data stores on the session */
215         AST_LIST_ENTRY(mansession_session) list;
216 };
217
218 /* In case you didn't read that giant block of text above the mansession_session struct, the
219  * 'mansession' struct is named this solely to keep the API the same in Asterisk. This structure really
220  * represents data that is different from Manager action to Manager action. The mansession_session pointer
221  * contained within points to session-specific data.
222  */
223 struct mansession {
224         struct mansession_session *session;
225         FILE *f;
226         int fd;
227 };
228
229 static struct ao2_container *sessions = NULL;
230
231 #define NEW_EVENT(m)    (AST_LIST_NEXT(m->session->last_ev, eq_next))
232
233 /*! \brief user descriptor, as read from the config file.
234  *
235  * \note It is still missing some fields -- e.g. we can have multiple permit and deny
236  * lines which are not supported here, and readperm/writeperm/writetimeout
237  * are not stored.
238  */
239 struct ast_manager_user {
240         char username[80];
241         char *secret;
242         struct ast_ha *ha;              /*!< ACL setting */
243         int readperm;                   /*! Authorization for reading */
244         int writeperm;                  /*! Authorization for writing */
245         int writetimeout;               /*! Per user Timeout for ast_carefulwrite() */
246         int displayconnects;            /*!< XXX unused */
247         int keep;                       /*!< mark entries created on a reload */
248         char *a1_hash;                  /*!< precalculated A1 for Digest auth */
249         AST_RWLIST_ENTRY(ast_manager_user) list;
250 };
251
252 /*! \brief list of users found in the config file */
253 static AST_RWLIST_HEAD_STATIC(users, ast_manager_user);
254
255 /*! \brief list of actions registered */
256 static AST_RWLIST_HEAD_STATIC(actions, manager_action);
257
258 /*! \brief list of hooks registered */
259 static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook);
260
261 static struct eventqent *unref_event(struct eventqent *e);
262 static void ref_event(struct eventqent *e);
263
264 /*! \brief Add a custom hook to be called when an event is fired */
265 void ast_manager_register_hook(struct manager_custom_hook *hook)
266 {
267         AST_RWLIST_WRLOCK(&manager_hooks);
268         AST_RWLIST_INSERT_TAIL(&manager_hooks, hook, list);
269         AST_RWLIST_UNLOCK(&manager_hooks);
270         return;
271 }
272
273 /*! \brief Delete a custom hook to be called when an event is fired */
274 void ast_manager_unregister_hook(struct manager_custom_hook *hook)
275 {
276         AST_RWLIST_WRLOCK(&manager_hooks);
277         AST_RWLIST_REMOVE(&manager_hooks, hook, list);
278         AST_RWLIST_UNLOCK(&manager_hooks);
279         return;
280 }
281
282 /*! \brief
283  * Event list management functions.
284  * We assume that the event list always has at least one element,
285  * and the delete code will not remove the last entry even if the
286  *
287  */
288 #if 0
289 static time_t __deb(time_t start, const char *msg)
290 {
291         time_t now = time(NULL);
292         ast_verbose("%4d th %p %s\n", (int)(now % 3600), pthread_self(), msg);
293         if (start != 0 && now - start > 5)
294                 ast_verbose("+++ WOW, %s took %d seconds\n", msg, (int)(now - start));
295         return now;
296 }
297
298 static void LOCK_EVENTS(void)
299 {
300         time_t start = __deb(0, "about to lock events");
301         AST_LIST_LOCK(&all_events);
302         __deb(start, "done lock events");
303 }
304
305 static void UNLOCK_EVENTS(void)
306 {
307         __deb(0, "about to unlock events");
308         AST_LIST_UNLOCK(&all_events);
309 }
310
311 static void LOCK_SESS(void)
312 {
313         time_t start = __deb(0, "about to lock sessions");
314         AST_LIST_LOCK(&sessions);
315         __deb(start, "done lock sessions");
316 }
317
318 static void UNLOCK_SESS(void)
319 {
320         __deb(0, "about to unlock sessions");
321         AST_LIST_UNLOCK(&sessions);
322 }
323 #endif
324
325 int check_manager_enabled()
326 {
327         return manager_enabled;
328 }
329
330 int check_webmanager_enabled()
331 {
332         return (webmanager_enabled && manager_enabled);
333 }
334
335 /*!
336  * Grab a reference to the last event, update usecount as needed.
337  * Can handle a NULL pointer.
338  */
339 static struct eventqent *grab_last(void)
340 {
341         struct eventqent *ret;
342
343         AST_LIST_LOCK(&all_events);
344         ret = AST_LIST_LAST(&all_events);
345         /* the list is never empty now, but may become so when
346          * we optimize it in the future, so be prepared.
347          */
348         if (ret) {
349                 ast_atomic_fetchadd_int(&ret->usecount, 1);
350         }
351         AST_LIST_UNLOCK(&all_events);
352         return ret;
353 }
354
355 /*!
356  * Purge unused events. Remove elements from the head
357  * as long as their usecount is 0 and there is a next element.
358  */
359 static void purge_events(void)
360 {
361         struct eventqent *ev;
362
363         AST_LIST_LOCK(&all_events);
364         while ( (ev = AST_LIST_FIRST(&all_events)) &&
365             ev->usecount == 0 && AST_LIST_NEXT(ev, eq_next)) {
366                 AST_LIST_REMOVE_HEAD(&all_events, eq_next);
367                 ast_free(ev);
368         }
369         AST_LIST_UNLOCK(&all_events);
370 }
371
372 /*!
373  * helper functions to convert back and forth between
374  * string and numeric representation of set of flags
375  */
376 static struct permalias {
377         int num;
378         char *label;
379 } perms[] = {
380         { EVENT_FLAG_SYSTEM, "system" },
381         { EVENT_FLAG_CALL, "call" },
382         { EVENT_FLAG_LOG, "log" },
383         { EVENT_FLAG_VERBOSE, "verbose" },
384         { EVENT_FLAG_COMMAND, "command" },
385         { EVENT_FLAG_AGENT, "agent" },
386         { EVENT_FLAG_USER, "user" },
387         { EVENT_FLAG_CONFIG, "config" },
388         { EVENT_FLAG_DTMF, "dtmf" },
389         { EVENT_FLAG_REPORTING, "reporting" },
390         { EVENT_FLAG_CDR, "cdr" },
391         { EVENT_FLAG_DIALPLAN, "dialplan" },
392         { EVENT_FLAG_ORIGINATE, "originate" },
393         { EVENT_FLAG_AGI, "agi" },
394         { -1, "all" },
395         { 0, "none" },
396 };
397
398 /*! \brief Convert authority code to a list of options */
399 static char *authority_to_str(int authority, struct ast_str **res)
400 {
401         int i;
402         char *sep = "";
403
404         ast_str_reset(*res);
405         for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
406                 if (authority & perms[i].num) {
407                         ast_str_append(res, 0, "%s%s", sep, perms[i].label);
408                         sep = ",";
409                 }
410         }
411
412         if (ast_str_strlen(*res) == 0)  /* replace empty string with something sensible */
413                 ast_str_append(res, 0, "<none>");
414
415         return ast_str_buffer(*res);
416 }
417
418 /*! Tells you if smallstr exists inside bigstr
419    which is delim by delim and uses no buf or stringsep
420    ast_instring("this|that|more","this",'|') == 1;
421
422    feel free to move this to app.c -anthm */
423 static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
424 {
425         const char *val = bigstr, *next;
426
427         do {
428                 if ((next = strchr(val, delim))) {
429                         if (!strncmp(val, smallstr, (next - val))) {
430                                 return 1;
431                         } else {
432                                 continue;
433                         }
434                 } else {
435                         return !strcmp(smallstr, val);
436                 }
437         } while (*(val = (next + 1)));
438
439         return 0;
440 }
441
442 static int get_perm(const char *instr)
443 {
444         int x = 0, ret = 0;
445
446         if (!instr) {
447                 return 0;
448         }
449
450         for (x = 0; x < ARRAY_LEN(perms); x++) {
451                 if (ast_instring(instr, perms[x].label, ',')) {
452                         ret |= perms[x].num;
453                 }
454         }
455
456         return ret;
457 }
458
459 /*!
460  * A number returns itself, false returns 0, true returns all flags,
461  * other strings return the flags that are set.
462  */
463 static int strings_to_mask(const char *string)
464 {
465         const char *p;
466
467         if (ast_strlen_zero(string)) {
468                 return -1;
469         }
470
471         for (p = string; *p; p++) {
472                 if (*p < '0' || *p > '9') {
473                         break;
474                 }
475         }
476         if (!p) { /* all digits */
477                 return atoi(string);
478         }
479         if (ast_false(string)) {
480                 return 0;
481         }
482         if (ast_true(string)) { /* all permissions */
483                 int x, ret = 0;
484                 for (x = 0; x < ARRAY_LEN(perms); x++) {
485                         ret |= perms[x].num;
486                 }
487                 return ret;
488         }
489         return get_perm(string);
490 }
491
492 /*! \brief Unreference manager session object.
493      If no more references, then go ahead and delete it */
494 static struct mansession_session *unref_mansession(struct mansession_session *s)
495 {
496         int refcount = ao2_ref(s, -1);
497         if (manager_debug) {
498                 ast_log(LOG_DEBUG, "Mansession: %p refcount now %d\n", s, refcount - 1);
499         }
500         return s;
501 }
502
503 static void session_destructor(void *obj)
504 {
505         struct mansession_session *session = obj;
506         struct eventqent *eqe = session->last_ev;
507
508         if (session->f != NULL) {
509                 fclose(session->f);
510         }
511         unref_event(eqe);
512 }
513
514 /*! \brief Allocate manager session structure and add it to the list of sessions */
515 static struct mansession_session *build_mansession(struct sockaddr_in sin)
516 {
517         struct mansession_session *newsession;
518
519         if (!(newsession = ao2_alloc(sizeof(*newsession), session_destructor))) {
520                 return NULL;
521         }
522         memset(newsession, 0, sizeof(*newsession));
523         newsession->fd = -1;
524         newsession->waiting_thread = AST_PTHREADT_NULL;
525         newsession->writetimeout = 100;
526         newsession->send_events = -1;
527         newsession->sin = sin;
528
529         ao2_link(sessions, newsession);
530
531         return unref_mansession(newsession);
532 }
533
534 static int mansession_cmp_fn(void *obj, void *arg, int flags)
535 {
536         struct mansession_session *s = obj;
537         char *str = arg;
538         return !strcasecmp(s->username, str) ? CMP_MATCH : 0;
539 }
540
541 static void session_destroy(struct mansession_session *s)
542 {
543         ao2_unlink(sessions, s);
544 }
545
546
547 static int check_manager_session_inuse(const char *name)
548 {
549         struct mansession_session *session = ao2_find(sessions, (char*) name, OBJ_POINTER);
550
551         if (session) {
552                 unref_mansession(session);
553         }
554         return session ? 1 : 0;
555 }
556
557
558 /*!
559  * lookup an entry in the list of registered users.
560  * must be called with the list lock held.
561  */
562 static struct ast_manager_user *get_manager_by_name_locked(const char *name)
563 {
564         struct ast_manager_user *user = NULL;
565
566         AST_RWLIST_TRAVERSE(&users, user, list)
567                 if (!strcasecmp(user->username, name)) {
568                         break;
569                 }
570         return user;
571 }
572
573 /*! \brief Get displayconnects config option.
574  *  \param session manager session to get parameter from.
575  *  \return displayconnects config option value.
576  */
577 static int manager_displayconnects (struct mansession_session *session)
578 {
579         struct ast_manager_user *user = NULL;
580         int ret = 0;
581
582         AST_RWLIST_RDLOCK(&users);
583         if ((user = get_manager_by_name_locked (session->username))) {
584                 ret = user->displayconnects;
585         }
586         AST_RWLIST_UNLOCK(&users);
587
588         return ret;
589 }
590
591 static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
592 {
593         struct manager_action *cur;
594         struct ast_str *authority;
595         int num, l, which;
596         char *ret = NULL;
597         switch (cmd) {
598         case CLI_INIT:
599                 e->command = "manager show command";
600                 e->usage =
601                         "Usage: manager show command <actionname>\n"
602                         "       Shows the detailed description for a specific Asterisk manager interface command.\n";
603                 return NULL;
604         case CLI_GENERATE:
605                 l = strlen(a->word);
606                 which = 0;
607                 AST_RWLIST_RDLOCK(&actions);
608                 AST_RWLIST_TRAVERSE(&actions, cur, list) {
609                         if (!strncasecmp(a->word, cur->action, l) && ++which > a->n) {
610                                 ret = ast_strdup(cur->action);
611                                 break;  /* make sure we exit even if ast_strdup() returns NULL */
612                         }
613                 }
614                 AST_RWLIST_UNLOCK(&actions);
615                 return ret;
616         }
617         authority = ast_str_alloca(80);
618         if (a->argc != 4) {
619                 return CLI_SHOWUSAGE;
620         }
621
622         AST_RWLIST_RDLOCK(&actions);
623         AST_RWLIST_TRAVERSE(&actions, cur, list) {
624                 for (num = 3; num < a->argc; num++) {
625                         if (!strcasecmp(cur->action, a->argv[num])) {
626                                 ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
627                                         cur->action, cur->synopsis,
628                                         authority_to_str(cur->authority, &authority),
629                                         S_OR(cur->description, ""));
630                         }
631                 }
632         }
633         AST_RWLIST_UNLOCK(&actions);
634
635         return CLI_SUCCESS;
636 }
637
638 static char *handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
639 {
640         switch (cmd) {
641         case CLI_INIT:
642                 e->command = "manager set debug [on|off]";
643                 e->usage = "Usage: manager set debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
644                 return NULL;
645         case CLI_GENERATE:
646                 return NULL;
647         }
648
649         if (a->argc == 3) {
650                 ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
651         } else if (a->argc == 4) {
652                 if (!strcasecmp(a->argv[3], "on")) {
653                         manager_debug = 1;
654                 } else if (!strcasecmp(a->argv[3], "off")) {
655                         manager_debug = 0;
656                 } else {
657                         return CLI_SHOWUSAGE;
658                 }
659         }
660         return CLI_SUCCESS;
661 }
662
663 static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
664 {
665         struct ast_manager_user *user = NULL;
666         int l, which;
667         char *ret = NULL;
668         struct ast_str *rauthority = ast_str_alloca(128);
669         struct ast_str *wauthority = ast_str_alloca(128);
670
671         switch (cmd) {
672         case CLI_INIT:
673                 e->command = "manager show user";
674                 e->usage =
675                         " Usage: manager show user <user>\n"
676                         "        Display all information related to the manager user specified.\n";
677                 return NULL;
678         case CLI_GENERATE:
679                 l = strlen(a->word);
680                 which = 0;
681                 if (a->pos != 3) {
682                         return NULL;
683                 }
684                 AST_RWLIST_RDLOCK(&users);
685                 AST_RWLIST_TRAVERSE(&users, user, list) {
686                         if ( !strncasecmp(a->word, user->username, l) && ++which > a->n ) {
687                                 ret = ast_strdup(user->username);
688                                 break;
689                         }
690                 }
691                 AST_RWLIST_UNLOCK(&users);
692                 return ret;
693         }
694
695         if (a->argc != 4) {
696                 return CLI_SHOWUSAGE;
697         }
698
699         AST_RWLIST_RDLOCK(&users);
700
701         if (!(user = get_manager_by_name_locked(a->argv[3]))) {
702                 ast_cli(a->fd, "There is no manager called %s\n", a->argv[3]);
703                 AST_RWLIST_UNLOCK(&users);
704                 return CLI_SUCCESS;
705         }
706
707         ast_cli(a->fd, "\n");
708         ast_cli(a->fd,
709                 "       username: %s\n"
710                 "         secret: %s\n"
711                 "            acl: %s\n"
712                 "      read perm: %s\n"
713                 "     write perm: %s\n"
714                 "displayconnects: %s\n",
715                 (user->username ? user->username : "(N/A)"),
716                 (user->secret ? "<Set>" : "(N/A)"),
717                 (user->ha ? "yes" : "no"),
718                 authority_to_str(user->readperm, &rauthority),
719                 authority_to_str(user->writeperm, &wauthority),
720                 (user->displayconnects ? "yes" : "no"));
721
722         AST_RWLIST_UNLOCK(&users);
723
724         return CLI_SUCCESS;
725 }
726
727
728 static char *handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
729 {
730         struct ast_manager_user *user = NULL;
731         int count_amu = 0;
732         switch (cmd) {
733         case CLI_INIT:
734                 e->command = "manager show users";
735                 e->usage =
736                         "Usage: manager show users\n"
737                         "       Prints a listing of all managers that are currently configured on that\n"
738                         " system.\n";
739                 return NULL;
740         case CLI_GENERATE:
741                 return NULL;
742         }
743         if (a->argc != 3) {
744                 return CLI_SHOWUSAGE;
745         }
746
747         AST_RWLIST_RDLOCK(&users);
748
749         /* If there are no users, print out something along those lines */
750         if (AST_RWLIST_EMPTY(&users)) {
751                 ast_cli(a->fd, "There are no manager users.\n");
752                 AST_RWLIST_UNLOCK(&users);
753                 return CLI_SUCCESS;
754         }
755
756         ast_cli(a->fd, "\nusername\n--------\n");
757
758         AST_RWLIST_TRAVERSE(&users, user, list) {
759                 ast_cli(a->fd, "%s\n", user->username);
760                 count_amu++;
761         }
762
763         AST_RWLIST_UNLOCK(&users);
764
765         ast_cli(a->fd,"-------------------\n"
766                       "%d manager users configured.\n", count_amu);
767         return CLI_SUCCESS;
768 }
769
770
771 /*! \brief  CLI command  manager list commands */
772 static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
773 {
774         struct manager_action *cur;
775         struct ast_str *authority;
776 #define HSMC_FORMAT "  %-15.15s  %-15.15s  %-55.55s\n"
777         switch (cmd) {
778         case CLI_INIT:
779                 e->command = "manager show commands";
780                 e->usage =
781                         "Usage: manager show commands\n"
782                         "       Prints a listing of all the available Asterisk manager interface commands.\n";
783                 return NULL;
784         case CLI_GENERATE:
785                 return NULL;
786         }
787         authority = ast_str_alloca(80);
788         ast_cli(a->fd, HSMC_FORMAT, "Action", "Privilege", "Synopsis");
789         ast_cli(a->fd, HSMC_FORMAT, "------", "---------", "--------");
790
791         AST_RWLIST_RDLOCK(&actions);
792         AST_RWLIST_TRAVERSE(&actions, cur, list)
793                 ast_cli(a->fd, HSMC_FORMAT, cur->action, authority_to_str(cur->authority, &authority), cur->synopsis);
794         AST_RWLIST_UNLOCK(&actions);
795
796         return CLI_SUCCESS;
797 }
798
799 /*! \brief CLI command manager list connected */
800 static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
801 {
802         struct mansession_session *session;
803         time_t now = time(NULL);
804 #define HSMCONN_FORMAT1 "  %-15.15s  %-15.15s  %-10.10s  %-10.10s  %-8.8s  %-8.8s  %-5.5s  %-5.5s\n"
805 #define HSMCONN_FORMAT2 "  %-15.15s  %-15.15s  %-10d  %-10d  %-8d  %-8d  %-5.5d  %-5.5d\n"
806         int count = 0;
807         struct ao2_iterator i;
808
809         switch (cmd) {
810         case CLI_INIT:
811                 e->command = "manager show connected";
812                 e->usage =
813                         "Usage: manager show connected\n"
814                         "       Prints a listing of the users that are currently connected to the\n"
815                         "Asterisk manager interface.\n";
816                 return NULL;
817         case CLI_GENERATE:
818                 return NULL;
819         }
820
821         ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
822
823         i = ao2_iterator_init(sessions, 0);
824         while ((session = ao2_iterator_next(&i))) {
825                 ao2_lock(session);
826                 ast_cli(a->fd, HSMCONN_FORMAT2, session->username, ast_inet_ntoa(session->sin.sin_addr), (int)(session->sessionstart), (int)(now - session->sessionstart), session->fd, session->inuse, session->readperm, session->writeperm);
827                 count++;
828                 ao2_unlock(session);
829                 unref_mansession(session);
830         }
831
832         ast_cli(a->fd, "%d users connected.\n", count);
833
834         return CLI_SUCCESS;
835 }
836
837 /*! \brief CLI command manager list eventq */
838 /* Should change to "manager show connected" */
839 static char *handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
840 {
841         struct eventqent *s;
842         switch (cmd) {
843         case CLI_INIT:
844                 e->command = "manager show eventq";
845                 e->usage =
846                         "Usage: manager show eventq\n"
847                         "       Prints a listing of all events pending in the Asterisk manger\n"
848                         "event queue.\n";
849                 return NULL;
850         case CLI_GENERATE:
851                 return NULL;
852         }
853         AST_LIST_LOCK(&all_events);
854         AST_LIST_TRAVERSE(&all_events, s, eq_next) {
855                 ast_cli(a->fd, "Usecount: %d\n", s->usecount);
856                 ast_cli(a->fd, "Category: %d\n", s->category);
857                 ast_cli(a->fd, "Event:\n%s", s->eventdata);
858         }
859         AST_LIST_UNLOCK(&all_events);
860
861         return CLI_SUCCESS;
862 }
863
864 /*! \brief CLI command manager reload */
865 static char *handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
866 {
867         switch (cmd) {
868         case CLI_INIT:
869                 e->command = "manager reload";
870                 e->usage =
871                         "Usage: manager reload\n"
872                         "       Reloads the manager configuration.\n";
873                 return NULL;
874         case CLI_GENERATE:
875                 return NULL;
876         }
877         if (a->argc > 2) {
878                 return CLI_SHOWUSAGE;
879         }
880         reload_manager();
881         return CLI_SUCCESS;
882 }
883
884
885 static struct ast_cli_entry cli_manager[] = {
886         AST_CLI_DEFINE(handle_showmancmd, "Show a manager interface command"),
887         AST_CLI_DEFINE(handle_showmancmds, "List manager interface commands"),
888         AST_CLI_DEFINE(handle_showmanconn, "List connected manager interface users"),
889         AST_CLI_DEFINE(handle_showmaneventq, "List manager interface queued events"),
890         AST_CLI_DEFINE(handle_showmanagers, "List configured manager users"),
891         AST_CLI_DEFINE(handle_showmanager, "Display information on a specific manager user"),
892         AST_CLI_DEFINE(handle_mandebug, "Show, enable, disable debugging of the manager code"),
893         AST_CLI_DEFINE(handle_manager_reload, "Reload manager configurations"),
894 };
895
896 static struct eventqent *unref_event(struct eventqent *e)
897 {
898         ast_atomic_fetchadd_int(&e->usecount, -1);
899         return AST_LIST_NEXT(e, eq_next);
900 }
901
902 static void ref_event(struct eventqent *e)
903 {
904         ast_atomic_fetchadd_int(&e->usecount, 1);
905 }
906
907 /*
908  * destroy a session, leaving the usecount
909  */
910 static void free_session(struct mansession_session *session)
911 {
912         struct eventqent *eqe = session->last_ev;
913         struct ast_datastore *datastore;
914
915         /* Get rid of each of the data stores on the session */
916         while ((datastore = AST_LIST_REMOVE_HEAD(&session->datastores, entry))) {
917                 /* Free the data store */
918                 ast_datastore_free(datastore);
919         }
920
921         if (session->f != NULL)
922                 fclose(session->f);
923         ast_free(session);
924         unref_event(eqe);
925 }
926
927 static void destroy_session(struct mansession_session *session)
928 {
929         ao2_unlink(sessions, session);
930         free_session(session);
931 }
932
933 /*
934  * Generic function to return either the first or the last matching header
935  * from a list of variables, possibly skipping empty strings.
936  * At the moment there is only one use of this function in this file,
937  * so we make it static.
938  */
939 #define GET_HEADER_FIRST_MATCH  0
940 #define GET_HEADER_LAST_MATCH   1
941 #define GET_HEADER_SKIP_EMPTY   2
942 static const char *__astman_get_header(const struct message *m, char *var, int mode)
943 {
944         int x, l = strlen(var);
945         const char *result = "";
946
947         for (x = 0; x < m->hdrcount; x++) {
948                 const char *h = m->headers[x];
949                 if (!strncasecmp(var, h, l) && h[l] == ':' && h[l+1] == ' ') {
950                         const char *value = h + l + 2;
951                         /* found a potential candidate */
952                         if (mode & GET_HEADER_SKIP_EMPTY && ast_strlen_zero(value))
953                                 continue;       /* not interesting */
954                         if (mode & GET_HEADER_LAST_MATCH)
955                                 result = value; /* record the last match so far */
956                         else
957                                 return value;
958                 }
959         }
960
961         return "";
962 }
963
964 /*
965  * Return the first matching variable from an array.
966  * This is the legacy function and is implemented in therms of
967  * __astman_get_header().
968  */
969 const char *astman_get_header(const struct message *m, char *var)
970 {
971         return __astman_get_header(m, var, GET_HEADER_FIRST_MATCH);
972 }
973
974
975 struct ast_variable *astman_get_variables(const struct message *m)
976 {
977         int varlen, x, y;
978         struct ast_variable *head = NULL, *cur;
979
980         AST_DECLARE_APP_ARGS(args,
981                 AST_APP_ARG(vars)[32];
982         );
983
984         varlen = strlen("Variable: ");
985
986         for (x = 0; x < m->hdrcount; x++) {
987                 char *parse, *var, *val;
988
989                 if (strncasecmp("Variable: ", m->headers[x], varlen)) {
990                         continue;
991                 }
992                 parse = ast_strdupa(m->headers[x] + varlen);
993
994                 AST_STANDARD_APP_ARGS(args, parse);
995                 if (!args.argc) {
996                         continue;
997                 }
998                 for (y = 0; y < args.argc; y++) {
999                         if (!args.vars[y]) {
1000                                 continue;
1001                         }
1002                         var = val = ast_strdupa(args.vars[y]);
1003                         strsep(&val, "=");
1004                         if (!val || ast_strlen_zero(var)) {
1005                                 continue;
1006                         }
1007                         cur = ast_variable_new(var, val, "");
1008                         cur->next = head;
1009                         head = cur;
1010                 }
1011         }
1012
1013         return head;
1014 }
1015
1016 /*!
1017  * helper function to send a string to the socket.
1018  * Return -1 on error (e.g. buffer full).
1019  */
1020 static int send_string(struct mansession *s, char *string)
1021 {
1022         if (s->f) {
1023                 return ast_careful_fwrite(s->f, s->fd, string, strlen(string), s->session->writetimeout);
1024         } else {
1025                 return ast_careful_fwrite(s->session->f, s->session->fd, string, strlen(string), s->session->writetimeout);
1026         }
1027 }
1028
1029 /*!
1030  * \brief thread local buffer for astman_append
1031  *
1032  * \note This can not be defined within the astman_append() function
1033  *       because it declares a couple of functions that get used to
1034  *       initialize the thread local storage key.
1035  */
1036 AST_THREADSTORAGE(astman_append_buf);
1037 AST_THREADSTORAGE(userevent_buf);
1038
1039 /*! \brief initial allocated size for the astman_append_buf */
1040 #define ASTMAN_APPEND_BUF_INITSIZE   256
1041
1042 /*!
1043  * utility functions for creating AMI replies
1044  */
1045 void astman_append(struct mansession *s, const char *fmt, ...)
1046 {
1047         va_list ap;
1048         struct ast_str *buf;
1049
1050         if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
1051                 return;
1052         }
1053
1054         va_start(ap, fmt);
1055         ast_str_set_va(&buf, 0, fmt, ap);
1056         va_end(ap);
1057
1058         if (s->f != NULL || s->session->f != NULL) {
1059                 send_string(s, ast_str_buffer(buf));
1060         } else {
1061                 ast_verbose("fd == -1 in astman_append, should not happen\n");
1062         }
1063 }
1064
1065 /*! \note NOTE: XXX this comment is unclear and possibly wrong.
1066    Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
1067    hold the session lock _or_ be running in an action callback (in which case s->session->busy will
1068    be non-zero). In either of these cases, there is no need to lock-protect the session's
1069    fd, since no other output will be sent (events will be queued), and no input will
1070    be read until either the current action finishes or get_input() obtains the session
1071    lock.
1072  */
1073
1074 /*! \brief send a response with an optional message,
1075  * and terminate it with an empty line.
1076  * m is used only to grab the 'ActionID' field.
1077  *
1078  * Use the explicit constant MSG_MOREDATA to remove the empty line.
1079  * XXX MSG_MOREDATA should go to a header file.
1080  */
1081 #define MSG_MOREDATA    ((char *)astman_send_response)
1082 static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
1083 {
1084         const char *id = astman_get_header(m, "ActionID");
1085
1086         astman_append(s, "Response: %s\r\n", resp);
1087         if (!ast_strlen_zero(id)) {
1088                 astman_append(s, "ActionID: %s\r\n", id);
1089         }
1090         if (listflag) {
1091                 astman_append(s, "Eventlist: %s\r\n", listflag);        /* Start, complete, cancelled */
1092         }
1093         if (msg == MSG_MOREDATA) {
1094                 return;
1095         } else if (msg) {
1096                 astman_append(s, "Message: %s\r\n\r\n", msg);
1097         } else {
1098                 astman_append(s, "\r\n");
1099         }
1100 }
1101
1102 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
1103 {
1104         astman_send_response_full(s, m, resp, msg, NULL);
1105 }
1106
1107 void astman_send_error(struct mansession *s, const struct message *m, char *error)
1108 {
1109         astman_send_response_full(s, m, "Error", error, NULL);
1110 }
1111
1112 void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
1113 {
1114         astman_send_response_full(s, m, "Success", msg, NULL);
1115 }
1116
1117 static void astman_start_ack(struct mansession *s, const struct message *m)
1118 {
1119         astman_send_response_full(s, m, "Success", MSG_MOREDATA, NULL);
1120 }
1121
1122 void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
1123 {
1124         astman_send_response_full(s, m, "Success", msg, listflag);
1125 }
1126
1127
1128 /*! \brief
1129    Rather than braindead on,off this now can also accept a specific int mask value
1130    or a ',' delim list of mask strings (the same as manager.conf) -anthm
1131 */
1132 static int set_eventmask(struct mansession *s, const char *eventmask)
1133 {
1134         int maskint = strings_to_mask(eventmask);
1135
1136         ao2_lock(s);
1137         if (maskint >= 0) {
1138                 s->session->send_events = maskint;
1139         }
1140         ao2_unlock(s);
1141
1142         return maskint;
1143 }
1144
1145 /*
1146  * Here we start with action_ handlers for AMI actions,
1147  * and the internal functions used by them.
1148  * Generally, the handlers are called action_foo()
1149  */
1150
1151 /* helper function for action_login() */
1152 static int authenticate(struct mansession *s, const struct message *m)
1153 {
1154         const char *username = astman_get_header(m, "Username");
1155         const char *password = astman_get_header(m, "Secret");
1156         int error = -1;
1157         struct ast_manager_user *user = NULL;
1158
1159         if (ast_strlen_zero(username)) {        /* missing username */
1160                 return -1;
1161         }
1162
1163         /* locate user in locked state */
1164         AST_RWLIST_WRLOCK(&users);
1165
1166         if (!(user = get_manager_by_name_locked(username))) {
1167                 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
1168         } else if (user->ha && !ast_apply_ha(user->ha, &(s->session->sin))) {
1169                 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
1170         } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
1171                 const char *key = astman_get_header(m, "Key");
1172                 if (!ast_strlen_zero(key) && !ast_strlen_zero(s->session->challenge) && user->secret) {
1173                         int x;
1174                         int len = 0;
1175                         char md5key[256] = "";
1176                         struct MD5Context md5;
1177                         unsigned char digest[16];
1178
1179                         MD5Init(&md5);
1180                         MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
1181                         MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
1182                         MD5Final(digest, &md5);
1183                         for (x = 0; x < 16; x++)
1184                                 len += sprintf(md5key + len, "%2.2x", digest[x]);
1185                         if (!strcmp(md5key, key)) {
1186                                 error = 0;
1187                         }
1188                 } else {
1189                         ast_debug(1, "MD5 authentication is not possible.  challenge: '%s'\n",
1190                                 S_OR(s->session->challenge, ""));
1191                 }
1192         } else if (password && user->secret && !strcmp(password, user->secret)) {
1193                 error = 0;
1194         }
1195
1196         if (error) {
1197                 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
1198                 AST_RWLIST_UNLOCK(&users);
1199                 return -1;
1200         }
1201
1202         /* auth complete */
1203
1204         ast_copy_string(s->session->username, username, sizeof(s->session->username));
1205         s->session->readperm = user->readperm;
1206         s->session->writeperm = user->writeperm;
1207         s->session->writetimeout = user->writetimeout;
1208         s->session->sessionstart = time(NULL);
1209         set_eventmask(s, astman_get_header(m, "Events"));
1210
1211         AST_RWLIST_UNLOCK(&users);
1212         return 0;
1213 }
1214
1215 /*! \brief Manager PING */
1216 static char mandescr_ping[] =
1217 "Description: A 'Ping' action will ellicit a 'Pong' response.  Used to keep the\n"
1218 "  manager connection open.\n"
1219 "Variables: NONE\n";
1220
1221 static int action_ping(struct mansession *s, const struct message *m)
1222 {
1223         const char *actionid = astman_get_header(m, "ActionID");
1224
1225         astman_append(s, "Response: Success\r\n");
1226         if (!ast_strlen_zero(actionid)){
1227                 astman_append(s, "ActionID: %s\r\n", actionid);
1228         }
1229         astman_append(s, "Ping: Pong\r\n\r\n");
1230         return 0;
1231 }
1232
1233 static char mandescr_getconfig[] =
1234 "Description: A 'GetConfig' action will dump the contents of a configuration\n"
1235 "file by category and contents or optionally by specified category only.\n"
1236 "Variables: (Names marked with * are required)\n"
1237 "   *Filename: Configuration filename (e.g. foo.conf)\n"
1238 "   Category: Category in configuration file\n";
1239
1240 static int action_getconfig(struct mansession *s, const struct message *m)
1241 {
1242         struct ast_config *cfg;
1243         const char *fn = astman_get_header(m, "Filename");
1244         const char *category = astman_get_header(m, "Category");
1245         int catcount = 0;
1246         int lineno = 0;
1247         char *cur_category = NULL;
1248         struct ast_variable *v;
1249         struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
1250
1251         if (ast_strlen_zero(fn)) {
1252                 astman_send_error(s, m, "Filename not specified");
1253                 return 0;
1254         }
1255         cfg = ast_config_load2(fn, "manager", config_flags);
1256         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1257                 astman_send_error(s, m, "Config file not found");
1258                 return 0;
1259         }
1260
1261         astman_start_ack(s, m);
1262         while ((cur_category = ast_category_browse(cfg, cur_category))) {
1263                 if (ast_strlen_zero(category) || (!ast_strlen_zero(category) && !strcmp(category, cur_category))) {
1264                         lineno = 0;
1265                         astman_append(s, "Category-%06d: %s\r\n", catcount, cur_category);
1266                         for (v = ast_variable_browse(cfg, cur_category); v; v = v->next) {
1267                                 astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
1268                         }
1269                         catcount++;
1270                 }
1271         }
1272         if (!ast_strlen_zero(category) && catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
1273                 astman_append(s, "No categories found\r\n");
1274         }
1275         ast_config_destroy(cfg);
1276         astman_append(s, "\r\n");
1277
1278         return 0;
1279 }
1280
1281 static char mandescr_listcategories[] =
1282 "Description: A 'ListCategories' action will dump the categories in\n"
1283 "a given file.\n"
1284 "Variables:\n"
1285 "   Filename: Configuration filename (e.g. foo.conf)\n";
1286
1287 static int action_listcategories(struct mansession *s, const struct message *m)
1288 {
1289         struct ast_config *cfg;
1290         const char *fn = astman_get_header(m, "Filename");
1291         char *category = NULL;
1292         struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
1293         int catcount = 0;
1294
1295         if (ast_strlen_zero(fn)) {
1296                 astman_send_error(s, m, "Filename not specified");
1297                 return 0;
1298         }
1299         if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
1300                 astman_send_error(s, m, "Config file not found or file has invalid syntax");
1301                 return 0;
1302         }
1303         astman_start_ack(s, m);
1304         while ((category = ast_category_browse(cfg, category))) {
1305                 astman_append(s, "Category-%06d: %s\r\n", catcount, category);
1306                 catcount++;
1307         }
1308         if (catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
1309                 astman_append(s, "Error: no categories found\r\n");
1310         }
1311         ast_config_destroy(cfg);
1312         astman_append(s, "\r\n");
1313
1314         return 0;
1315 }
1316
1317
1318
1319
1320 /*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
1321 static void json_escape(char *out, const char *in)
1322 {
1323         for (; *in; in++) {
1324                 if (*in == '\\' || *in == '\"') {
1325                         *out++ = '\\';
1326                 }
1327                 *out++ = *in;
1328         }
1329         *out = '\0';
1330 }
1331
1332 static char mandescr_getconfigjson[] =
1333 "Description: A 'GetConfigJSON' action will dump the contents of a configuration\n"
1334 "file by category and contents in JSON format.  This only makes sense to be used\n"
1335 "using rawman over the HTTP interface.\n"
1336 "Variables:\n"
1337 "   Filename: Configuration filename (e.g. foo.conf)\n";
1338
1339 static int action_getconfigjson(struct mansession *s, const struct message *m)
1340 {
1341         struct ast_config *cfg;
1342         const char *fn = astman_get_header(m, "Filename");
1343         char *category = NULL;
1344         struct ast_variable *v;
1345         int comma1 = 0;
1346         char *buf = NULL;
1347         unsigned int buf_len = 0;
1348         struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
1349
1350         if (ast_strlen_zero(fn)) {
1351                 astman_send_error(s, m, "Filename not specified");
1352                 return 0;
1353         }
1354
1355         if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
1356                 astman_send_error(s, m, "Config file not found");
1357                 return 0;
1358         }
1359
1360         buf_len = 512;
1361         buf = alloca(buf_len);
1362
1363         astman_start_ack(s, m);
1364         astman_append(s, "JSON: {");
1365         while ((category = ast_category_browse(cfg, category))) {
1366                 int comma2 = 0;
1367                 if (buf_len < 2 * strlen(category) + 1) {
1368                         buf_len *= 2;
1369                         buf = alloca(buf_len);
1370                 }
1371                 json_escape(buf, category);
1372                 astman_append(s, "%s\"%s\":[", comma1 ? "," : "", buf);
1373                 if (!comma1) {
1374                         comma1 = 1;
1375                 }
1376                 for (v = ast_variable_browse(cfg, category); v; v = v->next) {
1377                         if (comma2) {
1378                                 astman_append(s, ",");
1379                         }
1380                         if (buf_len < 2 * strlen(v->name) + 1) {
1381                                 buf_len *= 2;
1382                                 buf = alloca(buf_len);
1383                         }
1384                         json_escape(buf, v->name);
1385                         astman_append(s, "\"%s", buf);
1386                         if (buf_len < 2 * strlen(v->value) + 1) {
1387                                 buf_len *= 2;
1388                                 buf = alloca(buf_len);
1389                         }
1390                         json_escape(buf, v->value);
1391                         astman_append(s, "%s\"", buf);
1392                         if (!comma2) {
1393                                 comma2 = 1;
1394                         }
1395                 }
1396                 astman_append(s, "]");
1397         }
1398         astman_append(s, "}\r\n\r\n");
1399
1400         ast_config_destroy(cfg);
1401
1402         return 0;
1403 }
1404
1405 /* helper function for action_updateconfig */
1406 static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
1407 {
1408         int x;
1409         char hdr[40];
1410         const char *action, *cat, *var, *value, *match, *line;
1411         struct ast_category *category;
1412         struct ast_variable *v;
1413         struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
1414         enum error_type result = 0;
1415
1416         for (x = 0; x < 100000; x++) {  /* 100000 = the max number of allowed updates + 1 */
1417                 unsigned int object = 0;
1418
1419                 snprintf(hdr, sizeof(hdr), "Action-%06d", x);
1420                 action = astman_get_header(m, hdr);
1421                 if (ast_strlen_zero(action))            /* breaks the for loop if no action header */
1422                         break;                          /* this could cause problems if actions come in misnumbered */
1423
1424                 snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
1425                 cat = astman_get_header(m, hdr);
1426                 if (ast_strlen_zero(cat)) {             /* every action needs a category */
1427                         result =  UNSPECIFIED_CATEGORY;
1428                         break;
1429                 }
1430
1431                 snprintf(hdr, sizeof(hdr), "Var-%06d", x);
1432                 var = astman_get_header(m, hdr);
1433
1434                 snprintf(hdr, sizeof(hdr), "Value-%06d", x);
1435                 value = astman_get_header(m, hdr);
1436
1437                 if (!ast_strlen_zero(value) && *value == '>') {
1438                         object = 1;
1439                         value++;
1440                 }
1441
1442                 snprintf(hdr, sizeof(hdr), "Match-%06d", x);
1443                 match = astman_get_header(m, hdr);
1444
1445                 snprintf(hdr, sizeof(hdr), "Line-%06d", x);
1446                 line = astman_get_header(m, hdr);
1447
1448                 if (!strcasecmp(action, "newcat")) {
1449                         if (ast_category_get(cfg,cat)) {        /* check to make sure the cat doesn't */
1450                                 result = FAILURE_NEWCAT;        /* already exist */
1451                                 break;
1452                         }
1453                         if (!(category = ast_category_new(cat, dfn, -1))) {
1454                                 result = FAILURE_ALLOCATION;
1455                                 break;
1456                         }
1457                         if (ast_strlen_zero(match)) {
1458                                 ast_category_append(cfg, category);
1459                         } else {
1460                                 ast_category_insert(cfg, category, match);
1461                         }
1462                 } else if (!strcasecmp(action, "renamecat")) {
1463                         if (ast_strlen_zero(value)) {
1464                                 result = UNSPECIFIED_ARGUMENT;
1465                                 break;
1466                         }
1467                         if (!(category = ast_category_get(cfg, cat))) {
1468                                 result = UNKNOWN_CATEGORY;
1469                                 break;
1470                         }
1471                         ast_category_rename(category, value);
1472                 } else if (!strcasecmp(action, "delcat")) {
1473                         if (ast_category_delete(cfg, cat)) {
1474                                 result = FAILURE_DELCAT;
1475                                 break;
1476                         }
1477                 } else if (!strcasecmp(action, "emptycat")) {
1478                         if (ast_category_empty(cfg, cat)) {
1479                                 result = FAILURE_EMPTYCAT;
1480                                 break;
1481                         }
1482                 } else if (!strcasecmp(action, "update")) {
1483                         if (ast_strlen_zero(var)) {
1484                                 result = UNSPECIFIED_ARGUMENT;
1485                                 break;
1486                         }
1487                         if (!(category = ast_category_get(cfg,cat))) {
1488                                 result = UNKNOWN_CATEGORY;
1489                                 break;
1490                         }
1491                         if (ast_variable_update(category, var, value, match, object)) {
1492                                 result = FAILURE_UPDATE;
1493                                 break;
1494                         }
1495                 } else if (!strcasecmp(action, "delete")) {
1496                         if ((ast_strlen_zero(var) && ast_strlen_zero(line))) {
1497                                 result = UNSPECIFIED_ARGUMENT;
1498                                 break;
1499                         }
1500                         if (!(category = ast_category_get(cfg, cat))) {
1501                                 result = UNKNOWN_CATEGORY;
1502                                 break;
1503                         }
1504                         if (ast_variable_delete(category, var, match, line)) {
1505                                 result = FAILURE_DELETE;
1506                                 break;
1507                         }
1508                 } else if (!strcasecmp(action, "append")) {
1509                         if (ast_strlen_zero(var)) {
1510                                 result = UNSPECIFIED_ARGUMENT;
1511                                 break;
1512                         }
1513                         if (!(category = ast_category_get(cfg, cat))) {
1514                                 result = UNKNOWN_CATEGORY;
1515                                 break;
1516                         }
1517                         if (!(v = ast_variable_new(var, value, dfn))) {
1518                                 result = FAILURE_ALLOCATION;
1519                                 break;
1520                         }
1521                         if (object || (match && !strcasecmp(match, "object"))) {
1522                                 v->object = 1;
1523                         }
1524                         ast_variable_append(category, v);
1525                 } else if (!strcasecmp(action, "insert")) {
1526                         if (ast_strlen_zero(var) || ast_strlen_zero(line)) {
1527                                 result = UNSPECIFIED_ARGUMENT;
1528                                 break;
1529                         }
1530                         if (!(category = ast_category_get(cfg, cat))) {
1531                                 result = UNKNOWN_CATEGORY;
1532                                 break;
1533                         }
1534                         if (!(v = ast_variable_new(var, value, dfn))) {
1535                                 result = FAILURE_ALLOCATION;
1536                                 break;
1537                         }
1538                         ast_variable_insert(category, v, line);
1539                 }
1540                 else {
1541                         ast_log(LOG_WARNING, "Action-%06d: %s not handled\n", x, action);
1542                         result = UNKNOWN_ACTION;
1543                         break;
1544                 }
1545         }
1546         ast_free(str1);
1547         ast_free(str2);
1548         return result;
1549 }
1550
1551 static char mandescr_updateconfig[] =
1552 "Description: A 'UpdateConfig' action will modify, create, or delete\n"
1553 "configuration elements in Asterisk configuration files.\n"
1554 "Variables (X's represent 6 digit number beginning with 000000):\n"
1555 "   SrcFilename:   Configuration filename to read(e.g. foo.conf)\n"
1556 "   DstFilename:   Configuration filename to write(e.g. foo.conf)\n"
1557 "   Reload:        Whether or not a reload should take place (or name of specific module)\n"
1558 "   Action-XXXXXX: Action to Take (NewCat,RenameCat,DelCat,EmptyCat,Update,Delete,Append,Insert)\n"
1559 "   Cat-XXXXXX:    Category to operate on\n"
1560 "   Var-XXXXXX:    Variable to work on\n"
1561 "   Value-XXXXXX:  Value to work on\n"
1562 "   Match-XXXXXX:  Extra match required to match line\n"
1563 "   Line-XXXXXX:   Line in category to operate on (used with delete and insert actions)\n";
1564
1565 static int action_updateconfig(struct mansession *s, const struct message *m)
1566 {
1567         struct ast_config *cfg;
1568         const char *sfn = astman_get_header(m, "SrcFilename");
1569         const char *dfn = astman_get_header(m, "DstFilename");
1570         int res;
1571         const char *rld = astman_get_header(m, "Reload");
1572         struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
1573         enum error_type result;
1574
1575         if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
1576                 astman_send_error(s, m, "Filename not specified");
1577                 return 0;
1578         }
1579         if (!(cfg = ast_config_load2(sfn, "manager", config_flags))) {
1580                 astman_send_error(s, m, "Config file not found");
1581                 return 0;
1582         }
1583         result = handle_updates(s, m, cfg, dfn);
1584         if (!result) {
1585                 ast_include_rename(cfg, sfn, dfn); /* change the include references from dfn to sfn, so things match up */
1586                 res = ast_config_text_file_save(dfn, cfg, "Manager");
1587                 ast_config_destroy(cfg);
1588                 if (res) {
1589                         astman_send_error(s, m, "Save of config failed");
1590                         return 0;
1591                 }
1592                 astman_send_ack(s, m, NULL);
1593                 if (!ast_strlen_zero(rld)) {
1594                         if (ast_true(rld)) {
1595                                 rld = NULL;
1596                         }
1597                         ast_module_reload(rld);
1598                 }
1599         } else {
1600                 ast_config_destroy(cfg);
1601                 switch(result) {
1602                 case UNKNOWN_ACTION:
1603                         astman_send_error(s, m, "Unknown action command");
1604                         break;
1605                 case UNKNOWN_CATEGORY:
1606                         astman_send_error(s, m, "Given category does not exist");
1607                         break;
1608                 case UNSPECIFIED_CATEGORY:
1609                         astman_send_error(s, m, "Category not specified");
1610                         break;
1611                 case UNSPECIFIED_ARGUMENT:
1612                         astman_send_error(s, m, "Problem with category, value, or line (if required)");
1613                         break;
1614                 case FAILURE_ALLOCATION:
1615                         astman_send_error(s, m, "Memory allocation failure, this should not happen");
1616                         break;
1617                 case FAILURE_NEWCAT:
1618                         astman_send_error(s, m, "Create category did not complete successfully");
1619                         break;
1620                 case FAILURE_DELCAT:
1621                         astman_send_error(s, m, "Delete category did not complete successfully");
1622                         break;
1623                 case FAILURE_EMPTYCAT:
1624                         astman_send_error(s, m, "Empty category did not complete successfully");
1625                         break;
1626                 case FAILURE_UPDATE:
1627                         astman_send_error(s, m, "Update did not complete successfully");
1628                         break;
1629                 case FAILURE_DELETE:
1630                         astman_send_error(s, m, "Delete did not complete successfully");
1631                         break;
1632                 case FAILURE_APPEND:
1633                         astman_send_error(s, m, "Append did not complete successfully");
1634                         break;
1635                 }
1636         }
1637         return 0;
1638 }
1639
1640 static char mandescr_createconfig[] =
1641 "Description: A 'CreateConfig' action will create an empty file in the\n"
1642 "configuration directory. This action is intended to be used before an\n"
1643 "UpdateConfig action.\n"
1644 "Variables\n"
1645 "   Filename:   The configuration filename to create (e.g. foo.conf)\n";
1646
1647 static int action_createconfig(struct mansession *s, const struct message *m)
1648 {
1649         int fd;
1650         const char *fn = astman_get_header(m, "Filename");
1651         struct ast_str *filepath = ast_str_alloca(PATH_MAX);
1652         ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
1653         ast_str_append(&filepath, 0, "%s", fn);
1654
1655         if ((fd = open(ast_str_buffer(filepath), O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
1656                 close(fd);
1657                 astman_send_ack(s, m, "New configuration file created successfully");
1658         } else {
1659                 astman_send_error(s, m, strerror(errno));
1660         }
1661
1662         return 0;
1663 }
1664
1665 /*! \brief Manager WAITEVENT */
1666 static char mandescr_waitevent[] =
1667 "Description: A 'WaitEvent' action will ellicit a 'Success' response.  Whenever\n"
1668 "a manager event is queued.  Once WaitEvent has been called on an HTTP manager\n"
1669 "session, events will be generated and queued.\n"
1670 "Variables: \n"
1671 "   Timeout: Maximum time (in seconds) to wait for events, -1 means forever.\n";
1672
1673 static int action_waitevent(struct mansession *s, const struct message *m)
1674 {
1675         const char *timeouts = astman_get_header(m, "Timeout");
1676         int timeout = -1;
1677         int x;
1678         int needexit = 0;
1679         const char *id = astman_get_header(m, "ActionID");
1680         char idText[256];
1681
1682         if (!ast_strlen_zero(id)) {
1683                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
1684         } else {
1685                 idText[0] = '\0';
1686         }
1687
1688         if (!ast_strlen_zero(timeouts)) {
1689                 sscanf(timeouts, "%i", &timeout);
1690                 if (timeout < -1) {
1691                         timeout = -1;
1692                 }
1693                 /* XXX maybe put an upper bound, or prevent the use of 0 ? */
1694         }
1695
1696         ao2_lock(s);
1697         if (s->session->waiting_thread != AST_PTHREADT_NULL) {
1698                 pthread_kill(s->session->waiting_thread, SIGURG);
1699         }
1700
1701         if (s->session->managerid) { /* AMI-over-HTTP session */
1702                 /*
1703                  * Make sure the timeout is within the expire time of the session,
1704                  * as the client will likely abort the request if it does not see
1705                  * data coming after some amount of time.
1706                  */
1707                 time_t now = time(NULL);
1708                 int max = s->session->sessiontimeout - now - 10;
1709
1710                 if (max < 0) {  /* We are already late. Strange but possible. */
1711                         max = 0;
1712                 }
1713                 if (timeout < 0 || timeout > max) {
1714                         timeout = max;
1715                 }
1716                 if (!s->session->send_events) { /* make sure we record events */
1717                         s->session->send_events = -1;
1718                 }
1719         }
1720         ao2_unlock(s);
1721
1722         /* XXX should this go inside the lock ? */
1723         s->session->waiting_thread = pthread_self();    /* let new events wake up this thread */
1724         ast_debug(1, "Starting waiting for an event!\n");
1725
1726         for (x = 0; x < timeout || timeout < 0; x++) {
1727                 ao2_lock(s);
1728                 if (NEW_EVENT(s)) {
1729                         needexit = 1;
1730                 }
1731                 /* We can have multiple HTTP session point to the same mansession entry.
1732                  * The way we deal with it is not very nice: newcomers kick out the previous
1733                  * HTTP session. XXX this needs to be improved.
1734                  */
1735                 if (s->session->waiting_thread != pthread_self()) {
1736                         needexit = 1;
1737                 }
1738                 if (s->session->needdestroy) {
1739                         needexit = 1;
1740                 }
1741                 ao2_unlock(s);
1742                 if (needexit) {
1743                         break;
1744                 }
1745                 if (s->session->managerid == 0) {       /* AMI session */
1746                         if (ast_wait_for_input(s->session->fd, 1000)) {
1747                                 break;
1748                         }
1749                 } else {        /* HTTP session */
1750                         sleep(1);
1751                 }
1752         }
1753         ast_debug(1, "Finished waiting for an event!\n");
1754
1755         ao2_lock(s);
1756         if (s->session->waiting_thread == pthread_self()) {
1757                 struct eventqent *eqe;
1758                 astman_send_response(s, m, "Success", "Waiting for Event completed.");
1759                 while ( (eqe = NEW_EVENT(s)) ) {
1760                         ref_event(eqe);
1761                         if (((s->session->readperm & eqe->category) == eqe->category) &&
1762                             ((s->session->send_events & eqe->category) == eqe->category)) {
1763                                 astman_append(s, "%s", eqe->eventdata);
1764                         }
1765                         s->session->last_ev = unref_event(s->session->last_ev);
1766                 }
1767                 astman_append(s,
1768                         "Event: WaitEventComplete\r\n"
1769                         "%s"
1770                         "\r\n", idText);
1771                 s->session->waiting_thread = AST_PTHREADT_NULL;
1772         } else {
1773                 ast_debug(1, "Abandoning event request!\n");
1774         }
1775         ao2_unlock(s);
1776         return 0;
1777 }
1778
1779 static char mandescr_listcommands[] =
1780 "Description: Returns the action name and synopsis for every\n"
1781 "  action that is available to the user\n"
1782 "Variables: NONE\n";
1783
1784 /*! \note The actionlock is read-locked by the caller of this function */
1785 static int action_listcommands(struct mansession *s, const struct message *m)
1786 {
1787         struct manager_action *cur;
1788         struct ast_str *temp = ast_str_alloca(BUFSIZ); /* XXX very large ? */
1789
1790         astman_start_ack(s, m);
1791         AST_RWLIST_TRAVERSE(&actions, cur, list) {
1792                 if (s->session->writeperm & cur->authority || cur->authority == 0) {
1793                         astman_append(s, "%s: %s (Priv: %s)\r\n",
1794                                 cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
1795                 }
1796         }
1797         astman_append(s, "\r\n");
1798
1799         return 0;
1800 }
1801
1802 static char mandescr_events[] =
1803 "Description: Enable/Disable sending of events to this manager\n"
1804 "  client.\n"
1805 "Variables:\n"
1806 "       EventMask: 'on' if all events should be sent,\n"
1807 "               'off' if no events should be sent,\n"
1808 "               'system,call,log' to select which flags events should have to be sent.\n";
1809
1810 static int action_events(struct mansession *s, const struct message *m)
1811 {
1812         const char *mask = astman_get_header(m, "EventMask");
1813         int res;
1814
1815         res = set_eventmask(s, mask);
1816         if (res > 0)
1817                 astman_append(s, "Response: Success\r\n"
1818                                  "Events: On\r\n");
1819         else if (res == 0)
1820                 astman_append(s, "Response: Success\r\n"
1821                                  "Events: Off\r\n");
1822         return 0;
1823 }
1824
1825 static char mandescr_logoff[] =
1826 "Description: Logoff this manager session\n"
1827 "Variables: NONE\n";
1828
1829 static int action_logoff(struct mansession *s, const struct message *m)
1830 {
1831         astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
1832         return -1;
1833 }
1834
1835 static int action_login(struct mansession *s, const struct message *m)
1836 {
1837
1838         /* still authenticated - don't process again */
1839         if (s->session->authenticated) {
1840                 astman_send_ack(s, m, "Already authenticated");
1841                 return 0;
1842         }
1843
1844         if (authenticate(s, m)) {
1845                 sleep(1);
1846                 astman_send_error(s, m, "Authentication failed");
1847                 return -1;
1848         }
1849         s->session->authenticated = 1;
1850         if (manager_displayconnects(s->session)) {
1851                 ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
1852         }
1853         astman_send_ack(s, m, "Authentication accepted");
1854         return 0;
1855 }
1856
1857 static int action_challenge(struct mansession *s, const struct message *m)
1858 {
1859         const char *authtype = astman_get_header(m, "AuthType");
1860
1861         if (!strcasecmp(authtype, "MD5")) {
1862                 if (ast_strlen_zero(s->session->challenge)) {
1863                         snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
1864                 }
1865                 ao2_lock(s);
1866                 astman_start_ack(s, m);
1867                 astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
1868                 ao2_unlock(s);
1869         } else {
1870                 astman_send_error(s, m, "Must specify AuthType");
1871         }
1872         return 0;
1873 }
1874
1875 static char mandescr_hangup[] =
1876 "Description: Hangup a channel\n"
1877 "Variables: \n"
1878 "       Channel: The channel name to be hungup\n"
1879 "       Cause: numeric hangup cause\n";
1880
1881 static int action_hangup(struct mansession *s, const struct message *m)
1882 {
1883         struct ast_channel *c = NULL;
1884         int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
1885         const char *name = astman_get_header(m, "Channel");
1886         const char *cause = astman_get_header(m, "Cause");
1887
1888         if (ast_strlen_zero(name)) {
1889                 astman_send_error(s, m, "No channel specified");
1890                 return 0;
1891         }
1892
1893         if (!ast_strlen_zero(cause)) {
1894                 char *endptr;
1895                 causecode = strtol(cause, &endptr, 10);
1896                 if (causecode < 0 || causecode > 127 || *endptr != '\0') {
1897                         ast_log(LOG_NOTICE, "Invalid 'Cause: %s' in manager action Hangup\n", cause);
1898                         /* keep going, better to hangup without cause than to not hang up at all */
1899                         causecode = 0; /* do not set channel's hangupcause */
1900                 }
1901         }
1902
1903         if (!(c = ast_channel_get_by_name(name))) {
1904                 astman_send_error(s, m, "No such channel");
1905                 return 0;
1906         }
1907
1908         ast_channel_lock(c);
1909         if (causecode > 0) {
1910                 ast_debug(1, "Setting hangupcause of channel %s to %d (is %d now)\n",
1911                                 c->name, causecode, c->hangupcause);
1912                 c->hangupcause = causecode;
1913         }
1914         ast_softhangup_nolock(c, AST_SOFTHANGUP_EXPLICIT);
1915         ast_channel_unlock(c);
1916
1917         c = ast_channel_unref(c);
1918
1919         astman_send_ack(s, m, "Channel Hungup");
1920
1921         return 0;
1922 }
1923
1924 static char mandescr_setvar[] =
1925 "Description: Set a global or local channel variable.\n"
1926 "Variables: (Names marked with * are required)\n"
1927 "       Channel: Channel to set variable for\n"
1928 "       *Variable: Variable name\n"
1929 "       *Value: Value\n";
1930
1931 static int action_setvar(struct mansession *s, const struct message *m)
1932 {
1933         struct ast_channel *c = NULL;
1934         const char *name = astman_get_header(m, "Channel");
1935         const char *varname = astman_get_header(m, "Variable");
1936         const char *varval = astman_get_header(m, "Value");
1937
1938         if (ast_strlen_zero(varname)) {
1939                 astman_send_error(s, m, "No variable specified");
1940                 return 0;
1941         }
1942
1943         if (!ast_strlen_zero(name)) {
1944                 if (!(c = ast_channel_get_by_name(name))) {
1945                         astman_send_error(s, m, "No such channel");
1946                         return 0;
1947                 }
1948         }
1949
1950         pbx_builtin_setvar_helper(c, varname, S_OR(varval, ""));
1951
1952         if (c) {
1953                 c = ast_channel_unref(c);
1954         }
1955
1956         astman_send_ack(s, m, "Variable Set");
1957
1958         return 0;
1959 }
1960
1961 static char mandescr_getvar[] =
1962 "Description: Get the value of a global or local channel variable.\n"
1963 "Variables: (Names marked with * are required)\n"
1964 "       Channel: Channel to read variable from\n"
1965 "       *Variable: Variable name\n"
1966 "       ActionID: Optional Action id for message matching.\n";
1967
1968 static int action_getvar(struct mansession *s, const struct message *m)
1969 {
1970         struct ast_channel *c = NULL;
1971         const char *name = astman_get_header(m, "Channel");
1972         const char *varname = astman_get_header(m, "Variable");
1973         char *varval;
1974         char workspace[1024] = "";
1975
1976         if (ast_strlen_zero(varname)) {
1977                 astman_send_error(s, m, "No variable specified");
1978                 return 0;
1979         }
1980
1981         if (!ast_strlen_zero(name)) {
1982                 if (!(c = ast_channel_get_by_name(name))) {
1983                         astman_send_error(s, m, "No such channel");
1984                         return 0;
1985                 }
1986         }
1987
1988         if (varname[strlen(varname) - 1] == ')') {
1989                 if (!c) {
1990                         c = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/manager");
1991                         if (c) {
1992                                 ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
1993                                 c = ast_channel_release(c);
1994                         } else
1995                                 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
1996                 } else {
1997                         ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
1998                 }
1999                 varval = workspace;
2000         } else {
2001                 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
2002         }
2003
2004         if (c) {
2005                 c = ast_channel_unref(c);
2006         }
2007
2008         astman_start_ack(s, m);
2009         astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, varval);
2010
2011         return 0;
2012 }
2013
2014 static char mandescr_status[] =
2015 "Description: Lists channel status along with requested channel vars.\n"
2016 "Variables: (Names marked with * are required)\n"
2017 "       *Channel: Name of the channel to query for status\n"
2018 "       Variables: Comma ',' separated list of variables to include\n"
2019 "       ActionID: Optional ID for this transaction\n"
2020 "Will return the status information of each channel along with the\n"
2021 "value for the specified channel variables.\n";
2022
2023
2024 /*! \brief Manager "status" command to show channels */
2025 /* Needs documentation... */
2026 static int action_status(struct mansession *s, const struct message *m)
2027 {
2028         const char *name = astman_get_header(m, "Channel");
2029         const char *cvariables = astman_get_header(m, "Variables");
2030         char *variables = ast_strdupa(S_OR(cvariables, ""));
2031         struct ast_channel *c;
2032         char bridge[256];
2033         struct timeval now = ast_tvnow();
2034         long elapsed_seconds = 0;
2035         int channels = 0;
2036         int all = ast_strlen_zero(name); /* set if we want all channels */
2037         const char *id = astman_get_header(m, "ActionID");
2038         char idText[256];
2039         AST_DECLARE_APP_ARGS(vars,
2040                 AST_APP_ARG(name)[100];
2041         );
2042         struct ast_str *str = ast_str_create(1000);
2043         struct ast_channel_iterator *iter = NULL;
2044
2045         if (!ast_strlen_zero(id)) {
2046                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2047         } else {
2048                 idText[0] = '\0';
2049         }
2050
2051         if (all) {
2052                 if (!(iter = ast_channel_iterator_all_new(0))) {
2053                         ast_free(str);
2054                         astman_send_error(s, m, "Memory Allocation Failure");
2055                         return 1;
2056                 }
2057                 c = ast_channel_iterator_next(iter);
2058         } else {
2059                 if (!(c = ast_channel_get_by_name(name))) {
2060                         astman_send_error(s, m, "No such channel");
2061                         ast_free(str);
2062                         return 0;
2063                 }
2064         }
2065
2066         astman_send_ack(s, m, "Channel status will follow");
2067
2068         if (!ast_strlen_zero(cvariables)) {
2069                 AST_STANDARD_APP_ARGS(vars, variables);
2070         }
2071
2072         /* if we look by name, we break after the first iteration */
2073         for (; c; c = ast_channel_iterator_next(iter)) {
2074                 ast_channel_lock(c);
2075
2076                 if (!ast_strlen_zero(cvariables)) {
2077                         int i;
2078                         ast_str_reset(str);
2079                         for (i = 0; i < vars.argc; i++) {
2080                                 char valbuf[512], *ret = NULL;
2081
2082                                 if (vars.name[i][strlen(vars.name[i]) - 1] == ')') {
2083                                         if (ast_func_read(c, vars.name[i], valbuf, sizeof(valbuf)) < 0) {
2084                                                 valbuf[0] = '\0';
2085                                         }
2086                                         ret = valbuf;
2087                                 } else {
2088                                         pbx_retrieve_variable(c, vars.name[i], &ret, valbuf, sizeof(valbuf), NULL);
2089                                 }
2090
2091                                 ast_str_append(&str, 0, "Variable: %s=%s\r\n", vars.name[i], ret);
2092                         }
2093                 }
2094
2095                 channels++;
2096                 if (c->_bridge) {
2097                         snprintf(bridge, sizeof(bridge), "BridgedChannel: %s\r\nBridgedUniqueid: %s\r\n", c->_bridge->name, c->_bridge->uniqueid);
2098                 } else {
2099                         bridge[0] = '\0';
2100                 }
2101                 if (c->pbx) {
2102                         if (c->cdr) {
2103                                 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
2104                         }
2105                         astman_append(s,
2106                         "Event: Status\r\n"
2107                         "Privilege: Call\r\n"
2108                         "Channel: %s\r\n"
2109                         "CallerIDNum: %s\r\n"
2110                         "CallerIDName: %s\r\n"
2111                         "Accountcode: %s\r\n"
2112                         "ChannelState: %d\r\n"
2113                         "ChannelStateDesc: %s\r\n"
2114                         "Context: %s\r\n"
2115                         "Extension: %s\r\n"
2116                         "Priority: %d\r\n"
2117                         "Seconds: %ld\r\n"
2118                         "%s"
2119                         "Uniqueid: %s\r\n"
2120                         "%s"
2121                         "%s"
2122                         "\r\n",
2123                         c->name,
2124                         S_OR(c->cid.cid_num, ""),
2125                         S_OR(c->cid.cid_name, ""),
2126                         c->accountcode,
2127                         c->_state,
2128                         ast_state2str(c->_state), c->context,
2129                         c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, ast_str_buffer(str), idText);
2130                 } else {
2131                         astman_append(s,
2132                                 "Event: Status\r\n"
2133                                 "Privilege: Call\r\n"
2134                                 "Channel: %s\r\n"
2135                                 "CallerIDNum: %s\r\n"
2136                                 "CallerIDName: %s\r\n"
2137                                 "Account: %s\r\n"
2138                                 "State: %s\r\n"
2139                                 "%s"
2140                                 "Uniqueid: %s\r\n"
2141                                 "%s"
2142                                 "%s"
2143                                 "\r\n",
2144                                 c->name,
2145                                 S_OR(c->cid.cid_num, "<unknown>"),
2146                                 S_OR(c->cid.cid_name, "<unknown>"),
2147                                 c->accountcode,
2148                                 ast_state2str(c->_state), bridge, c->uniqueid,
2149                                 ast_str_buffer(str), idText);
2150                 }
2151
2152                 ast_channel_unlock(c);
2153                 c = ast_channel_unref(c);
2154
2155                 if (!all) {
2156                         break;
2157                 }
2158         }
2159
2160         astman_append(s,
2161                 "Event: StatusComplete\r\n"
2162                 "%s"
2163                 "Items: %d\r\n"
2164                 "\r\n", idText, channels);
2165
2166         ast_free(str);
2167
2168         return 0;
2169 }
2170
2171 static char mandescr_sendtext[] =
2172 "Description: Sends A Text Message while in a call.\n"
2173 "Variables: (Names marked with * are required)\n"
2174 "       *Channel: Channel to send message to\n"
2175 "       *Message: Message to send\n"
2176 "       ActionID: Optional Action id for message matching.\n";
2177
2178 static int action_sendtext(struct mansession *s, const struct message *m)
2179 {
2180         struct ast_channel *c = NULL;
2181         const char *name = astman_get_header(m, "Channel");
2182         const char *textmsg = astman_get_header(m, "Message");
2183         int res = 0;
2184
2185         if (ast_strlen_zero(name)) {
2186                 astman_send_error(s, m, "No channel specified");
2187                 return 0;
2188         }
2189
2190         if (ast_strlen_zero(textmsg)) {
2191                 astman_send_error(s, m, "No Message specified");
2192                 return 0;
2193         }
2194
2195         if (!(c = ast_channel_get_by_name(name))) {
2196                 astman_send_error(s, m, "No such channel");
2197                 return 0;
2198         }
2199
2200         ast_channel_lock(c);
2201         res = ast_sendtext(c, textmsg);
2202         ast_channel_unlock(c);
2203         c = ast_channel_unref(c);
2204
2205         if (res > 0) {
2206                 astman_send_ack(s, m, "Success");
2207         } else {
2208                 astman_send_error(s, m, "Failure");
2209         }
2210
2211         return res;
2212 }
2213
2214 static char mandescr_redirect[] =
2215 "Description: Redirect (transfer) a call.\n"
2216 "Variables: (Names marked with * are required)\n"
2217 "       *Channel: Channel to redirect\n"
2218 "       ExtraChannel: Second call leg to transfer (optional)\n"
2219 "       *Exten: Extension to transfer to\n"
2220 "       *Context: Context to transfer to\n"
2221 "       *Priority: Priority to transfer to\n"
2222 "       ActionID: Optional Action id for message matching.\n";
2223
2224 /*! \brief  action_redirect: The redirect manager command */
2225 static int action_redirect(struct mansession *s, const struct message *m)
2226 {
2227         const char *name = astman_get_header(m, "Channel");
2228         const char *name2 = astman_get_header(m, "ExtraChannel");
2229         const char *exten = astman_get_header(m, "Exten");
2230         const char *context = astman_get_header(m, "Context");
2231         const char *priority = astman_get_header(m, "Priority");
2232         struct ast_channel *chan, *chan2 = NULL;
2233         int pi = 0;
2234         int res;
2235
2236         if (ast_strlen_zero(name)) {
2237                 astman_send_error(s, m, "Channel not specified");
2238                 return 0;
2239         }
2240
2241         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
2242                 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
2243                         astman_send_error(s, m, "Invalid priority");
2244                         return 0;
2245                 }
2246         }
2247
2248         if (!(chan = ast_channel_get_by_name(name))) {
2249                 char buf[256];
2250                 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
2251                 astman_send_error(s, m, buf);
2252                 return 0;
2253         }
2254
2255         if (ast_check_hangup_locked(chan)) {
2256                 astman_send_error(s, m, "Redirect failed, channel not up.");
2257                 chan = ast_channel_unref(chan);
2258                 return 0;
2259         }
2260
2261         if (!ast_strlen_zero(name2)) {
2262                 chan2 = ast_channel_get_by_name(name2);
2263         }
2264
2265         if (chan2 && ast_check_hangup_locked(chan2)) {
2266                 astman_send_error(s, m, "Redirect failed, extra channel not up.");
2267                 chan = ast_channel_unref(chan);
2268                 chan2 = ast_channel_unref(chan2);
2269                 return 0;
2270         }
2271
2272         if (chan->pbx) {
2273                 ast_channel_lock(chan);
2274                 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
2275                 ast_channel_unlock(chan);
2276         }
2277
2278         res = ast_async_goto(chan, context, exten, pi);
2279         if (!res) {
2280                 if (!ast_strlen_zero(name2)) {
2281                         if (chan2) {
2282                                 if (chan2->pbx) {
2283                                         ast_channel_lock(chan2);
2284                                         ast_set_flag(chan2, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
2285                                         ast_channel_unlock(chan2);
2286                                 }
2287                                 res = ast_async_goto(chan2, context, exten, pi);
2288                         } else {
2289                                 res = -1;
2290                         }
2291                         if (!res) {
2292                                 astman_send_ack(s, m, "Dual Redirect successful");
2293                         } else {
2294                                 astman_send_error(s, m, "Secondary redirect failed");
2295                         }
2296                 } else {
2297                         astman_send_ack(s, m, "Redirect successful");
2298                 }
2299         } else {
2300                 astman_send_error(s, m, "Redirect failed");
2301         }
2302
2303         if (chan) {
2304                 chan = ast_channel_unref(chan);
2305         }
2306
2307         if (chan2) {
2308                 chan2 = ast_channel_unref(chan2);
2309         }
2310
2311         return 0;
2312 }
2313
2314 static char mandescr_atxfer[] =
2315 "Description: Attended transfer.\n"
2316 "Variables: (Names marked with * are required)\n"
2317 "       *Channel: Transferer's channel\n"
2318 "       *Exten: Extension to transfer to\n"
2319 "       *Context: Context to transfer to\n"
2320 "       *Priority: Priority to transfer to\n"
2321 "       ActionID: Optional Action id for message matching.\n";
2322
2323 static int action_atxfer(struct mansession *s, const struct message *m)
2324 {
2325         const char *name = astman_get_header(m, "Channel");
2326         const char *exten = astman_get_header(m, "Exten");
2327         const char *context = astman_get_header(m, "Context");
2328         struct ast_channel *chan = NULL;
2329         struct ast_call_feature *atxfer_feature = NULL;
2330         char *feature_code = NULL;
2331
2332         if (ast_strlen_zero(name)) {
2333                 astman_send_error(s, m, "No channel specified");
2334                 return 0;
2335         }
2336         if (ast_strlen_zero(exten)) {
2337                 astman_send_error(s, m, "No extension specified");
2338                 return 0;
2339         }
2340
2341         if (!(atxfer_feature = ast_find_call_feature("atxfer"))) {
2342                 astman_send_error(s, m, "No attended transfer feature found");
2343                 return 0;
2344         }
2345
2346         if (!(chan = ast_channel_get_by_name(name))) {
2347                 astman_send_error(s, m, "Channel specified does not exist");
2348                 return 0;
2349         }
2350
2351         if (!ast_strlen_zero(context)) {
2352                 pbx_builtin_setvar_helper(chan, "TRANSFER_CONTEXT", context);
2353         }
2354
2355         for (feature_code = atxfer_feature->exten; feature_code && *feature_code; ++feature_code) {
2356                 struct ast_frame f = { AST_FRAME_DTMF, *feature_code };
2357                 ast_queue_frame(chan, &f);
2358         }
2359
2360         for (feature_code = (char *)exten; feature_code && *feature_code; ++feature_code) {
2361                 struct ast_frame f = { AST_FRAME_DTMF, *feature_code };
2362                 ast_queue_frame(chan, &f);
2363         }
2364
2365         chan = ast_channel_unref(chan);
2366
2367         astman_send_ack(s, m, "Atxfer successfully queued");
2368
2369         return 0;
2370 }
2371
2372 static int check_blacklist(const char *cmd)
2373 {
2374         char *cmd_copy, *cur_cmd;
2375         char *cmd_words[MAX_BLACKLIST_CMD_LEN] = { NULL, };
2376         int i;
2377
2378         cmd_copy = ast_strdupa(cmd);
2379         for (i = 0; i < MAX_BLACKLIST_CMD_LEN && (cur_cmd = strsep(&cmd_copy, " ")); i++) {
2380                 cur_cmd = ast_strip(cur_cmd);
2381                 if (ast_strlen_zero(cur_cmd)) {
2382                         i--;
2383                         continue;
2384                 }
2385
2386                 cmd_words[i] = cur_cmd;
2387         }
2388
2389         for (i = 0; i < ARRAY_LEN(command_blacklist); i++) {
2390                 int j, match = 1;
2391
2392                 for (j = 0; command_blacklist[i].words[j]; j++) {
2393                         if (ast_strlen_zero(cmd_words[j]) || strcasecmp(cmd_words[j], command_blacklist[i].words[j])) {
2394                                 match = 0;
2395                                 break;
2396                         }
2397                 }
2398
2399                 if (match) {
2400                         return 1;
2401                 }
2402         }
2403
2404         return 0;
2405 }
2406
2407 static char mandescr_command[] =
2408 "Description: Run a CLI command.\n"
2409 "Variables: (Names marked with * are required)\n"
2410 "       *Command: Asterisk CLI command to run\n"
2411 "       ActionID: Optional Action id for message matching.\n";
2412
2413 /*! \brief  Manager command "command" - execute CLI command */
2414 static int action_command(struct mansession *s, const struct message *m)
2415 {
2416         const char *cmd = astman_get_header(m, "Command");
2417         const char *id = astman_get_header(m, "ActionID");
2418         char *buf, *final_buf;
2419         char template[] = "/tmp/ast-ami-XXXXXX";        /* template for temporary file */
2420         int fd = mkstemp(template);
2421         off_t l;
2422
2423         if (ast_strlen_zero(cmd)) {
2424                 astman_send_error(s, m, "No command provided");
2425                 return 0;
2426         }
2427
2428         if (check_blacklist(cmd)) {
2429                 astman_send_error(s, m, "Command blacklisted");
2430                 return 0;
2431         }
2432
2433         astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
2434         if (!ast_strlen_zero(id)) {
2435                 astman_append(s, "ActionID: %s\r\n", id);
2436         }
2437         /* FIXME: Wedge a ActionID response in here, waiting for later changes */
2438         ast_cli_command(fd, cmd);       /* XXX need to change this to use a FILE * */
2439         l = lseek(fd, 0, SEEK_END);     /* how many chars available */
2440
2441         /* This has a potential to overflow the stack.  Hence, use the heap. */
2442         buf = ast_calloc(1, l + 1);
2443         final_buf = ast_calloc(1, l + 1);
2444         if (buf) {
2445                 lseek(fd, 0, SEEK_SET);
2446                 if (read(fd, buf, l) < 0) {
2447                         ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
2448                 }
2449                 buf[l] = '\0';
2450                 if (final_buf) {
2451                         term_strip(final_buf, buf, l);
2452                         final_buf[l] = '\0';
2453                 }
2454                 astman_append(s, "%s", S_OR(final_buf, buf));
2455                 ast_free(buf);
2456         }
2457         close(fd);
2458         unlink(template);
2459         astman_append(s, "--END COMMAND--\r\n\r\n");
2460         if (final_buf) {
2461                 ast_free(final_buf);
2462         }
2463         return 0;
2464 }
2465
2466 /*! \brief helper function for originate */
2467 struct fast_originate_helper {
2468         char tech[AST_MAX_EXTENSION];
2469         /*! data can contain a channel name, extension number, username, password, etc. */
2470         char data[512];
2471         int timeout;
2472         int format;                             /*!< Codecs used for a call */
2473         char app[AST_MAX_APP];
2474         char appdata[AST_MAX_EXTENSION];
2475         char cid_name[AST_MAX_EXTENSION];
2476         char cid_num[AST_MAX_EXTENSION];
2477         char context[AST_MAX_CONTEXT];
2478         char exten[AST_MAX_EXTENSION];
2479         char idtext[AST_MAX_EXTENSION];
2480         char account[AST_MAX_ACCOUNT_CODE];
2481         int priority;
2482         struct ast_variable *vars;
2483 };
2484
2485 static void *fast_originate(void *data)
2486 {
2487         struct fast_originate_helper *in = data;
2488         int res;
2489         int reason = 0;
2490         struct ast_channel *chan = NULL;
2491         char requested_channel[AST_CHANNEL_NAME];
2492
2493         if (!ast_strlen_zero(in->app)) {
2494                 res = ast_pbx_outgoing_app(in->tech, in->format, in->data, in->timeout, in->app, in->appdata, &reason, 1,
2495                         S_OR(in->cid_num, NULL),
2496                         S_OR(in->cid_name, NULL),
2497                         in->vars, in->account, &chan);
2498         } else {
2499                 res = ast_pbx_outgoing_exten(in->tech, in->format, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
2500                         S_OR(in->cid_num, NULL),
2501                         S_OR(in->cid_name, NULL),
2502                         in->vars, in->account, &chan);
2503         }
2504
2505         if (!chan) {
2506                 snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
2507         }
2508         /* Tell the manager what happened with the channel */
2509         manager_event(EVENT_FLAG_CALL, "OriginateResponse",
2510                 "%s%s"
2511                 "Response: %s\r\n"
2512                 "Channel: %s\r\n"
2513                 "Context: %s\r\n"
2514                 "Exten: %s\r\n"
2515                 "Reason: %d\r\n"
2516                 "Uniqueid: %s\r\n"
2517                 "CallerIDNum: %s\r\n"
2518                 "CallerIDName: %s\r\n",
2519                 in->idtext, ast_strlen_zero(in->idtext) ? "" : "\r\n", res ? "Failure" : "Success",
2520                 chan ? chan->name : requested_channel, in->context, in->exten, reason,
2521                 chan ? chan->uniqueid : "<null>",
2522                 S_OR(in->cid_num, "<unknown>"),
2523                 S_OR(in->cid_name, "<unknown>")
2524                 );
2525
2526         /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
2527         if (chan) {
2528                 ast_channel_unlock(chan);
2529         }
2530         ast_free(in);
2531         return NULL;
2532 }
2533
2534 static char mandescr_originate[] =
2535 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
2536 "  Application/Data\n"
2537 "Variables: (Names marked with * are required)\n"
2538 "       *Channel: Channel name to call\n"
2539 "       Exten: Extension to use (requires 'Context' and 'Priority')\n"
2540 "       Context: Context to use (requires 'Exten' and 'Priority')\n"
2541 "       Priority: Priority to use (requires 'Exten' and 'Context')\n"
2542 "       Application: Application to use\n"
2543 "       Data: Data to use (requires 'Application')\n"
2544 "       Timeout: How long to wait for call to be answered (in ms)\n"
2545 "       CallerID: Caller ID to be set on the outgoing channel\n"
2546 "       Variable: Channel variable to set, multiple Variable: headers are allowed\n"
2547 "       Account: Account code\n"
2548 "       Async: Set to 'true' for fast origination\n";
2549
2550 static int action_originate(struct mansession *s, const struct message *m)
2551 {
2552         const char *name = astman_get_header(m, "Channel");
2553         const char *exten = astman_get_header(m, "Exten");
2554         const char *context = astman_get_header(m, "Context");
2555         const char *priority = astman_get_header(m, "Priority");
2556         const char *timeout = astman_get_header(m, "Timeout");
2557         const char *callerid = astman_get_header(m, "CallerID");
2558         const char *account = astman_get_header(m, "Account");
2559         const char *app = astman_get_header(m, "Application");
2560         const char *appdata = astman_get_header(m, "Data");
2561         const char *async = astman_get_header(m, "Async");
2562         const char *id = astman_get_header(m, "ActionID");
2563         const char *codecs = astman_get_header(m, "Codecs");
2564         struct ast_variable *vars = astman_get_variables(m);
2565         char *tech, *data;
2566         char *l = NULL, *n = NULL;
2567         int pi = 0;
2568         int res;
2569         int to = 30000;
2570         int reason = 0;
2571         char tmp[256];
2572         char tmp2[256];
2573         int format = AST_FORMAT_SLINEAR;
2574
2575         pthread_t th;
2576         if (ast_strlen_zero(name)) {
2577                 astman_send_error(s, m, "Channel not specified");
2578                 return 0;
2579         }
2580         if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
2581                 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
2582                         astman_send_error(s, m, "Invalid priority");
2583                         return 0;
2584                 }
2585         }
2586         if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
2587                 astman_send_error(s, m, "Invalid timeout");
2588                 return 0;
2589         }
2590         ast_copy_string(tmp, name, sizeof(tmp));
2591         tech = tmp;
2592         data = strchr(tmp, '/');
2593         if (!data) {
2594                 astman_send_error(s, m, "Invalid channel");
2595                 return 0;
2596         }
2597         *data++ = '\0';
2598         ast_copy_string(tmp2, callerid, sizeof(tmp2));
2599         ast_callerid_parse(tmp2, &n, &l);
2600         if (n) {
2601                 if (ast_strlen_zero(n)) {
2602                         n = NULL;
2603                 }
2604         }
2605         if (l) {
2606                 ast_shrink_phone_number(l);
2607                 if (ast_strlen_zero(l)) {
2608                         l = NULL;
2609                 }
2610         }
2611         if (!ast_strlen_zero(codecs)) {
2612                 format = 0;
2613                 ast_parse_allow_disallow(NULL, &format, codecs, 1);
2614         }
2615         if (ast_true(async)) {
2616                 struct fast_originate_helper *fast = ast_calloc(1, sizeof(*fast));
2617                 if (!fast) {
2618                         res = -1;
2619                 } else {
2620                         if (!ast_strlen_zero(id))
2621                                 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s", id);
2622                         ast_copy_string(fast->tech, tech, sizeof(fast->tech));
2623                         ast_copy_string(fast->data, data, sizeof(fast->data));
2624                         ast_copy_string(fast->app, app, sizeof(fast->app));
2625                         ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
2626                         if (l) {
2627                                 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
2628                         }
2629                         if (n) {
2630                                 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
2631                         }
2632                         fast->vars = vars;
2633                         ast_copy_string(fast->context, context, sizeof(fast->context));
2634                         ast_copy_string(fast->exten, exten, sizeof(fast->exten));
2635                         ast_copy_string(fast->account, account, sizeof(fast->account));
2636                         fast->format = format;
2637                         fast->timeout = to;
2638                         fast->priority = pi;
2639                         if (ast_pthread_create_detached(&th, NULL, fast_originate, fast)) {
2640                                 ast_free(fast);
2641                                 res = -1;
2642                         } else {
2643                                 res = 0;
2644                         }
2645                 }
2646         } else if (!ast_strlen_zero(app)) {
2647                 /* To run the System application (or anything else that goes to shell), you must have the additional System privilege */
2648                 if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
2649                         && (
2650                                 strcasestr(app, "system") == 0 || /* System(rm -rf /)
2651                                                                      TrySystem(rm -rf /)       */
2652                                 strcasestr(app, "exec") ||        /* Exec(System(rm -rf /))
2653                                                                      TryExec(System(rm -rf /)) */
2654                                 strcasestr(app, "agi") ||         /* AGI(/bin/rm,-rf /)
2655                                                                      EAGI(/bin/rm,-rf /)       */
2656                                 strstr(appdata, "SHELL") ||       /* NoOp(${SHELL(rm -rf /)})  */
2657                                 strstr(appdata, "EVAL")           /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
2658                                 )) {
2659                         astman_send_error(s, m, "Originate with certain 'Application' arguments requires the additional System privilege, which you do not have.");
2660                         return 0;
2661                 }
2662                 res = ast_pbx_outgoing_app(tech, format, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
2663         } else {
2664                 if (exten && context && pi) {
2665                         res = ast_pbx_outgoing_exten(tech, format, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
2666                 } else {
2667                         astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
2668                         return 0;
2669                 }
2670         }
2671         if (!res) {
2672                 astman_send_ack(s, m, "Originate successfully queued");
2673         } else {
2674                 astman_send_error(s, m, "Originate failed");
2675         }
2676         return 0;
2677 }
2678
2679 /*! \brief Help text for manager command mailboxstatus
2680  */
2681 static char mandescr_mailboxstatus[] =
2682 "Description: Checks a voicemail account for status.\n"
2683 "Variables: (Names marked with * are required)\n"
2684 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
2685 "       ActionID: Optional ActionID for message matching.\n"
2686 "Returns number of messages.\n"
2687 "       Message: Mailbox Status\n"
2688 "       Mailbox: <mailboxid>\n"
2689 "       Waiting: <count>\n"
2690 "\n";
2691
2692 static int action_mailboxstatus(struct mansession *s, const struct message *m)
2693 {
2694         const char *mailbox = astman_get_header(m, "Mailbox");
2695         int ret;
2696
2697         if (ast_strlen_zero(mailbox)) {
2698                 astman_send_error(s, m, "Mailbox not specified");
2699                 return 0;
2700         }
2701         ret = ast_app_has_voicemail(mailbox, NULL);
2702         astman_start_ack(s, m);
2703         astman_append(s, "Message: Mailbox Status\r\n"
2704                          "Mailbox: %s\r\n"
2705                          "Waiting: %d\r\n\r\n", mailbox, ret);
2706         return 0;
2707 }
2708
2709 static char mandescr_mailboxcount[] =
2710 "Description: Checks a voicemail account for new messages.\n"
2711 "Variables: (Names marked with * are required)\n"
2712 "       *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
2713 "       ActionID: Optional ActionID for message matching.\n"
2714 "Returns number of urgent, new and old messages.\n"
2715 "       Message: Mailbox Message Count\n"
2716 "       Mailbox: <mailboxid>\n"
2717 "       UrgentMessages: <count>\n"
2718 "       NewMessages: <count>\n"
2719 "       OldMessages: <count>\n"
2720 "\n";
2721 static int action_mailboxcount(struct mansession *s, const struct message *m)
2722 {
2723         const char *mailbox = astman_get_header(m, "Mailbox");
2724         int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;;
2725
2726         if (ast_strlen_zero(mailbox)) {
2727                 astman_send_error(s, m, "Mailbox not specified");
2728                 return 0;
2729         }
2730         ast_app_inboxcount2(mailbox, &urgentmsgs, &newmsgs, &oldmsgs);
2731         astman_start_ack(s, m);
2732         astman_append(s,   "Message: Mailbox Message Count\r\n"
2733                            "Mailbox: %s\r\n"
2734                            "UrgMessages: %d\r\n"
2735                            "NewMessages: %d\r\n"
2736                            "OldMessages: %d\r\n"
2737                            "\r\n",
2738                            mailbox, urgentmsgs, newmsgs, oldmsgs);
2739         return 0;
2740 }
2741
2742 static char mandescr_extensionstate[] =
2743 "Description: Report the extension state for given extension.\n"
2744 "  If the extension has a hint, will use devicestate to check\n"
2745 "  the status of the device connected to the extension.\n"
2746 "Variables: (Names marked with * are required)\n"
2747 "       *Exten: Extension to check state on\n"
2748 "       *Context: Context for extension\n"
2749 "       ActionId: Optional ID for this transaction\n"
2750 "Will return an \"Extension Status\" message.\n"
2751 "The response will include the hint for the extension and the status.\n";
2752
2753 static int action_extensionstate(struct mansession *s, const struct message *m)
2754 {
2755         const char *exten = astman_get_header(m, "Exten");
2756         const char *context = astman_get_header(m, "Context");
2757         char hint[256] = "";
2758         int status;
2759         if (ast_strlen_zero(exten)) {
2760                 astman_send_error(s, m, "Extension not specified");
2761                 return 0;
2762         }
2763         if (ast_strlen_zero(context)) {
2764                 context = "default";
2765         }
2766         status = ast_extension_state(NULL, context, exten);
2767         ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
2768         astman_start_ack(s, m);
2769         astman_append(s,   "Message: Extension Status\r\n"
2770                            "Exten: %s\r\n"
2771                            "Context: %s\r\n"
2772                            "Hint: %s\r\n"
2773                            "Status: %d\r\n\r\n",
2774                            exten, context, hint, status);
2775         return 0;
2776 }
2777
2778 static char mandescr_timeout[] =
2779 "Description: Hangup a channel after a certain time.\n"
2780 "Variables: (Names marked with * are required)\n"
2781 "       *Channel: Channel name to hangup\n"
2782 "       *Timeout: Maximum duration of the call (sec)\n"
2783 "Acknowledges set time with 'Timeout Set' message\n";
2784
2785 static int action_timeout(struct mansession *s, const struct message *m)
2786 {
2787         struct ast_channel *c;
2788         const char *name = astman_get_header(m, "Channel");
2789         double timeout = atof(astman_get_header(m, "Timeout"));
2790         struct timeval when = { timeout, 0 };
2791
2792         if (ast_strlen_zero(name)) {
2793                 astman_send_error(s, m, "No channel specified");
2794                 return 0;
2795         }
2796
2797         if (!timeout || timeout < 0) {
2798                 astman_send_error(s, m, "No timeout specified");
2799                 return 0;
2800         }
2801
2802         if (!(c = ast_channel_get_by_name(name))) {
2803                 astman_send_error(s, m, "No such channel");
2804                 return 0;
2805         }
2806
2807         when.tv_usec = (timeout - when.tv_sec) * 1000000.0;
2808
2809         ast_channel_lock(c);
2810         ast_channel_setwhentohangup_tv(c, when);
2811         ast_channel_unlock(c);
2812         c = ast_channel_unref(c);
2813
2814         astman_send_ack(s, m, "Timeout Set");
2815
2816         return 0;
2817 }
2818
2819 /*!
2820  * Send any applicable events to the client listening on this socket.
2821  * Wait only for a finite time on each event, and drop all events whether
2822  * they are successfully sent or not.
2823  */
2824 static int process_events(struct mansession *s)
2825 {
2826         int ret = 0;
2827
2828         ao2_lock(s->session);
2829         if (s->session->f != NULL) {
2830                 struct eventqent *eqe;
2831
2832                 while ( (eqe = NEW_EVENT(s)) ) {
2833                         ref_event(eqe);
2834                         if (!ret && s->session->authenticated &&
2835                             (s->session->readperm & eqe->category) == eqe->category &&
2836                             (s->session->send_events & eqe->category) == eqe->category) {
2837                                 if (send_string(s, eqe->eventdata) < 0)
2838                                         ret = -1;       /* don't send more */
2839                         }
2840                         s->session->last_ev = unref_event(s->session->last_ev);
2841                 }
2842         }
2843         ao2_unlock(s->session);
2844         return ret;
2845 }
2846
2847 static char mandescr_userevent[] =
2848 "Description: Send an event to manager sessions.\n"
2849 "Variables: (Names marked with * are required)\n"
2850 "       *UserEvent: EventStringToSend\n"
2851 "       Header1: Content1\n"
2852 "       HeaderN: ContentN\n";
2853
2854 static int action_userevent(struct mansession *s, const struct message *m)
2855 {
2856         const char *event = astman_get_header(m, "UserEvent");
2857         struct ast_str *body = ast_str_thread_get(&userevent_buf, 16);
2858         int x;
2859
2860         ast_str_reset(body);
2861
2862         for (x = 0; x < m->hdrcount; x++) {
2863                 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
2864                         ast_str_append(&body, 0, "%s\r\n", m->headers[x]);
2865                 }
2866         }
2867
2868         manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, ast_str_buffer(body));
2869         return 0;
2870 }
2871
2872 static char mandescr_coresettings[] =
2873 "Description: Query for Core PBX settings.\n"
2874 "Variables: (Names marked with * are optional)\n"
2875 "       *ActionID: ActionID of this transaction\n";
2876
2877 /*! \brief Show PBX core settings information */
2878 static int action_coresettings(struct mansession *s, const struct message *m)
2879 {
2880         const char *actionid = astman_get_header(m, "ActionID");
2881         char idText[150];
2882
2883         if (!ast_strlen_zero(actionid)) {
2884                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
2885         } else {
2886                 idText[0] = '\0';
2887         }
2888
2889         astman_append(s, "Response: Success\r\n"
2890                         "%s"
2891                         "AMIversion: %s\r\n"
2892                         "AsteriskVersion: %s\r\n"
2893                         "SystemName: %s\r\n"
2894                         "CoreMaxCalls: %d\r\n"
2895                         "CoreMaxLoadAvg: %f\r\n"
2896                         "CoreRunUser: %s\r\n"
2897                         "CoreRunGroup: %s\r\n"
2898                         "CoreMaxFilehandles: %d\r\n"
2899                         "CoreRealTimeEnabled: %s\r\n"
2900                         "CoreCDRenabled: %s\r\n"
2901                         "CoreHTTPenabled: %s\r\n"
2902                         "\r\n",
2903                         idText,
2904                         AMI_VERSION,
2905                         ast_get_version(),
2906                         ast_config_AST_SYSTEM_NAME,
2907                         option_maxcalls,
2908                         option_maxload,
2909                         ast_config_AST_RUN_USER,
2910                         ast_config_AST_RUN_GROUP,
2911                         option_maxfiles,
2912                         ast_realtime_enabled() ? "Yes" : "No",
2913                         check_cdr_enabled() ? "Yes" : "No",
2914                         check_webmanager_enabled() ? "Yes" : "No"
2915                         );
2916         return 0;
2917 }
2918
2919 static char mandescr_corestatus[] =
2920 "Description: Query for Core PBX status.\n"
2921 "Variables: (Names marked with * are optional)\n"
2922 "       *ActionID: ActionID of this transaction\n";
2923
2924 /*! \brief Show PBX core status information */
2925 static int action_corestatus(struct mansession *s, const struct message *m)
2926 {
2927         const char *actionid = astman_get_header(m, "ActionID");
2928         char idText[150];
2929         char startuptime[150];
2930         char reloadtime[150];
2931         struct ast_tm tm;
2932
2933         if (!ast_strlen_zero(actionid)) {
2934                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
2935         } else {
2936                 idText[0] = '\0';
2937         }
2938
2939         ast_localtime(&ast_startuptime, &tm, NULL);
2940         ast_strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
2941         ast_localtime(&ast_lastreloadtime, &tm, NULL);
2942         ast_strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
2943
2944         astman_append(s, "Response: Success\r\n"
2945                         "%s"
2946                         "CoreStartupTime: %s\r\n"
2947                         "CoreReloadTime: %s\r\n"
2948                         "CoreCurrentCalls: %d\r\n"
2949                         "\r\n",
2950                         idText,
2951                         startuptime,
2952                         reloadtime,
2953                         ast_active_channels()
2954                         );
2955         return 0;
2956 }
2957
2958 static char mandescr_reload[] =
2959 "Description: Send a reload event.\n"
2960 "Variables: (Names marked with * are optional)\n"
2961 "       *ActionID: ActionID of this transaction\n"
2962 "       *Module: Name of the module to reload\n";
2963
2964 /*! \brief Send a reload event */
2965 static int action_reload(struct mansession *s, const struct message *m)
2966 {
2967         const char *module = astman_get_header(m, "Module");
2968         int res = ast_module_reload(S_OR(module, NULL));
2969
2970         if (res == 2) {
2971                 astman_send_ack(s, m, "Module Reloaded");
2972         } else {
2973                 astman_send_error(s, m, s == 0 ? "No such module" : "Module does not support reload");
2974         }
2975         return 0;
2976 }
2977
2978 static char mandescr_coreshowchannels[] =
2979 "Description: List currently defined channels and some information\n"
2980 "             about them.\n"
2981 "Variables:\n"
2982 "          ActionID: Optional Action id for message matching.\n";
2983
2984 /*! \brief  Manager command "CoreShowChannels" - List currently defined channels
2985  *          and some information about them. */
2986 static int action_coreshowchannels(struct mansession *s, const struct message *m)
2987 {
2988         const char *actionid = astman_get_header(m, "ActionID");
2989         char actionidtext[256];
2990         struct ast_channel *c = NULL;
2991         int numchans = 0;
2992         int duration, durh, durm, durs;
2993         struct ast_channel_iterator *iter;
2994
2995         if (!ast_strlen_zero(actionid)) {
2996                 snprintf(actionidtext, sizeof(actionidtext), "ActionID: %s\r\n", actionid);
2997         } else {
2998                 actionidtext[0] = '\0';
2999         }
3000
3001         if (!(iter = ast_channel_iterator_all_new(0))) {
3002                 astman_send_error(s, m, "Memory Allocation Failure");
3003                 return 1;
3004         }
3005
3006         astman_send_listack(s, m, "Channels will follow", "start");
3007
3008         for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
3009                 struct ast_channel *bc;
3010                 char durbuf[10] = "";
3011
3012                 ast_channel_lock(c);
3013
3014                 bc = ast_bridged_channel(c);
3015                 if (c->cdr && !ast_tvzero(c->cdr->start)) {
3016                         duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
3017                         durh = duration / 3600;
3018                         durm = (duration % 3600) / 60;
3019                         durs = duration % 60;
3020                         snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
3021                 }
3022
3023                 astman_append(s,
3024                         "Event: CoreShowChannel\r\n"
3025                         "Channel: %s\r\n"
3026                         "UniqueID: %s\r\n"
3027                         "Context: %s\r\n"
3028                         "Extension: %s\r\n"
3029                         "Priority: %d\r\n"
3030                         "ChannelState: %d\r\n"
3031                         "ChannelStateDesc: %s\r\n"
3032                         "Application: %s\r\n"
3033                         "ApplicationData: %s\r\n"
3034                         "CallerIDnum: %s\r\n"
3035                         "Duration: %s\r\n"
3036                         "AccountCode: %s\r\n"
3037                         "BridgedChannel: %s\r\n"
3038                         "BridgedUniqueID: %s\r\n"
3039                         "\r\n", c->name, c->uniqueid, c->context, c->exten, c->priority, c->_state, ast_state2str(c->_state),
3040                         c->appl ? c->appl : "", c->data ? S_OR(c->data, ""): "",
3041                         S_OR(c->cid.cid_num, ""), durbuf, S_OR(c->accountcode, ""), bc ? bc->name : "", bc ? bc->uniqueid : "");
3042
3043                 ast_channel_unlock(c);
3044
3045                 numchans++;
3046         }
3047
3048         astman_append(s,
3049                 "Event: CoreShowChannelsComplete\r\n"
3050                 "EventList: Complete\r\n"
3051                 "ListItems: %d\r\n"
3052                 "%s"
3053                 "\r\n", numchans, actionidtext);
3054
3055         ast_channel_iterator_destroy(iter);
3056
3057         return 0;
3058 }
3059
3060 static char mandescr_modulecheck[] =
3061 "Description: Checks if Asterisk module is loaded\n"
3062 "Variables: \n"
3063 "  ActionID: <id>          Action ID for this transaction. Will be returned.\n"
3064 "  Module: <name>          Asterisk module name (not including extension)\n"
3065 "\n"
3066 "Will return Success/Failure\n"
3067 "For success returns, the module revision number is included.\n";
3068
3069 /* Manager function to check if module is loaded */
3070 static int manager_modulecheck(struct mansession *s, const struct message *m)
3071 {
3072         int res;
3073         const char *module = astman_get_header(m, "Module");
3074         const char *id = astman_get_header(m, "ActionID");
3075         char idText[256];
3076 #if !defined(LOW_MEMORY)
3077         const char *version;
3078 #endif
3079         char filename[PATH_MAX];
3080         char *cut;
3081
3082         ast_copy_string(filename, module, sizeof(filename));
3083         if ((cut = strchr(filename, '.'))) {
3084                 *cut = '\0';
3085         } else {
3086                 cut = filename + strlen(filename);
3087         }
3088         snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".so");
3089         ast_log(LOG_DEBUG, "**** ModuleCheck .so file %s\n", filename);
3090         res = ast_module_check(filename);
3091         if (!res) {
3092                 astman_send_error(s, m, "Module not loaded");
3093                 return 0;
3094         }
3095         snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".c");
3096         ast_log(LOG_DEBUG, "**** ModuleCheck .c file %s\n", filename);
3097 #if !defined(LOW_MEMORY)
3098         version = ast_file_version_find(filename);
3099 #endif
3100
3101         if (!ast_strlen_zero(id)) {
3102                 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
3103         } else {
3104                 idText[0] = '\0';
3105         }
3106         astman_append(s, "Response: Success\r\n%s", idText);
3107 #if !defined(LOW_MEMORY)
3108         astman_append(s, "Version: %s\r\n\r\n", version ? version : "");
3109 #endif
3110         return 0;
3111 }
3112
3113 static char mandescr_moduleload[] =
3114 "Description: Loads, unloads or reloads an Asterisk module in a running system.\n"
3115 "Variables: \n"
3116 "  ActionID: <id>          Action ID for this transaction. Will be returned.\n"
3117 "  Module: <name>          Asterisk module name (including .so extension)\n"
3118 "                          or subsystem identifier:\n"
3119 "                               cdr, enum, dnsmgr, extconfig, manager, rtp, http\n"
3120 "  LoadType: load | unload | reload\n"
3121 "                          The operation to be done on module\n"
3122 " If no module is specified for a reload loadtype, all modules are reloaded";
3123
3124 static int manager_moduleload(struct mansession *s, const struct message *m)
3125 {
3126         int res;
3127         const char *module = astman_get_header(m, "Module");
3128         const char *loadtype = astman_get_header(m, "LoadType");
3129
3130         if (!loadtype || strlen(loadtype) == 0) {
3131                 astman_send_error(s, m, "Incomplete ModuleLoad action.");
3132         }
3133         if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0) {
3134                 astman_send_error(s, m, "Need module name");
3135         }
3136
3137         if (!strcasecmp(loadtype, "load")) {
3138                 res = ast_load_resource(module);
3139                 if (res) {
3140                         astman_send_error(s, m, "Could not load module.");
3141                 } else {
3142                         astman_send_ack(s, m, "Module loaded.");
3143                 }
3144         } else if (!strcasecmp(loadtype, "unload")) {
3145                 res = ast_unload_resource(module, AST_FORCE_SOFT);
3146                 if (res) {
3147                         astman_send_error(s, m, "Could not unload module.");
3148                 } else {
3149                         astman_send_ack(s, m, "Module unloaded.");
3150                 }
3151         } else if (!strcasecmp(loadtype, "reload")) {
3152                 if (module != NULL) {
3153                         res = ast_module_reload(module);
3154                         if (res == 0) {
3155                                 astman_send_error(s, m, "No such module.");
3156                         } else if (res == 1) {
3157                                 astman_send_error(s, m, "Module does not support reload action.");
3158                         } else {
3159                                 astman_send_ack(s, m, "Module reloaded.");
3160                         }
3161                 } else {
3162                         ast_module_reload(NULL);        /* Reload all modules */
3163                         astman_send_ack(s, m, "All modules reloaded");
3164                 }
3165         } else
3166                 astman_send_error(s, m, "Incomplete ModuleLoad action.");
3167         return 0;
3168 }
3169
3170 /*
3171  * Done with the action handlers here, we start with the code in charge
3172  * of accepting connections and serving them.
3173  * accept_thread() forks a new thread for each connection, session_do(),
3174  * which in turn calls get_input() repeatedly until a full message has
3175  * been accumulated, and then invokes process_message() to pass it to
3176  * the appropriate handler.
3177  */
3178
3179 /*
3180  * Process an AMI message, performing desired action.
3181  * Return 0 on success, -1 on error that require the session to be destroyed.
3182  */
3183 static int process_message(struct mansession *s, const struct message *m)
3184 {
3185         char action[80] = "";
3186         int ret = 0;
3187         struct manager_action *tmp;
3188         const char *user = astman_get_header(m, "Username");
3189         int (*call_func)(struct mansession *s, const struct message *m) = NULL;
3190
3191         ast_copy_string(action, __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY), sizeof(action));
3192
3193         if (ast_strlen_zero(action)) {
3194                 ao2_lock(s);
3195                 astman_send_error(s, m, "Missing action in request");
3196                 ao2_unlock(s);
3197                 return 0;
3198         }
3199
3200         if (!s->session->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") && strcasecmp(action, "Challenge")) {
3201                 ao2_lock(s);
3202                 astman_send_error(s, m, "Permission denied");
3203                 ao2_unlock(s);
3204                 return 0;
3205         }
3206
3207         if (!allowmultiplelogin && !s->session->authenticated && user &&
3208                 (!strcasecmp(action, "Login") || !strcasecmp(action, "Challenge"))) {
3209                 if (check_manager_session_inuse(user)) {
3210                         sleep(1);
3211                         ao2_lock(s);
3212                         astman_send_error(s, m, "Login Already In Use");
3213                         ao2_unlock(s);
3214                         return -1;
3215                 }
3216         }
3217
3218         AST_RWLIST_RDLOCK(&actions);
3219         AST_RWLIST_TRAVERSE(&actions, tmp, list) {
3220                 if (strcasecmp(action, tmp->action)) {
3221                         continue;
3222                 }
3223                 if (s->session->writeperm & tmp->authority || tmp->authority == 0) {
3224                         call_func = tmp->func;
3225                 } else {
3226                         astman_send_error(s, m, "Permission denied");
3227                         tmp = NULL;
3228                 }
3229                 break;
3230         }
3231         AST_RWLIST_UNLOCK(&actions);
3232
3233         if (tmp && call_func) {
3234                 /* call AMI function after actions list are unlocked */
3235                 ast_debug(1, "Running action '%s'\n", tmp->action);
3236                 ret = call_func(s, m);
3237         } else {
3238                 char buf[512];
3239                 snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
3240                 ao2_lock(s);
3241                 astman_send_error(s, m, buf);
3242                 ao2_unlock(s);
3243         }
3244         if (ret) {