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