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