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