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