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