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