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