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