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