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