Asterisk - The Open Source Telephony Project  GIT-master-932eae6
manager.c
Go to the documentation of this file.
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  * 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 /*! \li \ref manager.c uses the configuration file \ref manager.conf and \ref users.conf
40  * \addtogroup configuration_file
41  */
42 
43 /*! \page manager.conf manager.conf
44  * \verbinclude manager.conf.sample
45  */
46 
47 /*! \page users.conf users.conf
48  * \verbinclude users.conf.sample
49  */
50 
51 /*** MODULEINFO
52  <support_level>core</support_level>
53  ***/
54 
55 #include "asterisk.h"
56 
57 #include "asterisk/paths.h" /* use various ast_config_AST_* */
58 #include <ctype.h>
59 #include <sys/time.h>
60 #include <signal.h>
61 #include <sys/mman.h>
62 #include <sys/types.h>
63 #include <regex.h>
64 
65 #include "asterisk/channel.h"
66 #include "asterisk/file.h"
67 #include "asterisk/manager.h"
68 #include "asterisk/module.h"
69 #include "asterisk/config.h"
70 #include "asterisk/callerid.h"
71 #include "asterisk/lock.h"
72 #include "asterisk/cli.h"
73 #include "asterisk/app.h"
74 #include "asterisk/mwi.h"
75 #include "asterisk/pbx.h"
76 #include "asterisk/md5.h"
77 #include "asterisk/acl.h"
78 #include "asterisk/utils.h"
79 #include "asterisk/tcptls.h"
80 #include "asterisk/http.h"
81 #include "asterisk/ast_version.h"
82 #include "asterisk/threadstorage.h"
83 #include "asterisk/linkedlists.h"
84 #include "asterisk/term.h"
85 #include "asterisk/astobj2.h"
86 #include "asterisk/features.h"
88 #include "asterisk/aoc.h"
89 #include "asterisk/strings.h"
90 #include "asterisk/stringfields.h"
91 #include "asterisk/presencestate.h"
95 #include "asterisk/test.h"
96 #include "asterisk/json.h"
97 #include "asterisk/bridge.h"
99 #include "asterisk/rtp_engine.h"
100 #include "asterisk/format_cache.h"
101 #include "asterisk/translate.h"
102 #include "asterisk/taskprocessor.h"
103 #include "asterisk/message.h"
104 
105 /*** DOCUMENTATION
106  <manager name="Ping" language="en_US">
107  <synopsis>
108  Keepalive command.
109  </synopsis>
110  <syntax>
111  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
112  </syntax>
113  <description>
114  <para>A 'Ping' action will ellicit a 'Pong' response. Used to keep the
115  manager connection open.</para>
116  </description>
117  </manager>
118  <manager name="Events" language="en_US">
119  <synopsis>
120  Control Event Flow.
121  </synopsis>
122  <syntax>
123  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
124  <parameter name="EventMask" required="true">
125  <enumlist>
126  <enum name="on">
127  <para>If all events should be sent.</para>
128  </enum>
129  <enum name="off">
130  <para>If no events should be sent.</para>
131  </enum>
132  <enum name="system,call,log,...">
133  <para>To select which flags events should have to be sent.</para>
134  </enum>
135  </enumlist>
136  </parameter>
137  </syntax>
138  <description>
139  <para>Enable/Disable sending of events to this manager client.</para>
140  </description>
141  </manager>
142  <manager name="Logoff" language="en_US">
143  <synopsis>
144  Logoff Manager.
145  </synopsis>
146  <syntax>
147  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
148  </syntax>
149  <description>
150  <para>Logoff the current manager session.</para>
151  </description>
152  <see-also>
153  <ref type="manager">Login</ref>
154  </see-also>
155  </manager>
156  <manager name="Login" language="en_US">
157  <synopsis>
158  Login Manager.
159  </synopsis>
160  <syntax>
161  <parameter name="ActionID">
162  <para>ActionID for this transaction. Will be returned.</para>
163  </parameter>
164  <parameter name="Username" required="true">
165  <para>Username to login with as specified in manager.conf.</para>
166  </parameter>
167  <parameter name="Secret">
168  <para>Secret to login with as specified in manager.conf.</para>
169  </parameter>
170  </syntax>
171  <description>
172  <para>Login Manager.</para>
173  </description>
174  <see-also>
175  <ref type="manager">Logoff</ref>
176  </see-also>
177  </manager>
178  <manager name="Challenge" language="en_US">
179  <synopsis>
180  Generate Challenge for MD5 Auth.
181  </synopsis>
182  <syntax>
183  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
184  <parameter name="AuthType" required="true">
185  <para>Digest algorithm to use in the challenge. Valid values are:</para>
186  <enumlist>
187  <enum name="MD5" />
188  </enumlist>
189  </parameter>
190  </syntax>
191  <description>
192  <para>Generate a challenge for MD5 authentication.</para>
193  </description>
194  </manager>
195  <manager name="Hangup" language="en_US">
196  <synopsis>
197  Hangup channel.
198  </synopsis>
199  <syntax>
200  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
201  <parameter name="Channel" required="true">
202  <para>The exact channel name to be hungup, or to use a regular expression, set this parameter to: /regex/</para>
203  <para>Example exact channel: SIP/provider-0000012a</para>
204  <para>Example regular expression: /^SIP/provider-.*$/</para>
205  </parameter>
206  <parameter name="Cause">
207  <para>Numeric hangup cause.</para>
208  </parameter>
209  </syntax>
210  <description>
211  <para>Hangup a channel.</para>
212  </description>
213  </manager>
214  <manager name="Status" language="en_US">
215  <synopsis>
216  List channel status.
217  </synopsis>
218  <syntax>
219  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
220  <parameter name="Channel" required="false">
221  <para>The name of the channel to query for status.</para>
222  </parameter>
223  <parameter name="Variables">
224  <para>Comma <literal>,</literal> separated list of variable to include.</para>
225  </parameter>
226  <parameter name="AllVariables">
227  <para>If set to "true", the Status event will include all channel variables for
228  the requested channel(s).</para>
229  <enumlist>
230  <enum name="true"/>
231  <enum name="false"/>
232  </enumlist>
233  </parameter>
234  </syntax>
235  <description>
236  <para>Will return the status information of each channel along with the
237  value for the specified channel variables.</para>
238  </description>
239  <responses>
240  <list-elements>
241  <xi:include xpointer="xpointer(/docs/managerEvent[@name='Status'])" />
242  </list-elements>
243  <xi:include xpointer="xpointer(/docs/managerEvent[@name='StatusComplete'])" />
244  </responses>
245  </manager>
246  <managerEvent language="en_US" name="Status">
247  <managerEventInstance class="EVENT_FLAG_CALL">
248  <synopsis>Raised in response to a Status command.</synopsis>
249  <syntax>
250  <parameter name="ActionID" required="false"/>
251  <channel_snapshot/>
252  <parameter name="Type">
253  <para>Type of channel</para>
254  </parameter>
255  <parameter name="DNID">
256  <para>Dialed number identifier</para>
257  </parameter>
258  <parameter name="EffectiveConnectedLineNum">
259  </parameter>
260  <parameter name="EffectiveConnectedLineName">
261  </parameter>
262  <parameter name="TimeToHangup">
263  <para>Absolute lifetime of the channel</para>
264  </parameter>
265  <parameter name="BridgeID">
266  <para>Identifier of the bridge the channel is in, may be empty if not in one</para>
267  </parameter>
268  <parameter name="Application">
269  <para>Application currently executing on the channel</para>
270  </parameter>
271  <parameter name="Data">
272  <para>Data given to the currently executing channel</para>
273  </parameter>
274  <parameter name="Nativeformats">
275  <para>Media formats the connected party is willing to send or receive</para>
276  </parameter>
277  <parameter name="Readformat">
278  <para>Media formats that frames from the channel are received in</para>
279  </parameter>
280  <parameter name="Readtrans">
281  <para>Translation path for media received in native formats</para>
282  </parameter>
283  <parameter name="Writeformat">
284  <para>Media formats that frames to the channel are accepted in</para>
285  </parameter>
286  <parameter name="Writetrans">
287  <para>Translation path for media sent to the connected party</para>
288  </parameter>
289  <parameter name="Callgroup">
290  <para>Configured call group on the channel</para>
291  </parameter>
292  <parameter name="Pickupgroup">
293  <para>Configured pickup group on the channel</para>
294  </parameter>
295  <parameter name="Seconds">
296  <para>Number of seconds the channel has been active</para>
297  </parameter>
298  </syntax>
299  <see-also>
300  <ref type="manager">Status</ref>
301  </see-also>
302  </managerEventInstance>
303  </managerEvent>
304  <managerEvent language="en_US" name="StatusComplete">
305  <managerEventInstance class="EVENT_FLAG_CALL">
306  <synopsis>Raised in response to a Status command.</synopsis>
307  <syntax>
308  <parameter name="Items">
309  <para>Number of Status events returned</para>
310  </parameter>
311  </syntax>
312  <see-also>
313  <ref type="manager">Status</ref>
314  </see-also>
315  </managerEventInstance>
316  </managerEvent>
317  <manager name="Setvar" language="en_US">
318  <synopsis>
319  Sets a channel variable or function value.
320  </synopsis>
321  <syntax>
322  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
323  <parameter name="Channel">
324  <para>Channel to set variable for.</para>
325  </parameter>
326  <parameter name="Variable" required="true">
327  <para>Variable name, function or expression.</para>
328  </parameter>
329  <parameter name="Value" required="true">
330  <para>Variable or function value.</para>
331  </parameter>
332  </syntax>
333  <description>
334  <para>This command can be used to set the value of channel variables or dialplan
335  functions.</para>
336  <note>
337  <para>If a channel name is not provided then the variable is considered global.</para>
338  </note>
339  </description>
340  <see-also>
341  <ref type="manager">Getvar</ref>
342  </see-also>
343  </manager>
344  <manager name="Getvar" language="en_US">
345  <synopsis>
346  Gets a channel variable or function value.
347  </synopsis>
348  <syntax>
349  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
350  <parameter name="Channel">
351  <para>Channel to read variable from.</para>
352  </parameter>
353  <parameter name="Variable" required="true">
354  <para>Variable name, function or expression.</para>
355  </parameter>
356  </syntax>
357  <description>
358  <para>Get the value of a channel variable or function return.</para>
359  <note>
360  <para>If a channel name is not provided then the variable is considered global.</para>
361  </note>
362  </description>
363  <see-also>
364  <ref type="manager">Setvar</ref>
365  </see-also>
366  </manager>
367  <manager name="GetConfig" language="en_US">
368  <synopsis>
369  Retrieve configuration.
370  </synopsis>
371  <syntax>
372  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
373  <parameter name="Filename" required="true">
374  <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
375  </parameter>
376  <parameter name="Category">
377  <para>Category in configuration file.</para>
378  </parameter>
379  <parameter name="Filter">
380  <para>A comma separated list of
381  <replaceable>name_regex</replaceable>=<replaceable>value_regex</replaceable>
382  expressions which will cause only categories whose variables match all expressions
383  to be considered. The special variable name <literal>TEMPLATES</literal>
384  can be used to control whether templates are included. Passing
385  <literal>include</literal> as the value will include templates
386  along with normal categories. Passing
387  <literal>restrict</literal> as the value will restrict the operation to
388  ONLY templates. Not specifying a <literal>TEMPLATES</literal> expression
389  results in the default behavior which is to not include templates.</para>
390  </parameter>
391  </syntax>
392  <description>
393  <para>This action will dump the contents of a configuration
394  file by category and contents or optionally by specified category only.
395  In the case where a category name is non-unique, a filter may be specified
396  to match only categories with matching variable values.</para>
397  </description>
398  <see-also>
399  <ref type="manager">GetConfigJSON</ref>
400  <ref type="manager">UpdateConfig</ref>
401  <ref type="manager">CreateConfig</ref>
402  <ref type="manager">ListCategories</ref>
403  </see-also>
404  </manager>
405  <manager name="GetConfigJSON" language="en_US">
406  <synopsis>
407  Retrieve configuration (JSON format).
408  </synopsis>
409  <syntax>
410  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
411  <parameter name="Filename" required="true">
412  <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
413  </parameter>
414  <parameter name="Category">
415  <para>Category in configuration file.</para>
416  </parameter>
417  <parameter name="Filter">
418  <xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
419  </parameter>
420  </syntax>
421  <description>
422  <para>This action will dump the contents of a configuration file by category
423  and contents in JSON format or optionally by specified category only.
424  This only makes sense to be used using rawman over the HTTP interface.
425  In the case where a category name is non-unique, a filter may be specified
426  to match only categories with matching variable values.</para>
427  </description>
428  <see-also>
429  <ref type="manager">GetConfig</ref>
430  <ref type="manager">UpdateConfig</ref>
431  <ref type="manager">CreateConfig</ref>
432  <ref type="manager">ListCategories</ref>
433  </see-also>
434  </manager>
435  <manager name="UpdateConfig" language="en_US">
436  <synopsis>
437  Update basic configuration.
438  </synopsis>
439  <syntax>
440  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
441  <parameter name="SrcFilename" required="true">
442  <para>Configuration filename to read (e.g. <filename>foo.conf</filename>).</para>
443  </parameter>
444  <parameter name="DstFilename" required="true">
445  <para>Configuration filename to write (e.g. <filename>foo.conf</filename>)</para>
446  </parameter>
447  <parameter name="Reload">
448  <para>Whether or not a reload should take place (or name of specific module).</para>
449  </parameter>
450  <parameter name="PreserveEffectiveContext">
451  <para>Whether the effective category contents should be preserved on template change. Default is true (pre 13.2 behavior).</para>
452  </parameter>
453  <parameter name="Action-000000">
454  <para>Action to take.</para>
455  <para>0's represent 6 digit number beginning with 000000.</para>
456  <enumlist>
457  <enum name="NewCat" />
458  <enum name="RenameCat" />
459  <enum name="DelCat" />
460  <enum name="EmptyCat" />
461  <enum name="Update" />
462  <enum name="Delete" />
463  <enum name="Append" />
464  <enum name="Insert" />
465  </enumlist>
466  </parameter>
467  <parameter name="Cat-000000">
468  <para>Category to operate on.</para>
469  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
470  </parameter>
471  <parameter name="Var-000000">
472  <para>Variable to work on.</para>
473  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
474  </parameter>
475  <parameter name="Value-000000">
476  <para>Value to work on.</para>
477  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
478  </parameter>
479  <parameter name="Match-000000">
480  <para>Extra match required to match line.</para>
481  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
482  </parameter>
483  <parameter name="Line-000000">
484  <para>Line in category to operate on (used with delete and insert actions).</para>
485  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
486  </parameter>
487  <parameter name="Options-000000">
488  <para>A comma separated list of action-specific options.</para>
489  <enumlist>
490  <enum name="NewCat"><para>One or more of the following... </para>
491  <enumlist>
492  <enum name="allowdups"><para>Allow duplicate category names.</para></enum>
493  <enum name="template"><para>This category is a template.</para></enum>
494  <enum name="inherit=&quot;template[,...]&quot;"><para>Templates from which to inherit.</para></enum>
495  </enumlist>
496  </enum>
497  </enumlist>
498  <para> </para>
499  <para>The following actions share the same options...</para>
500  <enumlist>
501  <enum name="RenameCat"/>
502  <enum name="DelCat"/>
503  <enum name="EmptyCat"/>
504  <enum name="Update"/>
505  <enum name="Delete"/>
506  <enum name="Append"/>
507  <enum name="Insert"><para> </para>
508  <enumlist>
509  <enum name="catfilter=&quot;&lt;expression&gt;[,...]&quot;"><para> </para>
510  <xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
511  <para><literal>catfilter</literal> is most useful when a file
512  contains multiple categories with the same name and you wish to
513  operate on specific ones instead of all of them.</para>
514  </enum>
515  </enumlist>
516  </enum>
517  </enumlist>
518  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
519  </parameter>
520  </syntax>
521  <description>
522  <para>This action will modify, create, or delete configuration elements
523  in Asterisk configuration files.</para>
524  </description>
525  <see-also>
526  <ref type="manager">GetConfig</ref>
527  <ref type="manager">GetConfigJSON</ref>
528  <ref type="manager">CreateConfig</ref>
529  <ref type="manager">ListCategories</ref>
530  </see-also>
531  </manager>
532  <manager name="CreateConfig" language="en_US">
533  <synopsis>
534  Creates an empty file in the configuration directory.
535  </synopsis>
536  <syntax>
537  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
538  <parameter name="Filename" required="true">
539  <para>The configuration filename to create (e.g. <filename>foo.conf</filename>).</para>
540  </parameter>
541  </syntax>
542  <description>
543  <para>This action will create an empty file in the configuration
544  directory. This action is intended to be used before an UpdateConfig
545  action.</para>
546  </description>
547  <see-also>
548  <ref type="manager">GetConfig</ref>
549  <ref type="manager">GetConfigJSON</ref>
550  <ref type="manager">UpdateConfig</ref>
551  <ref type="manager">ListCategories</ref>
552  </see-also>
553  </manager>
554  <manager name="ListCategories" language="en_US">
555  <synopsis>
556  List categories in configuration file.
557  </synopsis>
558  <syntax>
559  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
560  <parameter name="Filename" required="true">
561  <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
562  </parameter>
563  </syntax>
564  <description>
565  <para>This action will dump the categories in a given file.</para>
566  </description>
567  <see-also>
568  <ref type="manager">GetConfig</ref>
569  <ref type="manager">GetConfigJSON</ref>
570  <ref type="manager">UpdateConfig</ref>
571  <ref type="manager">CreateConfig</ref>
572  </see-also>
573  </manager>
574  <manager name="Redirect" language="en_US">
575  <synopsis>
576  Redirect (transfer) a call.
577  </synopsis>
578  <syntax>
579  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
580  <parameter name="Channel" required="true">
581  <para>Channel to redirect.</para>
582  </parameter>
583  <parameter name="ExtraChannel">
584  <para>Second call leg to transfer (optional).</para>
585  </parameter>
586  <parameter name="Exten" required="true">
587  <para>Extension to transfer to.</para>
588  </parameter>
589  <parameter name="ExtraExten">
590  <para>Extension to transfer extrachannel to (optional).</para>
591  </parameter>
592  <parameter name="Context" required="true">
593  <para>Context to transfer to.</para>
594  </parameter>
595  <parameter name="ExtraContext">
596  <para>Context to transfer extrachannel to (optional).</para>
597  </parameter>
598  <parameter name="Priority" required="true">
599  <para>Priority to transfer to.</para>
600  </parameter>
601  <parameter name="ExtraPriority">
602  <para>Priority to transfer extrachannel to (optional).</para>
603  </parameter>
604  </syntax>
605  <description>
606  <para>Redirect (transfer) a call.</para>
607  </description>
608  <see-also>
609  <ref type="manager">BlindTransfer</ref>
610  </see-also>
611  </manager>
612  <manager name="Atxfer" language="en_US">
613  <synopsis>
614  Attended transfer.
615  </synopsis>
616  <syntax>
617  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
618  <parameter name="Channel" required="true">
619  <para>Transferer's channel.</para>
620  </parameter>
621  <parameter name="Exten" required="true">
622  <para>Extension to transfer to.</para>
623  </parameter>
624  <parameter name="Context">
625  <para>Context to transfer to.</para>
626  </parameter>
627  </syntax>
628  <description>
629  <para>Attended transfer.</para>
630  </description>
631  <see-also>
632  <ref type="managerEvent">AttendedTransfer</ref>
633  </see-also>
634  </manager>
635  <manager name="CancelAtxfer" language="en_US">
636  <synopsis>
637  Cancel an attended transfer.
638  </synopsis>
639  <syntax>
640  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
641  <parameter name="Channel" required="true">
642  <para>The transferer channel.</para>
643  </parameter>
644  </syntax>
645  <description>
646  <para>Cancel an attended transfer. Note, this uses the configured cancel attended transfer
647  feature option (atxferabort) to cancel the transfer. If not available this action will fail.
648  </para>
649  </description>
650  <see-also>
651  <ref type="managerEvent">AttendedTransfer</ref>
652  </see-also>
653  </manager>
654  <manager name="Originate" language="en_US">
655  <synopsis>
656  Originate a call.
657  </synopsis>
658  <syntax>
659  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
660  <parameter name="Channel" required="true">
661  <para>Channel name to call.</para>
662  </parameter>
663  <parameter name="Exten">
664  <para>Extension to use (requires <literal>Context</literal> and
665  <literal>Priority</literal>)</para>
666  </parameter>
667  <parameter name="Context">
668  <para>Context to use (requires <literal>Exten</literal> and
669  <literal>Priority</literal>)</para>
670  </parameter>
671  <parameter name="Priority">
672  <para>Priority to use (requires <literal>Exten</literal> and
673  <literal>Context</literal>)</para>
674  </parameter>
675  <parameter name="Application">
676  <para>Application to execute.</para>
677  </parameter>
678  <parameter name="Data">
679  <para>Data to use (requires <literal>Application</literal>).</para>
680  </parameter>
681  <parameter name="Timeout" default="30000">
682  <para>How long to wait for call to be answered (in ms.).</para>
683  </parameter>
684  <parameter name="CallerID">
685  <para>Caller ID to be set on the outgoing channel.</para>
686  </parameter>
687  <parameter name="Variable">
688  <para>Channel variable to set, multiple Variable: headers are allowed.</para>
689  </parameter>
690  <parameter name="Account">
691  <para>Account code.</para>
692  </parameter>
693  <parameter name="EarlyMedia">
694  <para>Set to <literal>true</literal> to force call bridge on early media..</para>
695  </parameter>
696  <parameter name="Async">
697  <para>Set to <literal>true</literal> for fast origination.</para>
698  </parameter>
699  <parameter name="Codecs">
700  <para>Comma-separated list of codecs to use for this call.</para>
701  </parameter>
702  <parameter name="ChannelId">
703  <para>Channel UniqueId to be set on the channel.</para>
704  </parameter>
705  <parameter name="OtherChannelId">
706  <para>Channel UniqueId to be set on the second local channel.</para>
707  </parameter>
708  </syntax>
709  <description>
710  <para>Generates an outgoing call to a
711  <replaceable>Extension</replaceable>/<replaceable>Context</replaceable>/<replaceable>Priority</replaceable>
712  or <replaceable>Application</replaceable>/<replaceable>Data</replaceable></para>
713  </description>
714  <see-also>
715  <ref type="managerEvent">OriginateResponse</ref>
716  </see-also>
717  </manager>
718  <managerEvent language="en_US" name="OriginateResponse">
719  <managerEventInstance class="EVENT_FLAG_CALL">
720  <synopsis>Raised in response to an Originate command.</synopsis>
721  <syntax>
722  <parameter name="ActionID" required="false"/>
723  <parameter name="Response">
724  <enumlist>
725  <enum name="Failure"/>
726  <enum name="Success"/>
727  </enumlist>
728  </parameter>
729  <parameter name="Channel"/>
730  <parameter name="Context"/>
731  <parameter name="Exten"/>
732  <parameter name="Application"/>
733  <parameter name="Data"/>
734  <parameter name="Reason"/>
735  <parameter name="Uniqueid"/>
736  <parameter name="CallerIDNum"/>
737  <parameter name="CallerIDName"/>
738  </syntax>
739  <see-also>
740  <ref type="manager">Originate</ref>
741  </see-also>
742  </managerEventInstance>
743  </managerEvent>
744  <manager name="Command" language="en_US">
745  <synopsis>
746  Execute Asterisk CLI Command.
747  </synopsis>
748  <syntax>
749  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
750  <parameter name="Command" required="true">
751  <para>Asterisk CLI command to run.</para>
752  </parameter>
753  </syntax>
754  <description>
755  <para>Run a CLI command.</para>
756  </description>
757  </manager>
758  <manager name="ExtensionState" language="en_US">
759  <synopsis>
760  Check Extension Status.
761  </synopsis>
762  <syntax>
763  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
764  <parameter name="Exten" required="true">
765  <para>Extension to check state on.</para>
766  </parameter>
767  <parameter name="Context" required="true">
768  <para>Context for extension.</para>
769  </parameter>
770  </syntax>
771  <description>
772  <para>Report the extension state for given extension. If the extension has a hint,
773  will use devicestate to check the status of the device connected to the extension.</para>
774  <para>Will return an <literal>Extension Status</literal> message. The response will include
775  the hint for the extension and the status.</para>
776  </description>
777  <see-also>
778  <ref type="managerEvent">ExtensionStatus</ref>
779  </see-also>
780  </manager>
781  <manager name="PresenceState" language="en_US">
782  <synopsis>
783  Check Presence State
784  </synopsis>
785  <syntax>
786  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
787  <parameter name="Provider" required="true">
788  <para>Presence Provider to check the state of</para>
789  </parameter>
790  </syntax>
791  <description>
792  <para>Report the presence state for the given presence provider.</para>
793  <para>Will return a <literal>Presence State</literal> message. The response will include the
794  presence state and, if set, a presence subtype and custom message.</para>
795  </description>
796  <see-also>
797  <ref type="managerEvent">PresenceStatus</ref>
798  </see-also>
799  </manager>
800  <manager name="AbsoluteTimeout" language="en_US">
801  <synopsis>
802  Set absolute timeout.
803  </synopsis>
804  <syntax>
805  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
806  <parameter name="Channel" required="true">
807  <para>Channel name to hangup.</para>
808  </parameter>
809  <parameter name="Timeout" required="true">
810  <para>Maximum duration of the call (sec).</para>
811  </parameter>
812  </syntax>
813  <description>
814  <para>Hangup a channel after a certain time. Acknowledges set time with
815  <literal>Timeout Set</literal> message.</para>
816  </description>
817  </manager>
818  <manager name="MailboxStatus" language="en_US">
819  <synopsis>
820  Check mailbox.
821  </synopsis>
822  <syntax>
823  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
824  <parameter name="Mailbox" required="true">
825  <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
826  </parameter>
827  </syntax>
828  <description>
829  <para>Checks a voicemail account for status.</para>
830  <para>Returns whether there are messages waiting.</para>
831  <para>Message: Mailbox Status.</para>
832  <para>Mailbox: <replaceable>mailboxid</replaceable>.</para>
833  <para>Waiting: <literal>0</literal> if messages waiting, <literal>1</literal>
834  if no messages waiting.</para>
835  </description>
836  <see-also>
837  <ref type="manager">MailboxCount</ref>
838  </see-also>
839  </manager>
840  <manager name="MailboxCount" language="en_US">
841  <synopsis>
842  Check Mailbox Message Count.
843  </synopsis>
844  <syntax>
845  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
846  <parameter name="Mailbox" required="true">
847  <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
848  </parameter>
849  </syntax>
850  <description>
851  <para>Checks a voicemail account for new messages.</para>
852  <para>Returns number of urgent, new and old messages.</para>
853  <para>Message: Mailbox Message Count</para>
854  <para>Mailbox: <replaceable>mailboxid</replaceable></para>
855  <para>UrgentMessages: <replaceable>count</replaceable></para>
856  <para>NewMessages: <replaceable>count</replaceable></para>
857  <para>OldMessages: <replaceable>count</replaceable></para>
858  </description>
859  <see-also>
860  <ref type="manager">MailboxStatus</ref>
861  </see-also>
862  </manager>
863  <manager name="ListCommands" language="en_US">
864  <synopsis>
865  List available manager commands.
866  </synopsis>
867  <syntax>
868  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
869  </syntax>
870  <description>
871  <para>Returns the action name and synopsis for every action that
872  is available to the user.</para>
873  </description>
874  </manager>
875  <manager name="SendText" language="en_US">
876  <synopsis>
877  Sends a text message to channel. A content type can be optionally specified. If not set
878  it is set to an empty string allowing a custom handler to default it as it sees fit.
879  </synopsis>
880  <syntax>
881  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
882  <parameter name="Channel" required="true">
883  <para>Channel to send message to.</para>
884  </parameter>
885  <parameter name="Message" required="true">
886  <para>Message to send.</para>
887  </parameter>
888  <parameter name="Content-Type" required="false" default="">
889  <para>The type of content in the message</para>
890  </parameter>
891  </syntax>
892  <description>
893  <para>Sends A Text Message to a channel while in a call.</para>
894  </description>
895  <see-also>
896  <ref type="application">SendText</ref>
897  </see-also>
898  </manager>
899  <manager name="UserEvent" language="en_US">
900  <synopsis>
901  Send an arbitrary event.
902  </synopsis>
903  <syntax>
904  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
905  <parameter name="UserEvent" required="true">
906  <para>Event string to send.</para>
907  </parameter>
908  <parameter name="Header1">
909  <para>Content1.</para>
910  </parameter>
911  <parameter name="HeaderN">
912  <para>ContentN.</para>
913  </parameter>
914  </syntax>
915  <description>
916  <para>Send an event to manager sessions.</para>
917  </description>
918  <see-also>
919  <ref type="managerEvent">UserEvent</ref>
920  <ref type="application">UserEvent</ref>
921  </see-also>
922  </manager>
923  <manager name="WaitEvent" language="en_US">
924  <synopsis>
925  Wait for an event to occur.
926  </synopsis>
927  <syntax>
928  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
929  <parameter name="Timeout" required="true">
930  <para>Maximum time (in seconds) to wait for events, <literal>-1</literal> means forever.</para>
931  </parameter>
932  </syntax>
933  <description>
934  <para>This action will ellicit a <literal>Success</literal> response. Whenever
935  a manager event is queued. Once WaitEvent has been called on an HTTP manager
936  session, events will be generated and queued.</para>
937  </description>
938  </manager>
939  <manager name="CoreSettings" language="en_US">
940  <synopsis>
941  Show PBX core settings (version etc).
942  </synopsis>
943  <syntax>
944  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
945  </syntax>
946  <description>
947  <para>Query for Core PBX settings.</para>
948  </description>
949  </manager>
950  <manager name="CoreStatus" language="en_US">
951  <synopsis>
952  Show PBX core status variables.
953  </synopsis>
954  <syntax>
955  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
956  </syntax>
957  <description>
958  <para>Query for Core PBX status.</para>
959  </description>
960  </manager>
961  <manager name="Reload" language="en_US">
962  <synopsis>
963  Send a reload event.
964  </synopsis>
965  <syntax>
966  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
967  <parameter name="Module">
968  <para>Name of the module to reload.</para>
969  </parameter>
970  </syntax>
971  <description>
972  <para>Send a reload event.</para>
973  </description>
974  <see-also>
975  <ref type="manager">ModuleLoad</ref>
976  </see-also>
977  </manager>
978  <managerEvent language="en_US" name="CoreShowChannel">
979  <managerEventInstance class="EVENT_FLAG_CALL">
980  <synopsis>Raised in response to a CoreShowChannels command.</synopsis>
981  <syntax>
982  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
983  <channel_snapshot/>
984  <parameter name="BridgeId">
985  <para>Identifier of the bridge the channel is in, may be empty if not in one</para>
986  </parameter>
987  <parameter name="Application">
988  <para>Application currently executing on the channel</para>
989  </parameter>
990  <parameter name="ApplicationData">
991  <para>Data given to the currently executing application</para>
992  </parameter>
993  <parameter name="Duration">
994  <para>The amount of time the channel has existed</para>
995  </parameter>
996  </syntax>
997  <see-also>
998  <ref type="manager">CoreShowChannels</ref>
999  <ref type="managerEvent">CoreShowChannelsComplete</ref>
1000  </see-also>
1001  </managerEventInstance>
1002  </managerEvent>
1003  <managerEvent language="en_US" name="CoreShowChannelsComplete">
1004  <managerEventInstance class="EVENT_FLAG_CALL">
1005  <synopsis>Raised at the end of the CoreShowChannel list produced by the CoreShowChannels command.</synopsis>
1006  <syntax>
1007  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1008  <parameter name="EventList">
1009  <para>Conveys the status of the command reponse list</para>
1010  </parameter>
1011  <parameter name="ListItems">
1012  <para>The total number of list items produced</para>
1013  </parameter>
1014  </syntax>
1015  <see-also>
1016  <ref type="manager">CoreShowChannels</ref>
1017  <ref type="managerEvent">CoreShowChannel</ref>
1018  </see-also>
1019  </managerEventInstance>
1020  </managerEvent>
1021  <manager name="CoreShowChannels" language="en_US">
1022  <synopsis>
1023  List currently active channels.
1024  </synopsis>
1025  <syntax>
1026  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1027  </syntax>
1028  <description>
1029  <para>List currently defined channels and some information about them.</para>
1030  </description>
1031  <responses>
1032  <list-elements>
1033  <xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannel'])" />
1034  </list-elements>
1035  <xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannelsComplete'])" />
1036  </responses>
1037  </manager>
1038  <manager name="LoggerRotate" language="en_US">
1039  <synopsis>
1040  Reload and rotate the Asterisk logger.
1041  </synopsis>
1042  <syntax>
1043  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1044  </syntax>
1045  <description>
1046  <para>Reload and rotate the logger. Analogous to the CLI command 'logger rotate'.</para>
1047  </description>
1048  </manager>
1049  <manager name="ModuleLoad" language="en_US">
1050  <synopsis>
1051  Module management.
1052  </synopsis>
1053  <syntax>
1054  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1055  <parameter name="Module">
1056  <para>Asterisk module name (including .so extension) or subsystem identifier:</para>
1057  <enumlist>
1058  <enum name="cdr" />
1059  <enum name="dnsmgr" />
1060  <enum name="extconfig" />
1061  <enum name="enum" />
1062  <enum name="acl" />
1063  <enum name="manager" />
1064  <enum name="http" />
1065  <enum name="logger" />
1066  <enum name="features" />
1067  <enum name="dsp" />
1068  <enum name="udptl" />
1069  <enum name="indications" />
1070  <enum name="cel" />
1071  <enum name="plc" />
1072  </enumlist>
1073  </parameter>
1074  <parameter name="LoadType" required="true">
1075  <para>The operation to be done on module. Subsystem identifiers may only
1076  be reloaded.</para>
1077  <enumlist>
1078  <enum name="load" />
1079  <enum name="unload" />
1080  <enum name="reload" />
1081  </enumlist>
1082  <para>If no module is specified for a <literal>reload</literal> loadtype,
1083  all modules are reloaded.</para>
1084  </parameter>
1085  </syntax>
1086  <description>
1087  <para>Loads, unloads or reloads an Asterisk module in a running system.</para>
1088  </description>
1089  <see-also>
1090  <ref type="manager">Reload</ref>
1091  <ref type="manager">ModuleCheck</ref>
1092  </see-also>
1093  </manager>
1094  <manager name="ModuleCheck" language="en_US">
1095  <synopsis>
1096  Check if module is loaded.
1097  </synopsis>
1098  <syntax>
1099  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1100  <parameter name="Module" required="true">
1101  <para>Asterisk module name (not including extension).</para>
1102  </parameter>
1103  </syntax>
1104  <description>
1105  <para>Checks if Asterisk module is loaded. Will return Success/Failure.
1106  For success returns, the module revision number is included.</para>
1107  </description>
1108  <see-also>
1109  <ref type="manager">ModuleLoad</ref>
1110  </see-also>
1111  </manager>
1112  <manager name="AOCMessage" language="en_US">
1113  <synopsis>
1114  Generate an Advice of Charge message on a channel.
1115  </synopsis>
1116  <syntax>
1117  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1118  <parameter name="Channel" required="true">
1119  <para>Channel name to generate the AOC message on.</para>
1120  </parameter>
1121  <parameter name="ChannelPrefix">
1122  <para>Partial channel prefix. By using this option one can match the beginning part
1123  of a channel name without having to put the entire name in. For example
1124  if a channel name is SIP/snom-00000001 and this value is set to SIP/snom, then
1125  that channel matches and the message will be sent. Note however that only
1126  the first matched channel has the message sent on it. </para>
1127  </parameter>
1128  <parameter name="MsgType" required="true">
1129  <para>Defines what type of AOC message to create, AOC-D or AOC-E</para>
1130  <enumlist>
1131  <enum name="D" />
1132  <enum name="E" />
1133  </enumlist>
1134  </parameter>
1135  <parameter name="ChargeType" required="true">
1136  <para>Defines what kind of charge this message represents.</para>
1137  <enumlist>
1138  <enum name="NA" />
1139  <enum name="FREE" />
1140  <enum name="Currency" />
1141  <enum name="Unit" />
1142  </enumlist>
1143  </parameter>
1144  <parameter name="UnitAmount(0)">
1145  <para>This represents the amount of units charged. The ETSI AOC standard specifies that
1146  this value along with the optional UnitType value are entries in a list. To accommodate this
1147  these values take an index value starting at 0 which can be used to generate this list of
1148  unit entries. For Example, If two unit entires were required this could be achieved by setting the
1149  paramter UnitAmount(0)=1234 and UnitAmount(1)=5678. Note that UnitAmount at index 0 is
1150  required when ChargeType=Unit, all other entries in the list are optional.
1151  </para>
1152  </parameter>
1153  <parameter name="UnitType(0)">
1154  <para>Defines the type of unit. ETSI AOC standard specifies this as an integer
1155  value between 1 and 16, but this value is left open to accept any positive
1156  integer. Like the UnitAmount parameter, this value represents a list entry
1157  and has an index parameter that starts at 0.
1158  </para>
1159  </parameter>
1160  <parameter name="CurrencyName">
1161  <para>Specifies the currency's name. Note that this value is truncated after 10 characters.</para>
1162  </parameter>
1163  <parameter name="CurrencyAmount">
1164  <para>Specifies the charge unit amount as a positive integer. This value is required
1165  when ChargeType==Currency.</para>
1166  </parameter>
1167  <parameter name="CurrencyMultiplier">
1168  <para>Specifies the currency multiplier. This value is required when ChargeType==Currency.</para>
1169  <enumlist>
1170  <enum name="OneThousandth" />
1171  <enum name="OneHundredth" />
1172  <enum name="OneTenth" />
1173  <enum name="One" />
1174  <enum name="Ten" />
1175  <enum name="Hundred" />
1176  <enum name="Thousand" />
1177  </enumlist>
1178  </parameter>
1179  <parameter name="TotalType" default="Total">
1180  <para>Defines what kind of AOC-D total is represented.</para>
1181  <enumlist>
1182  <enum name="Total" />
1183  <enum name="SubTotal" />
1184  </enumlist>
1185  </parameter>
1186  <parameter name="AOCBillingId">
1187  <para>Represents a billing ID associated with an AOC-D or AOC-E message. Note
1188  that only the first 3 items of the enum are valid AOC-D billing IDs</para>
1189  <enumlist>
1190  <enum name="Normal" />
1191  <enum name="ReverseCharge" />
1192  <enum name="CreditCard" />
1193  <enum name="CallFwdUnconditional" />
1194  <enum name="CallFwdBusy" />
1195  <enum name="CallFwdNoReply" />
1196  <enum name="CallDeflection" />
1197  <enum name="CallTransfer" />
1198  </enumlist>
1199  </parameter>
1200  <parameter name="ChargingAssociationId">
1201  <para>Charging association identifier. This is optional for AOC-E and can be
1202  set to any value between -32768 and 32767</para>
1203  </parameter>
1204  <parameter name="ChargingAssociationNumber">
1205  <para>Represents the charging association party number. This value is optional
1206  for AOC-E.</para>
1207  </parameter>
1208  <parameter name="ChargingAssociationPlan">
1209  <para>Integer representing the charging plan associated with the ChargingAssociationNumber.
1210  The value is bits 7 through 1 of the Q.931 octet containing the type-of-number and
1211  numbering-plan-identification fields.</para>
1212  </parameter>
1213  </syntax>
1214  <description>
1215  <para>Generates an AOC-D or AOC-E message on a channel.</para>
1216  </description>
1217  <see-also>
1218  <ref type="managerEvent">AOC-D</ref>
1219  <ref type="managerEvent">AOC-E</ref>
1220  </see-also>
1221  </manager>
1222  <function name="AMI_CLIENT" language="en_US">
1223  <synopsis>
1224  Checks attributes of manager accounts
1225  </synopsis>
1226  <syntax>
1227  <parameter name="loginname" required="true">
1228  <para>Login name, specified in manager.conf</para>
1229  </parameter>
1230  <parameter name="field" required="true">
1231  <para>The manager account attribute to return</para>
1232  <enumlist>
1233  <enum name="sessions"><para>The number of sessions for this AMI account</para></enum>
1234  </enumlist>
1235  </parameter>
1236  </syntax>
1237  <description>
1238  <para>
1239  Currently, the only supported parameter is "sessions" which will return the current number of
1240  active sessions for this AMI account.
1241  </para>
1242  </description>
1243  </function>
1244  <manager name="Filter" language="en_US">
1245  <synopsis>
1246  Dynamically add filters for the current manager session.
1247  </synopsis>
1248  <syntax>
1249  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1250  <parameter name="Operation">
1251  <enumlist>
1252  <enum name="Add">
1253  <para>Add a filter.</para>
1254  </enum>
1255  </enumlist>
1256  </parameter>
1257  <parameter name="Filter">
1258  <para>Filters can be whitelist or blacklist</para>
1259  <para>Example whitelist filter: "Event: Newchannel"</para>
1260  <para>Example blacklist filter: "!Channel: DAHDI.*"</para>
1261  <para>This filter option is used to whitelist or blacklist events per user to be
1262  reported with regular expressions and are allowed if both the regex matches
1263  and the user has read access as defined in manager.conf. Filters are assumed to be for whitelisting
1264  unless preceeded by an exclamation point, which marks it as being black.
1265  Evaluation of the filters is as follows:</para>
1266  <para>- If no filters are configured all events are reported as normal.</para>
1267  <para>- If there are white filters only: implied black all filter processed first, then white filters.</para>
1268  <para>- If there are black filters only: implied white all filter processed first, then black filters.</para>
1269  <para>- If there are both white and black filters: implied black all filter processed first, then white
1270  filters, and lastly black filters.</para>
1271  </parameter>
1272  </syntax>
1273  <description>
1274  <para>The filters added are only used for the current session.
1275  Once the connection is closed the filters are removed.</para>
1276  <para>This comand requires the system permission because
1277  this command can be used to create filters that may bypass
1278  filters defined in manager.conf</para>
1279  </description>
1280  <see-also>
1281  <ref type="manager">FilterList</ref>
1282  </see-also>
1283  </manager>
1284  <manager name="FilterList" language="en_US">
1285  <synopsis>
1286  Show current event filters for this session
1287  </synopsis>
1288  <description>
1289  <para>The filters displayed are for the current session. Only those filters defined in
1290  manager.conf will be present upon starting a new session.</para>
1291  </description>
1292  <see-also>
1293  <ref type="manager">Filter</ref>
1294  </see-also>
1295  </manager>
1296  <manager name="BlindTransfer" language="en_US">
1297  <synopsis>
1298  Blind transfer channel(s) to the given destination
1299  </synopsis>
1300  <syntax>
1301  <parameter name="Channel" required="true">
1302  </parameter>
1303  <parameter name="Context">
1304  </parameter>
1305  <parameter name="Exten">
1306  </parameter>
1307  </syntax>
1308  <description>
1309  <para>Redirect all channels currently bridged to the specified channel to the specified destination.</para>
1310  </description>
1311  <see-also>
1312  <ref type="manager">Redirect</ref>
1313  <ref type="managerEvent">BlindTransfer</ref>
1314  </see-also>
1315  </manager>
1316  <managerEvent name="ExtensionStatus" language="en_US">
1317  <managerEventInstance class="EVENT_FLAG_CALL">
1318  <synopsis>Raised when a hint changes due to a device state change.</synopsis>
1319  <syntax>
1320  <parameter name="Exten">
1321  <para>Name of the extension.</para>
1322  </parameter>
1323  <parameter name="Context">
1324  <para>Context that owns the extension.</para>
1325  </parameter>
1326  <parameter name="Hint">
1327  <para>Hint set for the extension</para>
1328  </parameter>
1329  <parameter name="Status">
1330  <para>Numerical value of the extension status. Extension
1331  status is determined by the combined device state of all items
1332  contained in the hint.</para>
1333  <enumlist>
1334  <enum name="-2">
1335  <para>The extension was removed from the dialplan.</para>
1336  </enum>
1337  <enum name="-1">
1338  <para>The extension's hint was removed from the dialplan.</para>
1339  </enum>
1340  <enum name="0">
1341  <para><literal>Idle</literal> - Related device(s) are in an idle
1342  state.</para>
1343  </enum>
1344  <enum name="1">
1345  <para><literal>InUse</literal> - Related device(s) are in active
1346  calls but may take more calls.</para>
1347  </enum>
1348  <enum name="2">
1349  <para><literal>Busy</literal> - Related device(s) are in active
1350  calls and may not take any more calls.</para>
1351  </enum>
1352  <enum name="4">
1353  <para><literal>Unavailable</literal> - Related device(s) are
1354  not reachable.</para>
1355  </enum>
1356  <enum name="8">
1357  <para><literal>Ringing</literal> - Related device(s) are
1358  currently ringing.</para>
1359  </enum>
1360  <enum name="9">
1361  <para><literal>InUse&amp;Ringing</literal> - Related device(s)
1362  are currently ringing and in active calls.</para>
1363  </enum>
1364  <enum name="16">
1365  <para><literal>Hold</literal> - Related device(s) are
1366  currently on hold.</para>
1367  </enum>
1368  <enum name="17">
1369  <para><literal>InUse&amp;Hold</literal> - Related device(s)
1370  are currently on hold and in active calls.</para>
1371  </enum>
1372  </enumlist>
1373  </parameter>
1374  <parameter name="StatusText">
1375  <para>Text representation of <literal>Status</literal>.</para>
1376  <enumlist>
1377  <enum name="Idle" />
1378  <enum name="InUse" />
1379  <enum name="Busy" />
1380  <enum name="Unavailable" />
1381  <enum name="Ringing" />
1382  <enum name="InUse&amp;Ringing" />
1383  <enum name="Hold" />
1384  <enum name="InUse&amp;Hold" />
1385  <enum name="Unknown">
1386  <para>Status does not match any of the above values.</para>
1387  </enum>
1388  </enumlist>
1389  </parameter>
1390  </syntax>
1391  <see-also>
1392  <ref type="manager">ExtensionState</ref>
1393  </see-also>
1394  </managerEventInstance>
1395  </managerEvent>
1396  <managerEvent name="PresenceStatus" language="en_US">
1397  <managerEventInstance class="EVENT_FLAG_CALL">
1398  <synopsis>Raised when a hint changes due to a presence state change.</synopsis>
1399  <syntax>
1400  <parameter name="Exten" />
1401  <parameter name="Context" />
1402  <parameter name="Hint" />
1403  <parameter name="Status" />
1404  <parameter name="Subtype" />
1405  <parameter name="Message" />
1406  </syntax>
1407  <see-also>
1408  <ref type="manager">PresenceState</ref>
1409  </see-also>
1410  </managerEventInstance>
1411  </managerEvent>
1412  ***/
1413 
1414 /*! \addtogroup Group_AMI AMI functions
1415 */
1416 /*! @{
1417  Doxygen group */
1418 
1432 };
1433 
1438 };
1439 
1440 /*!
1441  * Linked list of events.
1442  * Global events are appended to the list by append_event().
1443  * The usecount is the number of stored pointers to the element,
1444  * excluding the list pointers. So an element that is only in
1445  * the list has a usecount of 0, not 1.
1446  *
1447  * Clients have a pointer to the last event processed, and for each
1448  * of these clients we track the usecount of the elements.
1449  * If we have a pointer to an entry in the list, it is safe to navigate
1450  * it forward because elements will not be deleted, but only appended.
1451  * The worst that can happen is seeing the pointer still NULL.
1452  *
1453  * When the usecount of an element drops to 0, and the element is the
1454  * first in the list, we can remove it. Removal is done within the
1455  * main thread, which is woken up for the purpose.
1456  *
1457  * For simplicity of implementation, we make sure the list is never empty.
1458  */
1459 struct eventqent {
1460  int usecount; /*!< # of clients who still need the event */
1462  unsigned int seq; /*!< sequence number */
1463  struct timeval tv; /*!< When event was allocated */
1464  AST_RWLIST_ENTRY(eventqent) eq_next;
1465  char eventdata[1]; /*!< really variable size, allocated by append_event() */
1466 };
1467 
1469 
1470 static int displayconnects = 1;
1471 static int allowmultiplelogin = 1;
1472 static int timestampevents;
1473 static int httptimeout = 60;
1474 static int broken_events_action = 0;
1475 static int manager_enabled = 0;
1476 static int subscribed = 0;
1477 static int webmanager_enabled = 0;
1478 static int manager_debug = 0; /*!< enable some debugging code in the manager */
1479 static int authtimeout;
1480 static int authlimit;
1481 static char *manager_channelvars;
1482 
1483 #define DEFAULT_REALM "asterisk"
1484 static char global_realm[MAXHOSTNAMELEN]; /*!< Default realm */
1485 
1486 static int unauth_sessions = 0;
1488 
1489 /*! \brief A \ref stasis_topic that all topics AMI cares about will be forwarded to */
1491 
1492 /*! \brief The \ref stasis_message_router for all \ref stasis messages */
1494 
1495 /*! \brief The \ref stasis_subscription for forwarding the RTP topic to the AMI topic */
1497 
1498 /*! \brief The \ref stasis_subscription for forwarding the Security topic to the AMI topic */
1500 
1501 #ifdef TEST_FRAMEWORK
1502 /*! \brief The \ref stasis_subscription for forwarding the Test topic to the AMI topic */
1503 static struct stasis_forward *test_suite_forwarder;
1504 #endif
1505 
1506 #define MGR_SHOW_TERMINAL_WIDTH 80
1507 
1508 #define MAX_VARS 128
1509 
1510 /*! \brief Fake event class used to end sessions at shutdown */
1511 #define EVENT_FLAG_SHUTDOWN -1
1512 
1513 /*! \brief
1514  * Descriptor for a manager session, either on the AMI socket or over HTTP.
1515  *
1516  * \note
1517  * AMI session have managerid == 0; the entry is created upon a connect,
1518  * and destroyed with the socket.
1519  * HTTP sessions have managerid != 0, the value is used as a search key
1520  * to lookup sessions (using the mansession_id cookie, or nonce key from
1521  * Digest Authentication http header).
1522  */
1523 #define MAX_BLACKLIST_CMD_LEN 2
1524 static const struct {
1525  const char *words[AST_MAX_CMD_LEN];
1526 } command_blacklist[] = {
1527  {{ "module", "load", NULL }},
1528  {{ "module", "unload", NULL }},
1529  {{ "restart", "gracefully", NULL }},
1530 };
1531 
1532 static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
1533 
1535 {
1536  if (!acl_change_sub) {
1537  acl_change_sub = stasis_subscribe(ast_security_topic(),
1541  }
1542 }
1543 
1545 {
1546  acl_change_sub = stasis_unsubscribe_and_join(acl_change_sub);
1547 }
1548 
1549 /* In order to understand what the heck is going on with the
1550  * mansession_session and mansession structs, we need to have a bit of a history
1551  * lesson.
1552  *
1553  * In the beginning, there was the mansession. The mansession contained data that was
1554  * intrinsic to a manager session, such as the time that it started, the name of the logged-in
1555  * user, etc. In addition to these parameters were the f and fd parameters. For typical manager
1556  * sessions, these were used to represent the TCP socket over which the AMI session was taking
1557  * place. It makes perfect sense for these fields to be a part of the session-specific data since
1558  * the session actually defines this information.
1559  *
1560  * Then came the HTTP AMI sessions. With these, the f and fd fields need to be opened and closed
1561  * for every single action that occurs. Thus the f and fd fields aren't really specific to the session
1562  * but rather to the action that is being executed. Because a single session may execute many commands
1563  * at once, some sort of safety needed to be added in order to be sure that we did not end up with fd
1564  * leaks from one action overwriting the f and fd fields used by a previous action before the previous action
1565  * has had a chance to properly close its handles.
1566  *
1567  * The initial idea to solve this was to use thread synchronization, but this prevented multiple actions
1568  * from being run at the same time in a single session. Some manager actions may block for a long time, thus
1569  * creating a large queue of actions to execute. In addition, this fix did not address the basic architectural
1570  * issue that for HTTP manager sessions, the f and fd variables are not really a part of the session, but are
1571  * part of the action instead.
1572  *
1573  * The new idea was to create a structure on the stack for each HTTP Manager action. This structure would
1574  * contain the action-specific information, such as which file to write to. In order to maintain expectations
1575  * of action handlers and not have to change the public API of the manager code, we would need to name this
1576  * new stacked structure 'mansession' and contain within it the old mansession struct that we used to use.
1577  * We renamed the old mansession struct 'mansession_session' to hopefully convey that what is in this structure
1578  * is session-specific data. The structure that it is wrapped in, called a 'mansession' really contains action-specific
1579  * data.
1580  */
1582  /*! \todo XXX need to document which fields it is protecting */
1583  struct ast_sockaddr addr; /*!< address we are connecting from */
1584  struct ast_iostream *stream; /*!< AMI stream */
1585  int inuse; /*!< number of HTTP sessions using this entry */
1586  int needdestroy; /*!< Whether an HTTP session should be destroyed */
1587  pthread_t waiting_thread; /*!< Sleeping thread using this descriptor */
1588  uint32_t managerid; /*!< Unique manager identifier, 0 for AMI sessions */
1589  time_t sessionstart; /*!< Session start time */
1590  struct timeval sessionstart_tv; /*!< Session start time */
1591  time_t sessiontimeout; /*!< Session timeout if HTTP */
1592  char username[80]; /*!< Logged in username */
1593  char challenge[10]; /*!< Authentication challenge */
1594  int authenticated; /*!< Authentication status */
1595  int readperm; /*!< Authorization for reading */
1596  int writeperm; /*!< Authorization for writing */
1597  char inbuf[1025]; /*!< Buffer - we use the extra byte to add a '\\0' and simplify parsing */
1598  int inlen; /*!< number of buffered bytes */
1599  struct ao2_container *whitefilters; /*!< Manager event filters - white list */
1600  struct ao2_container *blackfilters; /*!< Manager event filters - black list */
1601  struct ast_variable *chanvars; /*!< Channel variables to set for originate */
1602  int send_events; /*!< XXX what ? */
1603  struct eventqent *last_ev; /*!< last event processed. */
1604  int writetimeout; /*!< Timeout for ast_carefulwrite() */
1605  time_t authstart;
1606  int pending_event; /*!< Pending events indicator in case when waiting_thread is NULL */
1607  time_t noncetime; /*!< Timer for nonce value expiration */
1608  unsigned long oldnonce; /*!< Stale nonce value */
1609  unsigned long nc; /*!< incremental nonce counter */
1610  ast_mutex_t notify_lock; /*!< Lock for notifying this session of events */
1611  AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore) datastores; /*!< Data stores on the session */
1613 };
1614 
1618 };
1619 
1620 /*! \brief In case you didn't read that giant block of text above the mansession_session struct, the
1621  * \ref struct mansession is named this solely to keep the API the same in Asterisk. This structure really
1622  * represents data that is different from Manager action to Manager action. The mansession_session pointer
1623  * contained within points to session-specific data.
1624  */
1625 struct mansession {
1630  unsigned int write_error:1;
1633 };
1634 
1635 /*! Active manager connection sessions container. */
1636 static AO2_GLOBAL_OBJ_STATIC(mgr_sessions);
1637 
1638 /*! \brief user descriptor, as read from the config file.
1639  *
1640  * \note It is still missing some fields -- e.g. we can have multiple permit and deny
1641  * lines which are not supported here, and readperm/writeperm/writetimeout
1642  * are not stored.
1643  */
1645  char username[80];
1646  char *secret; /*!< Secret for logging in */
1647  int readperm; /*!< Authorization for reading */
1648  int writeperm; /*!< Authorization for writing */
1649  int writetimeout; /*!< Per user Timeout for ast_carefulwrite() */
1650  int displayconnects; /*!< XXX unused */
1651  int allowmultiplelogin; /*!< Per user option*/
1652  int keep; /*!< mark entries created on a reload */
1653  struct ao2_container *whitefilters; /*!< Manager event filters - white list */
1654  struct ao2_container *blackfilters; /*!< Manager event filters - black list */
1655  struct ast_acl_list *acl; /*!< ACL setting */
1656  char *a1_hash; /*!< precalculated A1 for Digest auth */
1657  struct ast_variable *chanvars; /*!< Channel variables to set for originate */
1659 };
1660 
1661 /*! \brief list of users found in the config file */
1663 
1664 /*! \brief list of actions registered */
1666 
1667 /*! \brief list of hooks registered */
1669 
1670 #ifdef AST_XML_DOCS
1671 /*! \brief A container of event documentation nodes */
1672 static AO2_GLOBAL_OBJ_STATIC(event_docs);
1673 #endif
1674 
1675 static int __attribute__((format(printf, 9, 0))) __manager_event_sessions(
1676  struct ao2_container *sessions,
1677  int category,
1678  const char *event,
1679  int chancount,
1680  struct ast_channel **chans,
1681  const char *file,
1682  int line,
1683  const char *func,
1684  const char *fmt,
1685  ...);
1686 static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters);
1687 
1688 static int match_filter(struct mansession *s, char *eventdata);
1689 
1690 /*!
1691  * @{ \brief Define AMI message types.
1692  */
1694 /*! @} */
1695 
1696 /*!
1697  * \internal
1698  * \brief Find a registered action object.
1699  *
1700  * \param name Name of AMI action to find.
1701  *
1702  * \return Reffed action found or NULL
1703  */
1704 static struct manager_action *action_find(const char *name)
1705 {
1706  struct manager_action *act;
1707 
1709  AST_RWLIST_TRAVERSE(&actions, act, list) {
1710  if (!strcasecmp(name, act->action)) {
1711  ao2_t_ref(act, +1, "found action object");
1712  break;
1713  }
1714  }
1716 
1717  return act;
1718 }
1719 
1721 {
1722  return manager_topic;
1723 }
1724 
1726 {
1727  return stasis_router;
1728 }
1729 
1730 static void manager_json_value_str_append(struct ast_json *value, const char *key,
1731  struct ast_str **res)
1732 {
1733  switch (ast_json_typeof(value)) {
1734  case AST_JSON_STRING:
1735  ast_str_append(res, 0, "%s: %s\r\n", key, ast_json_string_get(value));
1736  break;
1737  case AST_JSON_INTEGER:
1738  ast_str_append(res, 0, "%s: %jd\r\n", key, ast_json_integer_get(value));
1739  break;
1740  case AST_JSON_TRUE:
1741  ast_str_append(res, 0, "%s: True\r\n", key);
1742  break;
1743  case AST_JSON_FALSE:
1744  ast_str_append(res, 0, "%s: False\r\n", key);
1745  break;
1746  default:
1747  ast_str_append(res, 0, "%s: \r\n", key);
1748  break;
1749  }
1750 }
1751 
1752 static void manager_json_to_ast_str(struct ast_json *obj, const char *key,
1753  struct ast_str **res, key_exclusion_cb exclusion_cb);
1754 
1755 static void manager_json_array_with_key(struct ast_json *obj, const char* key,
1756  size_t index, struct ast_str **res,
1757  key_exclusion_cb exclusion_cb)
1758 {
1759  struct ast_str *key_str = ast_str_alloca(64);
1760  ast_str_set(&key_str, 0, "%s(%zu)", key, index);
1762  res, exclusion_cb);
1763 }
1764 
1765 static void manager_json_obj_with_key(struct ast_json *obj, const char* key,
1766  const char *parent_key, struct ast_str **res,
1767  key_exclusion_cb exclusion_cb)
1768 {
1769  if (parent_key) {
1770  struct ast_str *key_str = ast_str_alloca(64);
1771  ast_str_set(&key_str, 0, "%s/%s", parent_key, key);
1773  res, exclusion_cb);
1774  return;
1775  }
1776 
1777  manager_json_to_ast_str(obj, key, res, exclusion_cb);
1778 }
1779 
1780 void manager_json_to_ast_str(struct ast_json *obj, const char *key,
1781  struct ast_str **res, key_exclusion_cb exclusion_cb)
1782 {
1783  struct ast_json_iter *i;
1784 
1785  /* If obj or res is not given, just return */
1786  if (!obj || !res) {
1787  return;
1788  }
1789 
1790  if (!*res && !(*res = ast_str_create(1024))) {
1791  return;
1792  }
1793 
1794  if (exclusion_cb && key && exclusion_cb(key)) {
1795  return;
1796  }
1797 
1798  if (ast_json_typeof(obj) != AST_JSON_OBJECT &&
1799  ast_json_typeof(obj) != AST_JSON_ARRAY) {
1800  manager_json_value_str_append(obj, key, res);
1801  return;
1802  }
1803 
1804  if (ast_json_typeof(obj) == AST_JSON_ARRAY) {
1805  size_t j;
1806  for (j = 0; j < ast_json_array_size(obj); ++j) {
1808  key, j, res, exclusion_cb);
1809  }
1810  return;
1811  }
1812 
1813  for (i = ast_json_object_iter(obj); i;
1814  i = ast_json_object_iter_next(obj, i)) {
1817  key, res, exclusion_cb);
1818  }
1819 }
1820 
1822 {
1823  struct ast_str *res = ast_str_create(1024);
1824 
1825  if (!ast_json_is_null(blob)) {
1826  manager_json_to_ast_str(blob, NULL, &res, exclusion_cb);
1827  }
1828 
1829  return res;
1830 }
1831 
1832 #define manager_event_sessions(sessions, category, event, contents , ...) \
1833  __manager_event_sessions(sessions, category, event, 0, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, contents , ## __VA_ARGS__)
1834 
1835 #define any_manager_listeners(sessions) \
1836  ((sessions && ao2_container_count(sessions)) || !AST_RWLIST_EMPTY(&manager_hooks))
1837 
1838 static void manager_default_msg_cb(void *data, struct stasis_subscription *sub,
1839  struct stasis_message *message)
1840 {
1841  struct ao2_container *sessions;
1842  struct ast_manager_event_blob *ev;
1843 
1844  if (!stasis_message_can_be_ami(message)) {
1845  /* Not an AMI message; disregard */
1846  return;
1847  }
1848 
1849  sessions = ao2_global_obj_ref(mgr_sessions);
1850  if (!any_manager_listeners(sessions)) {
1851  /* Nobody is listening */
1852  ao2_cleanup(sessions);
1853  return;
1854  }
1855 
1856  ev = stasis_message_to_ami(message);
1857  if (!ev) {
1858  /* Conversion failure */
1859  ao2_cleanup(sessions);
1860  return;
1861  }
1862 
1864  "%s", ev->extra_fields);
1865  ao2_ref(ev, -1);
1866  ao2_cleanup(sessions);
1867 }
1868 
1869 static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub,
1870  struct stasis_message *message)
1871 {
1872  struct ast_json_payload *payload;
1873  int class_type;
1874  const char *type;
1875  struct ast_json *event;
1876  struct ast_str *event_buffer;
1877  struct ao2_container *sessions;
1878 
1879  sessions = ao2_global_obj_ref(mgr_sessions);
1880  if (!any_manager_listeners(sessions)) {
1881  /* Nobody is listening */
1882  ao2_cleanup(sessions);
1883  return;
1884  }
1885 
1886  payload = stasis_message_data(message);
1887  class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type"));
1888  type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
1889  event = ast_json_object_get(payload->json, "event");
1890 
1891  event_buffer = ast_manager_str_from_json_object(event, NULL);
1892  if (!event_buffer) {
1893  ast_log(AST_LOG_WARNING, "Error while creating payload for event %s\n", type);
1894  ao2_cleanup(sessions);
1895  return;
1896  }
1897  manager_event_sessions(sessions, class_type, type,
1898  "%s", ast_str_buffer(event_buffer));
1899  ast_free(event_buffer);
1900  ao2_cleanup(sessions);
1901 }
1902 
1903 void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
1904 {
1905  RAII_VAR(struct ast_json *, event_info, NULL, ast_json_unref);
1906  RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
1907  RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
1908 
1909  if (!obj || !ast_manager_get_generic_type()) {
1910  return;
1911  }
1912 
1913  ast_json_ref(obj);
1914  event_info = ast_json_pack("{s: s, s: i, s: o}",
1915  "type", type,
1916  "class_type", class_type,
1917  "event", obj);
1918  if (!event_info) {
1919  return;
1920  }
1921 
1922  payload = ast_json_payload_create(event_info);
1923  if (!payload) {
1924  return;
1925  }
1927  if (!message) {
1928  return;
1929  }
1931 }
1932 
1933 /*! \brief Add a custom hook to be called when an event is fired */
1935 {
1937  AST_RWLIST_INSERT_TAIL(&manager_hooks, hook, list);
1939 }
1940 
1941 /*! \brief Delete a custom hook to be called when an event is fired */
1943 {
1945  AST_RWLIST_REMOVE(&manager_hooks, hook, list);
1947 }
1948 
1950 {
1951  return manager_enabled;
1952 }
1953 
1955 {
1956  return (webmanager_enabled && manager_enabled);
1957 }
1958 
1959 /*!
1960  * Grab a reference to the last event, update usecount as needed.
1961  * Can handle a NULL pointer.
1962  */
1963 static struct eventqent *grab_last(void)
1964 {
1965  struct eventqent *ret;
1966 
1968  ret = AST_RWLIST_LAST(&all_events);
1969  /* the list is never empty now, but may become so when
1970  * we optimize it in the future, so be prepared.
1971  */
1972  if (ret) {
1974  }
1976  return ret;
1977 }
1978 
1979 /*!
1980  * Purge unused events. Remove elements from the head
1981  * as long as their usecount is 0 and there is a next element.
1982  */
1983 static void purge_events(void)
1984 {
1985  struct eventqent *ev;
1986  struct timeval now = ast_tvnow();
1987 
1989  while ( (ev = AST_RWLIST_FIRST(&all_events)) &&
1990  ev->usecount == 0 && AST_RWLIST_NEXT(ev, eq_next)) {
1992  ast_free(ev);
1993  }
1994 
1996  /* Never release the last event */
1997  if (!AST_RWLIST_NEXT(ev, eq_next)) {
1998  break;
1999  }
2000 
2001  /* 2.5 times whatever the HTTP timeout is (maximum 2.5 hours) is the maximum time that we will definitely cache an event */
2002  if (ev->usecount == 0 && ast_tvdiff_sec(now, ev->tv) > (httptimeout > 3600 ? 3600 : httptimeout) * 2.5) {
2003  AST_RWLIST_REMOVE_CURRENT(eq_next);
2004  ast_free(ev);
2005  }
2006  }
2009 }
2010 
2011 /*!
2012  * helper functions to convert back and forth between
2013  * string and numeric representation of set of flags
2014  */
2015 static const struct permalias {
2016  int num;
2017  const char *label;
2018 } perms[] = {
2019  { EVENT_FLAG_SYSTEM, "system" },
2020  { EVENT_FLAG_CALL, "call" },
2021  { EVENT_FLAG_LOG, "log" },
2022  { EVENT_FLAG_VERBOSE, "verbose" },
2023  { EVENT_FLAG_COMMAND, "command" },
2024  { EVENT_FLAG_AGENT, "agent" },
2025  { EVENT_FLAG_USER, "user" },
2026  { EVENT_FLAG_CONFIG, "config" },
2027  { EVENT_FLAG_DTMF, "dtmf" },
2028  { EVENT_FLAG_REPORTING, "reporting" },
2029  { EVENT_FLAG_CDR, "cdr" },
2030  { EVENT_FLAG_DIALPLAN, "dialplan" },
2031  { EVENT_FLAG_ORIGINATE, "originate" },
2032  { EVENT_FLAG_AGI, "agi" },
2033  { EVENT_FLAG_CC, "cc" },
2034  { EVENT_FLAG_AOC, "aoc" },
2035  { EVENT_FLAG_TEST, "test" },
2036  { EVENT_FLAG_SECURITY, "security" },
2037  { EVENT_FLAG_MESSAGE, "message" },
2038  { INT_MAX, "all" },
2039  { 0, "none" },
2040 };
2041 
2042 /*! Maximum string length of the AMI authority permission string buildable from perms[]. */
2043 #define MAX_AUTH_PERM_STRING 150
2044 
2045 /*! \brief Checks to see if a string which can be used to evaluate functions should be rejected */
2046 static int function_capable_string_allowed_with_auths(const char *evaluating, int writepermlist)
2047 {
2048  if (!(writepermlist & EVENT_FLAG_SYSTEM)
2049  && (
2050  strstr(evaluating, "SHELL") || /* NoOp(${SHELL(rm -rf /)}) */
2051  strstr(evaluating, "EVAL") /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
2052  )) {
2053  return 0;
2054  }
2055  return 1;
2056 }
2057 
2058 /*! \brief Convert authority code to a list of options for a user. This will only
2059  * display those authority codes that have an explicit match on authority */
2060 static const char *user_authority_to_str(int authority, struct ast_str **res)
2061 {
2062  int i;
2063  char *sep = "";
2064 
2065  ast_str_reset(*res);
2066  for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
2067  if ((authority & perms[i].num) == perms[i].num) {
2068  ast_str_append(res, 0, "%s%s", sep, perms[i].label);
2069  sep = ",";
2070  }
2071  }
2072 
2073  if (ast_str_strlen(*res) == 0) {
2074  /* replace empty string with something sensible */
2075  ast_str_append(res, 0, "<none>");
2076  }
2077 
2078  return ast_str_buffer(*res);
2079 }
2080 
2081 
2082 /*! \brief Convert authority code to a list of options. Note that the EVENT_FLAG_ALL
2083  * authority will always be returned. */
2084 static const char *authority_to_str(int authority, struct ast_str **res)
2085 {
2086  int i;
2087  char *sep = "";
2088 
2089  ast_str_reset(*res);
2090  if (authority != EVENT_FLAG_SHUTDOWN) {
2091  for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
2092  if (authority & perms[i].num) {
2093  ast_str_append(res, 0, "%s%s", sep, perms[i].label);
2094  sep = ",";
2095  }
2096  }
2097  }
2098 
2099  if (ast_str_strlen(*res) == 0) {
2100  /* replace empty string with something sensible */
2101  ast_str_append(res, 0, "<none>");
2102  }
2103 
2104  return ast_str_buffer(*res);
2105 }
2106 
2107 /*! Tells you if smallstr exists inside bigstr
2108  which is delim by delim and uses no buf or stringsep
2109  ast_instring("this|that|more","this",'|') == 1;
2110 
2111  feel free to move this to app.c -anthm */
2112 static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
2113 {
2114  const char *val = bigstr, *next;
2115 
2116  do {
2117  if ((next = strchr(val, delim))) {
2118  if (!strncmp(val, smallstr, (next - val))) {
2119  return 1;
2120  } else {
2121  continue;
2122  }
2123  } else {
2124  return !strcmp(smallstr, val);
2125  }
2126  } while (*(val = (next + 1)));
2127 
2128  return 0;
2129 }
2130 
2131 static int get_perm(const char *instr)
2132 {
2133  int x = 0, ret = 0;
2134 
2135  if (!instr) {
2136  return 0;
2137  }
2138 
2139  for (x = 0; x < ARRAY_LEN(perms); x++) {
2140  if (ast_instring(instr, perms[x].label, ',')) {
2141  ret |= perms[x].num;
2142  }
2143  }
2144 
2145  return ret;
2146 }
2147 
2148 /*!
2149  * A number returns itself, false returns 0, true returns all flags,
2150  * other strings return the flags that are set.
2151  */
2152 static int strings_to_mask(const char *string)
2153 {
2154  const char *p;
2155 
2156  if (ast_strlen_zero(string)) {
2157  return -1;
2158  }
2159 
2160  for (p = string; *p; p++) {
2161  if (*p < '0' || *p > '9') {
2162  break;
2163  }
2164  }
2165  if (!*p) { /* all digits */
2166  return atoi(string);
2167  }
2168  if (ast_false(string)) {
2169  return 0;
2170  }
2171  if (ast_true(string)) { /* all permissions */
2172  int x, ret = 0;
2173  for (x = 0; x < ARRAY_LEN(perms); x++) {
2174  ret |= perms[x].num;
2175  }
2176  return ret;
2177  }
2178  return get_perm(string);
2179 }
2180 
2181 /*! \brief Unreference manager session object.
2182  If no more references, then go ahead and delete it */
2184 {
2185  int refcount = ao2_ref(s, -1);
2186  if (manager_debug) {
2187  ast_debug(1, "Mansession: %p refcount now %d\n", s, refcount - 1);
2188  }
2189  return NULL;
2190 }
2191 
2192 static void event_filter_destructor(void *obj)
2193 {
2194  regex_t *regex_filter = obj;
2195  regfree(regex_filter);
2196 }
2197 
2198 static void session_destructor(void *obj)
2199 {
2200  struct mansession_session *session = obj;
2201  struct eventqent *eqe = session->last_ev;
2202  struct ast_datastore *datastore;
2203 
2204  /* Get rid of each of the data stores on the session */
2205  while ((datastore = AST_LIST_REMOVE_HEAD(&session->datastores, entry))) {
2206  /* Free the data store */
2207  ast_datastore_free(datastore);
2208  }
2209 
2210  if (eqe) {
2211  ast_atomic_fetchadd_int(&eqe->usecount, -1);
2212  }
2213  if (session->chanvars) {
2214  ast_variables_destroy(session->chanvars);
2215  }
2216 
2217  if (session->whitefilters) {
2218  ao2_t_ref(session->whitefilters, -1, "decrement ref for white container, should be last one");
2219  }
2220 
2221  if (session->blackfilters) {
2222  ao2_t_ref(session->blackfilters, -1, "decrement ref for black container, should be last one");
2223  }
2224 
2225  ast_mutex_destroy(&session->notify_lock);
2226 }
2227 
2228 /*! \brief Allocate manager session structure and add it to the list of sessions */
2230 {
2231  struct ao2_container *sessions;
2232  struct mansession_session *newsession;
2233 
2234  newsession = ao2_alloc(sizeof(*newsession), session_destructor);
2235  if (!newsession) {
2236  return NULL;
2237  }
2238 
2241  if (!newsession->whitefilters || !newsession->blackfilters) {
2242  ao2_ref(newsession, -1);
2243  return NULL;
2244  }
2245 
2246  newsession->waiting_thread = AST_PTHREADT_NULL;
2247  newsession->writetimeout = 100;
2248  newsession->send_events = -1;
2249  ast_sockaddr_copy(&newsession->addr, addr);
2250 
2251  ast_mutex_init(&newsession->notify_lock);
2252 
2253  sessions = ao2_global_obj_ref(mgr_sessions);
2254  if (sessions) {
2255  ao2_link(sessions, newsession);
2256  ao2_ref(sessions, -1);
2257  }
2258 
2259  return newsession;
2260 }
2261 
2262 static int mansession_cmp_fn(void *obj, void *arg, int flags)
2263 {
2264  struct mansession_session *s = obj;
2265  char *str = arg;
2266  return !strcasecmp(s->username, str) ? CMP_MATCH : 0;
2267 }
2268 
2269 static void session_destroy(struct mansession_session *s)
2270 {
2271  struct ao2_container *sessions;
2272 
2273  sessions = ao2_global_obj_ref(mgr_sessions);
2274  if (sessions) {
2275  ao2_unlink(sessions, s);
2276  ao2_ref(sessions, -1);
2277  }
2278  unref_mansession(s);
2279 }
2280 
2281 
2282 static int check_manager_session_inuse(const char *name)
2283 {
2284  struct ao2_container *sessions;
2285  struct mansession_session *session;
2286  int inuse = 0;
2287 
2288  sessions = ao2_global_obj_ref(mgr_sessions);
2289  if (sessions) {
2290  session = ao2_find(sessions, (char *) name, 0);
2291  ao2_ref(sessions, -1);
2292  if (session) {
2293  unref_mansession(session);
2294  inuse = 1;
2295  }
2296  }
2297  return inuse;
2298 }
2299 
2300 
2301 /*!
2302  * lookup an entry in the list of registered users.
2303  * must be called with the list lock held.
2304  */
2306 {
2307  struct ast_manager_user *user = NULL;
2308 
2309  AST_RWLIST_TRAVERSE(&users, user, list) {
2310  if (!strcasecmp(user->username, name)) {
2311  break;
2312  }
2313  }
2314 
2315  return user;
2316 }
2317 
2318 /*! \brief Get displayconnects config option.
2319  * \param session manager session to get parameter from.
2320  * \return displayconnects config option value.
2321  */
2323 {
2324  struct ast_manager_user *user = NULL;
2325  int ret = 0;
2326 
2328  if ((user = get_manager_by_name_locked(session->username))) {
2329  ret = user->displayconnects;
2330  }
2332 
2333  return ret;
2334 }
2335 
2336 #ifdef AST_XML_DOCS
2337 static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance);
2338 #endif
2339 
2340 static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2341 {
2342  struct manager_action *cur;
2343  struct ast_str *authority;
2344  int num;
2345  int l;
2346  const char *auth_str;
2347 #ifdef AST_XML_DOCS
2348  char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64];
2349  char arguments_title[64], privilege_title[64], final_response_title[64], list_responses_title[64];
2350 #endif
2351 
2352  switch (cmd) {
2353  case CLI_INIT:
2354  e->command = "manager show command";
2355  e->usage =
2356  "Usage: manager show command <actionname> [<actionname> [<actionname> [...]]]\n"
2357  " Shows the detailed description for a specific Asterisk manager interface command.\n";
2358  return NULL;
2359  case CLI_GENERATE:
2360  l = strlen(a->word);
2362  AST_RWLIST_TRAVERSE(&actions, cur, list) {
2363  if (!strncasecmp(a->word, cur->action, l)) {
2365  break;
2366  }
2367  }
2368  }
2370  return NULL;
2371  }
2372  if (a->argc < 4) {
2373  return CLI_SHOWUSAGE;
2374  }
2375 
2376  authority = ast_str_alloca(MAX_AUTH_PERM_STRING);
2377 
2378 #ifdef AST_XML_DOCS
2379  /* setup the titles */
2380  term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2381  term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
2382  term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
2383  term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
2384  term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
2385  term_color(privilege_title, "[Privilege]\n", COLOR_MAGENTA, 0, 40);
2386  term_color(final_response_title, "[Final Response]\n", COLOR_MAGENTA, 0, 40);
2387  term_color(list_responses_title, "[List Responses]\n", COLOR_MAGENTA, 0, 40);
2388 #endif
2389 
2391  AST_RWLIST_TRAVERSE(&actions, cur, list) {
2392  for (num = 3; num < a->argc; num++) {
2393  if (!strcasecmp(cur->action, a->argv[num])) {
2394  auth_str = authority_to_str(cur->authority, &authority);
2395 
2396 #ifdef AST_XML_DOCS
2397  if (cur->docsrc == AST_XML_DOC) {
2398  char *syntax = ast_xmldoc_printable(S_OR(cur->syntax, "Not available"), 1);
2399  char *synopsis = ast_xmldoc_printable(S_OR(cur->synopsis, "Not available"), 1);
2400  char *description = ast_xmldoc_printable(S_OR(cur->description, "Not available"), 1);
2401  char *arguments = ast_xmldoc_printable(S_OR(cur->arguments, "Not available"), 1);
2402  char *seealso = ast_xmldoc_printable(S_OR(cur->seealso, "Not available"), 1);
2403  char *privilege = ast_xmldoc_printable(S_OR(auth_str, "Not available"), 1);
2404  char *responses = ast_xmldoc_printable("None", 1);
2405 
2406  if (!syntax || !synopsis || !description || !arguments
2407  || !seealso || !privilege || !responses) {
2408  ast_free(syntax);
2409  ast_free(synopsis);
2410  ast_free(description);
2411  ast_free(arguments);
2412  ast_free(seealso);
2413  ast_free(privilege);
2414  ast_free(responses);
2415  ast_cli(a->fd, "Allocation failure.\n");
2417 
2418  return CLI_FAILURE;
2419  }
2420 
2421  ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s",
2422  syntax_title, syntax,
2423  synopsis_title, synopsis,
2424  description_title, description,
2425  arguments_title, arguments,
2426  seealso_title, seealso,
2427  privilege_title, privilege,
2428  list_responses_title);
2429 
2430  if (!cur->list_responses) {
2431  ast_cli(a->fd, "%s\n\n", responses);
2432  } else {
2433  struct ast_xml_doc_item *temp;
2434  for (temp = cur->list_responses; temp; temp = AST_LIST_NEXT(temp, next)) {
2435  ast_cli(a->fd, "Event: %s\n", temp->name);
2436  print_event_instance(a, temp);
2437  }
2438  }
2439 
2440  ast_cli(a->fd, "%s", final_response_title);
2441 
2442  if (!cur->final_response) {
2443  ast_cli(a->fd, "%s\n\n", responses);
2444  } else {
2445  ast_cli(a->fd, "Event: %s\n", cur->final_response->name);
2447  }
2448 
2449  ast_free(syntax);
2450  ast_free(synopsis);
2451  ast_free(description);
2452  ast_free(arguments);
2453  ast_free(seealso);
2454  ast_free(privilege);
2455  ast_free(responses);
2456  } else
2457 #endif
2458  {
2459  ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
2460  cur->action, cur->synopsis,
2461  auth_str,
2462  S_OR(cur->description, ""));
2463  }
2464  }
2465  }
2466  }
2468 
2469  return CLI_SUCCESS;
2470 }
2471 
2472 static char *handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2473 {
2474  switch (cmd) {
2475  case CLI_INIT:
2476  e->command = "manager set debug [on|off]";
2477  e->usage = "Usage: manager set debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
2478  return NULL;
2479  case CLI_GENERATE:
2480  return NULL;
2481  }
2482 
2483  if (a->argc == 3) {
2484  ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
2485  } else if (a->argc == 4) {
2486  if (!strcasecmp(a->argv[3], "on")) {
2487  manager_debug = 1;
2488  } else if (!strcasecmp(a->argv[3], "off")) {
2489  manager_debug = 0;
2490  } else {
2491  return CLI_SHOWUSAGE;
2492  }
2493  }
2494  return CLI_SUCCESS;
2495 }
2496 
2497 static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2498 {
2499  struct ast_manager_user *user = NULL;
2500  int l;
2501  struct ast_str *rauthority = ast_str_alloca(MAX_AUTH_PERM_STRING);
2502  struct ast_str *wauthority = ast_str_alloca(MAX_AUTH_PERM_STRING);
2503  struct ast_variable *v;
2504 
2505  switch (cmd) {
2506  case CLI_INIT:
2507  e->command = "manager show user";
2508  e->usage =
2509  " Usage: manager show user <user>\n"
2510  " Display all information related to the manager user specified.\n";
2511  return NULL;
2512  case CLI_GENERATE:
2513  l = strlen(a->word);
2514  if (a->pos != 3) {
2515  return NULL;
2516  }
2518  AST_RWLIST_TRAVERSE(&users, user, list) {
2519  if (!strncasecmp(a->word, user->username, l)) {
2521  break;
2522  }
2523  }
2524  }
2526  return NULL;
2527  }
2528 
2529  if (a->argc != 4) {
2530  return CLI_SHOWUSAGE;
2531  }
2532 
2534 
2535  if (!(user = get_manager_by_name_locked(a->argv[3]))) {
2536  ast_cli(a->fd, "There is no manager called %s\n", a->argv[3]);
2538  return CLI_SUCCESS;
2539  }
2540 
2541  ast_cli(a->fd, "\n");
2542  ast_cli(a->fd,
2543  " username: %s\n"
2544  " secret: %s\n"
2545  " ACL: %s\n"
2546  " read perm: %s\n"
2547  " write perm: %s\n"
2548  " displayconnects: %s\n"
2549  "allowmultiplelogin: %s\n",
2550  S_OR(user->username, "(N/A)"),
2551  (user->secret ? "<Set>" : "(N/A)"),
2552  ((user->acl && !ast_acl_list_is_empty(user->acl)) ? "yes" : "no"),
2553  user_authority_to_str(user->readperm, &rauthority),
2554  user_authority_to_str(user->writeperm, &wauthority),
2555  (user->displayconnects ? "yes" : "no"),
2556  (user->allowmultiplelogin ? "yes" : "no"));
2557  ast_cli(a->fd, " Variables: \n");
2558  for (v = user->chanvars ; v ; v = v->next) {
2559  ast_cli(a->fd, " %s = %s\n", v->name, v->value);
2560  }
2561  if (!ast_acl_list_is_empty(user->acl)) {
2562  ast_acl_output(a->fd, user->acl, NULL);
2563  }
2564 
2566 
2567  return CLI_SUCCESS;
2568 }
2569 
2570 static char *handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2571 {
2572  struct ast_manager_user *user = NULL;
2573  int count_amu = 0;
2574  switch (cmd) {
2575  case CLI_INIT:
2576  e->command = "manager show users";
2577  e->usage =
2578  "Usage: manager show users\n"
2579  " Prints a listing of all managers that are currently configured on that\n"
2580  " system.\n";
2581  return NULL;
2582  case CLI_GENERATE:
2583  return NULL;
2584  }
2585  if (a->argc != 3) {
2586  return CLI_SHOWUSAGE;
2587  }
2588 
2590 
2591  /* If there are no users, print out something along those lines */
2592  if (AST_RWLIST_EMPTY(&users)) {
2593  ast_cli(a->fd, "There are no manager users.\n");
2595  return CLI_SUCCESS;
2596  }
2597 
2598  ast_cli(a->fd, "\nusername\n--------\n");
2599 
2600  AST_RWLIST_TRAVERSE(&users, user, list) {
2601  ast_cli(a->fd, "%s\n", user->username);
2602  count_amu++;
2603  }
2604 
2606 
2607  ast_cli(a->fd,"-------------------\n"
2608  "%d manager users configured.\n", count_amu);
2609  return CLI_SUCCESS;
2610 }
2611 
2612 /*! \brief CLI command manager list commands */
2613 static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2614 {
2615  struct manager_action *cur;
2616  int name_len = 1;
2617  int space_remaining;
2618 #define HSMC_FORMAT " %-*.*s %-.*s\n"
2619  switch (cmd) {
2620  case CLI_INIT:
2621  e->command = "manager show commands";
2622  e->usage =
2623  "Usage: manager show commands\n"
2624  " Prints a listing of all the available Asterisk manager interface commands.\n";
2625  return NULL;
2626  case CLI_GENERATE:
2627  return NULL;
2628  }
2629 
2631  AST_RWLIST_TRAVERSE(&actions, cur, list) {
2632  int incoming_len = strlen(cur->action);
2633  if (incoming_len > name_len) {
2634  name_len = incoming_len;
2635  }
2636  }
2637 
2638  space_remaining = MGR_SHOW_TERMINAL_WIDTH - name_len - 4;
2639  if (space_remaining < 0) {
2640  space_remaining = 0;
2641  }
2642 
2643  ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, "Action", space_remaining, "Synopsis");
2644  ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, "------", space_remaining, "--------");
2645 
2646  AST_RWLIST_TRAVERSE(&actions, cur, list) {
2647  ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, cur->action, space_remaining, cur->synopsis);
2648  }
2650 
2651  return CLI_SUCCESS;
2652 }
2653 
2654 /*! \brief CLI command manager list connected */
2655 static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2656 {
2657  struct ao2_container *sessions;
2658  struct mansession_session *session;
2659  time_t now = time(NULL);
2660 #define HSMCONN_FORMAT1 " %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
2661 #define HSMCONN_FORMAT2 " %-15.15s %-55.55s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
2662  int count = 0;
2663  struct ao2_iterator i;
2664 
2665  switch (cmd) {
2666  case CLI_INIT:
2667  e->command = "manager show connected";
2668  e->usage =
2669  "Usage: manager show connected\n"
2670  " Prints a listing of the users that are currently connected to the\n"
2671  "Asterisk manager interface.\n";
2672  return NULL;
2673  case CLI_GENERATE:
2674  return NULL;
2675  }
2676 
2677  ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
2678 
2679  sessions = ao2_global_obj_ref(mgr_sessions);
2680  if (sessions) {
2681  i = ao2_iterator_init(sessions, 0);
2682  ao2_ref(sessions, -1);
2683  while ((session = ao2_iterator_next(&i))) {
2684  ao2_lock(session);
2685  ast_cli(a->fd, HSMCONN_FORMAT2, session->username,
2686  ast_sockaddr_stringify_addr(&session->addr),
2687  (int) (session->sessionstart),
2688  (int) (now - session->sessionstart),
2689  session->stream ? ast_iostream_get_fd(session->stream) : -1,
2690  session->inuse,
2691  session->readperm,
2692  session->writeperm);
2693  count++;
2694  ao2_unlock(session);
2695  unref_mansession(session);
2696  }
2698  }
2699  ast_cli(a->fd, "%d users connected.\n", count);
2700 
2701  return CLI_SUCCESS;
2702 }
2703 
2704 /*! \brief CLI command manager list eventq */
2705 /* Should change to "manager show connected" */
2706 static char *handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2707 {
2708  struct eventqent *s;
2709  switch (cmd) {
2710  case CLI_INIT:
2711  e->command = "manager show eventq";
2712  e->usage =
2713  "Usage: manager show eventq\n"
2714  " Prints a listing of all events pending in the Asterisk manger\n"
2715  "event queue.\n";
2716  return NULL;
2717  case CLI_GENERATE:
2718  return NULL;
2719  }
2721  AST_RWLIST_TRAVERSE(&all_events, s, eq_next) {
2722  ast_cli(a->fd, "Usecount: %d\n", s->usecount);
2723  ast_cli(a->fd, "Category: %d\n", s->category);
2724  ast_cli(a->fd, "Event:\n%s", s->eventdata);
2725  }
2727 
2728  return CLI_SUCCESS;
2729 }
2730 
2731 static int reload_module(void);
2732 
2733 /*! \brief CLI command manager reload */
2734 static char *handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2735 {
2736  switch (cmd) {
2737  case CLI_INIT:
2738  e->command = "manager reload";
2739  e->usage =
2740  "Usage: manager reload\n"
2741  " Reloads the manager configuration.\n";
2742  return NULL;
2743  case CLI_GENERATE:
2744  return NULL;
2745  }
2746  if (a->argc > 2) {
2747  return CLI_SHOWUSAGE;
2748  }
2749  reload_module();
2750  return CLI_SUCCESS;
2751 }
2752 
2753 static struct eventqent *advance_event(struct eventqent *e)
2754 {
2755  struct eventqent *next;
2756 
2758  if ((next = AST_RWLIST_NEXT(e, eq_next))) {
2759  ast_atomic_fetchadd_int(&next->usecount, 1);
2761  }
2763  return next;
2764 }
2765 
2766 #define GET_HEADER_FIRST_MATCH 0
2767 #define GET_HEADER_LAST_MATCH 1
2768 #define GET_HEADER_SKIP_EMPTY 2
2769 
2770 /*!
2771  * \brief Return a matching header value.
2772  *
2773  * \details
2774  * Generic function to return either the first or the last
2775  * matching header from a list of variables, possibly skipping
2776  * empty strings.
2777  *
2778  * \note At the moment there is only one use of this function in
2779  * this file, so we make it static.
2780  *
2781  * \note Never returns NULL.
2782  */
2783 static const char *__astman_get_header(const struct message *m, char *var, int mode)
2784 {
2785  int x, l = strlen(var);
2786  const char *result = "";
2787 
2788  if (!m) {
2789  return result;
2790  }
2791 
2792  for (x = 0; x < m->hdrcount; x++) {
2793  const char *h = m->headers[x];
2794  if (!strncasecmp(var, h, l) && h[l] == ':') {
2795  const char *value = h + l + 1;
2796  value = ast_skip_blanks(value); /* ignore leading spaces in the value */
2797  /* found a potential candidate */
2798  if ((mode & GET_HEADER_SKIP_EMPTY) && ast_strlen_zero(value)) {
2799  continue; /* not interesting */
2800  }
2801  if (mode & GET_HEADER_LAST_MATCH) {
2802  result = value; /* record the last match so far */
2803  } else {
2804  return value;
2805  }
2806  }
2807  }
2808 
2809  return result;
2810 }
2811 
2812 /*!
2813  * \brief Return the first matching variable from an array.
2814  *
2815  * \note This is the legacy function and is implemented in
2816  * therms of __astman_get_header().
2817  *
2818  * \note Never returns NULL.
2819  */
2820 const char *astman_get_header(const struct message *m, char *var)
2821 {
2823 }
2824 
2825 /*!
2826  * \brief Append additional headers into the message structure from params.
2827  *
2828  * \note You likely want to initialize m->hdrcount to 0 before calling this.
2829  */
2830 static void astman_append_headers(struct message *m, const struct ast_variable *params)
2831 {
2832  const struct ast_variable *v;
2833 
2834  for (v = params; v && m->hdrcount < ARRAY_LEN(m->headers); v = v->next) {
2835  if (ast_asprintf((char**)&m->headers[m->hdrcount], "%s: %s", v->name, v->value) > -1) {
2836  ++m->hdrcount;
2837  }
2838  }
2839 }
2840 
2841 /*!
2842  * \brief Free headers inside message structure, but not the message structure itself.
2843  */
2844 static void astman_free_headers(struct message *m)
2845 {
2846  while (m->hdrcount) {
2847  --m->hdrcount;
2848  ast_free((void *) m->headers[m->hdrcount]);
2849  m->headers[m->hdrcount] = NULL;
2850  }
2851 }
2852 
2853 /*!
2854  * \internal
2855  * \brief Process one "Variable:" header value string.
2856  *
2857  * \param head Current list of AMI variables to get new values added.
2858  * \param hdr_val Header value string to process.
2859  *
2860  * \return New variable list head.
2861  */
2862 static struct ast_variable *man_do_variable_value(struct ast_variable *head, const char *hdr_val)
2863 {
2864  char *parse;
2866  AST_APP_ARG(vars)[64];
2867  );
2868 
2869  hdr_val = ast_skip_blanks(hdr_val); /* ignore leading spaces in the value */
2870  parse = ast_strdupa(hdr_val);
2871 
2872  /* Break the header value string into name=val pair items. */
2873  AST_STANDARD_APP_ARGS(args, parse);
2874  if (args.argc) {
2875  int y;
2876 
2877  /* Process each name=val pair item. */
2878  for (y = 0; y < args.argc; y++) {
2879  struct ast_variable *cur;
2880  char *var;
2881  char *val;
2882 
2883  if (!args.vars[y]) {
2884  continue;
2885  }
2886  var = val = args.vars[y];
2887  strsep(&val, "=");
2888 
2889  /* XXX We may wish to trim whitespace from the strings. */
2890  if (!val || ast_strlen_zero(var)) {
2891  continue;
2892  }
2893 
2894  /* Create new variable list node and prepend it to the list. */
2895  cur = ast_variable_new(var, val, "");
2896  if (cur) {
2897  cur->next = head;
2898  head = cur;
2899  }
2900  }
2901  }
2902 
2903  return head;
2904 }
2905 
2906 struct ast_variable *astman_get_variables(const struct message *m)
2907 {
2909 }
2910 
2911 struct ast_variable *astman_get_variables_order(const struct message *m,
2912  enum variable_orders order)
2913 {
2914  int varlen;
2915  int x;
2916  struct ast_variable *head = NULL;
2917 
2918  static const char var_hdr[] = "Variable:";
2919 
2920  /* Process all "Variable:" headers. */
2921  varlen = strlen(var_hdr);
2922  for (x = 0; x < m->hdrcount; x++) {
2923  if (strncasecmp(var_hdr, m->headers[x], varlen)) {
2924  continue;
2925  }
2926  head = man_do_variable_value(head, m->headers[x] + varlen);
2927  }
2928 
2929  if (order == ORDER_NATURAL) {
2930  head = ast_variables_reverse(head);
2931  }
2932 
2933  return head;
2934 }
2935 
2936 /*! \brief access for hooks to send action messages to ami */
2937 int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
2938 {
2939  const char *action;
2940  int ret = 0;
2941  struct manager_action *act_found;
2942  struct mansession s = {.session = NULL, };
2943  struct message m = { 0 };
2944  char *dup_str;
2945  char *src;
2946  int x = 0;
2947  int curlen;
2948 
2949  if (hook == NULL) {
2950  return -1;
2951  }
2952 
2953  /* Create our own copy of the AMI action msg string. */
2954  src = dup_str = ast_strdup(msg);
2955  if (!dup_str) {
2956  return -1;
2957  }
2958 
2959  /* convert msg string to message struct */
2960  curlen = strlen(src);
2961  for (x = 0; x < curlen; x++) {
2962  int cr; /* set if we have \r */
2963  if (src[x] == '\r' && x+1 < curlen && src[x+1] == '\n')
2964  cr = 2; /* Found. Update length to include \r\n */
2965  else if (src[x] == '\n')
2966  cr = 1; /* also accept \n only */
2967  else
2968  continue;
2969  /* don't keep empty lines */
2970  if (x && m.hdrcount < ARRAY_LEN(m.headers)) {
2971  /* ... but trim \r\n and terminate the header string */
2972  src[x] = '\0';
2973  m.headers[m.hdrcount++] = src;
2974  }
2975  x += cr;
2976  curlen -= x; /* remaining size */
2977  src += x; /* update pointer */
2978  x = -1; /* reset loop */
2979  }
2980 
2981  action = astman_get_header(&m, "Action");
2982 
2983  do {
2984  if (!strcasecmp(action, "login")) {
2985  break;
2986  }
2987 
2988  act_found = action_find(action);
2989  if (!act_found) {
2990  break;
2991  }
2992 
2993  /*
2994  * we have to simulate a session for this action request
2995  * to be able to pass it down for processing
2996  * This is necessary to meet the previous design of manager.c
2997  */
2998  s.hook = hook;
2999 
3000  ret = -1;
3001  ao2_lock(act_found);
3002  if (act_found->registered && act_found->func) {
3003  struct ast_module *mod_ref = ast_module_running_ref(act_found->module);
3004 
3005  ao2_unlock(act_found);
3006  /* If the action is in a module it must be running. */
3007  if (!act_found->module || mod_ref) {
3008  ret = act_found->func(&s, &m);
3009  ast_module_unref(mod_ref);
3010  }
3011  } else {
3012  ao2_unlock(act_found);
3013  }
3014  ao2_t_ref(act_found, -1, "done with found action object");
3015  } while (0);
3016 
3017  ast_free(dup_str);
3018  return ret;
3019 }
3020 
3021 /*!
3022  * helper function to send a string to the socket.
3023  * Return -1 on error (e.g. buffer full).
3024  */
3025 static int send_string(struct mansession *s, char *string)
3026 {
3027  struct ast_iostream *stream;
3028  int len, res;
3029 
3030  /* It's a result from one of the hook's action invocation */
3031  if (s->hook) {
3032  /*
3033  * to send responses, we're using the same function
3034  * as for receiving events. We call the event "HookResponse"
3035  */
3036  s->hook->helper(EVENT_FLAG_HOOKRESPONSE, "HookResponse", string);
3037  return 0;
3038  }
3039 
3040  stream = s->stream ? s->stream : s->session->stream;
3041 
3042  len = strlen(string);
3044  res = ast_iostream_write(stream, string, len);
3046 
3047  if (res < len) {
3048  s->write_error = 1;
3049  }
3050 
3051  return res;
3052 }
3053 
3054 /*!
3055  * \brief thread local buffer for astman_append
3056  *
3057  * \note This can not be defined within the astman_append() function
3058  * because it declares a couple of functions that get used to
3059  * initialize the thread local storage key.
3060  */
3062 
3064 
3065 /*! \brief initial allocated size for the astman_append_buf and astman_send_*_va */
3066 #define ASTMAN_APPEND_BUF_INITSIZE 256
3067 
3068 static void astman_flush(struct mansession *s, struct ast_str *buf)
3069 {
3070  if (s->hook || (s->tcptls_session && s->tcptls_session->stream)) {
3071  send_string(s, ast_str_buffer(buf));
3072  } else {
3073  ast_verbose("No connection stream in astman_append, should not happen\n");
3074  }
3075 }
3076 
3077 /*!
3078  * utility functions for creating AMI replies
3079  */
3080 void astman_append(struct mansession *s, const char *fmt, ...)
3081 {
3082  int res;
3083  va_list ap;
3084  struct ast_str *buf;
3085 
3087  return;
3088  }
3089 
3090  va_start(ap, fmt);
3091  res = ast_str_set_va(&buf, 0, fmt, ap);
3092  va_end(ap);
3093  if (res == AST_DYNSTR_BUILD_FAILED) {
3094  return;
3095  }
3096 
3097  if (s->hook || (s->tcptls_session != NULL && s->tcptls_session->stream != NULL)) {
3098  send_string(s, ast_str_buffer(buf));
3099  } else {
3100  ast_verbose("No connection stream in astman_append, should not happen\n");
3101  }
3102 }
3103 
3104 /*! \note NOTE: XXX this comment is unclear and possibly wrong.
3105  Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
3106  hold the session lock _or_ be running in an action callback (in which case s->session->busy will
3107  be non-zero). In either of these cases, there is no need to lock-protect the session's
3108  fd, since no other output will be sent (events will be queued), and no input will
3109  be read until either the current action finishes or get_input() obtains the session
3110  lock.
3111  */
3112 
3113 /*! \todo XXX MSG_MOREDATA should go to a header file. */
3114 #define MSG_MOREDATA ((char *)astman_send_response)
3115 
3116 /*! \brief send a response with an optional message,
3117  * and terminate it with an empty line.
3118  * m is used only to grab the 'ActionID' field.
3119  *
3120  * Use the explicit constant MSG_MOREDATA to remove the empty line.
3121  * XXX MSG_MOREDATA should go to a header file.
3122  */
3123 static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
3124 {
3125  const char *id = astman_get_header(m, "ActionID");
3126  struct ast_str *buf;
3127 
3129  if (!buf) {
3130  return;
3131  }
3132 
3133  ast_str_set(&buf, 0, "Response: %s\r\n", resp);
3134 
3135  if (!ast_strlen_zero(id)) {
3136  ast_str_append(&buf, 0, "ActionID: %s\r\n", id);
3137  }
3138 
3139  if (listflag) {
3140  /* Start, complete, cancelled */
3141  ast_str_append(&buf, 0, "EventList: %s\r\n", listflag);
3142  }
3143 
3144  if (msg != MSG_MOREDATA) {
3145  if (msg) {
3146  ast_str_append(&buf, 0, "Message: %s\r\n", msg);
3147  }
3148  ast_str_append(&buf, 0, "\r\n");
3149  }
3150 
3151  astman_flush(s, buf);
3152 }
3153 
3154 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
3155 {
3156  astman_send_response_full(s, m, resp, msg, NULL);
3157 }
3158 
3159 void astman_send_error(struct mansession *s, const struct message *m, char *error)
3160 {
3161  astman_send_response_full(s, m, "Error", error, NULL);
3162 }
3163 
3164 void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt, ...)
3165 {
3166  int res;
3167  va_list ap;
3168  struct ast_str *buf;
3169  char *msg;
3170 
3172  return;
3173  }
3174 
3175  va_start(ap, fmt);
3176  res = ast_str_set_va(&buf, 0, fmt, ap);
3177  va_end(ap);
3178  if (res == AST_DYNSTR_BUILD_FAILED) {
3179  return;
3180  }
3181 
3182  /* astman_append will use the same underlying buffer, so copy the message out
3183  * before sending the response */
3184  msg = ast_str_buffer(buf);
3185  if (msg) {
3186  msg = ast_strdupa(msg);
3187  }
3188  astman_send_response_full(s, m, "Error", msg, NULL);
3189 }
3190 
3191 void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
3192 {
3193  astman_send_response_full(s, m, "Success", msg, NULL);
3194 }
3195 
3196 static void astman_start_ack(struct mansession *s, const struct message *m)
3197 {
3198  astman_send_response_full(s, m, "Success", MSG_MOREDATA, NULL);
3199 }
3200 
3201 void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
3202 {
3203  astman_send_response_full(s, m, "Success", msg, listflag);
3204 }
3205 
3206 static struct ast_str *astman_send_list_complete_start_common(struct mansession *s, const struct message *m, const char *event_name, int count)
3207 {
3208  const char *id = astman_get_header(m, "ActionID");
3209  struct ast_str *buf;
3210 
3212  if (!buf) {
3213  return NULL;
3214  }
3215 
3216  ast_str_set(&buf, 0, "Event: %s\r\n", event_name);
3217  if (!ast_strlen_zero(id)) {
3218  ast_str_append(&buf, 0, "ActionID: %s\r\n", id);
3219  }
3220  ast_str_append(&buf, 0,
3221  "EventList: Complete\r\n"
3222  "ListItems: %d\r\n",
3223  count);
3224 
3225  return buf;
3226 }
3227 
3228 static void astman_send_list_complete(struct mansession *s, const struct message *m, const char *event_name, int count)
3229 {
3230  struct ast_str *buf = astman_send_list_complete_start_common(s, m, event_name, count);
3231  if (buf) {
3232  ast_str_append(&buf, 0, "\r\n");
3233  astman_flush(s, buf);
3234  }
3235 }
3236 
3237 void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
3238 {
3239  struct ast_str *buf = astman_send_list_complete_start_common(s, m, event_name, count);
3240  if (buf) {
3241  astman_flush(s, buf);
3242  }
3243 }
3244 
3246 {
3247  astman_append(s, "\r\n");
3248 }
3249 
3250 /*! \brief Lock the 'mansession' structure. */
3251 static void mansession_lock(struct mansession *s)
3252 {
3253  ast_mutex_lock(&s->lock);
3254 }
3255 
3256 /*! \brief Unlock the 'mansession' structure. */
3257 static void mansession_unlock(struct mansession *s)
3258 {
3259  ast_mutex_unlock(&s->lock);
3260 }
3261 
3262 /*! \brief
3263  Rather than braindead on,off this now can also accept a specific int mask value
3264  or a ',' delim list of mask strings (the same as manager.conf) -anthm
3265 */
3266 static int set_eventmask(struct mansession *s, const char *eventmask)
3267 {
3268  int maskint = strings_to_mask(eventmask);
3269 
3270  ao2_lock(s->session);
3271  if (maskint >= 0) {
3272  s->session->send_events = maskint;
3273  }
3274  ao2_unlock(s->session);
3275 
3276  return maskint;
3277 }
3278 
3280 {
3283 }
3284 
3285 static void report_invalid_user(const struct mansession *s, const char *username)
3286 {
3287  char session_id[32];
3288  struct ast_security_event_inval_acct_id inval_acct_id = {
3290  .common.version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
3291  .common.service = "AMI",
3292  .common.account_id = username,
3293  .common.session_tv = &s->session->sessionstart_tv,
3294  .common.local_addr = {
3295  .addr = &s->tcptls_session->parent->local_address,
3296  .transport = mansession_get_transport(s),
3297  },
3298  .common.remote_addr = {
3299  .addr = &s->session->addr,
3300  .transport = mansession_get_transport(s),
3301  },
3302  .common.session_id = session_id,
3303  };
3304 
3305  snprintf(session_id, sizeof(session_id), "%p", s);
3306 
3307  ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
3308 }
3309 
3310 static void report_failed_acl(const struct mansession *s, const char *username)
3311 {
3312  char session_id[32];
3313  struct ast_security_event_failed_acl failed_acl_event = {
3315  .common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
3316  .common.service = "AMI",
3317  .common.account_id = username,
3318  .common.session_tv = &s->session->sessionstart_tv,
3319  .common.local_addr = {
3320  .addr = &s->tcptls_session->parent->local_address,
3321  .transport = mansession_get_transport(s),
3322  },
3323  .common.remote_addr = {
3324  .addr = &s->session->addr,
3325  .transport = mansession_get_transport(s),
3326  },
3327  .common.session_id = session_id,
3328  };
3329 
3330  snprintf(session_id, sizeof(session_id), "%p", s->session);
3331 
3332  ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
3333 }
3334 
3335 static void report_inval_password(const struct mansession *s, const char *username)
3336 {
3337  char session_id[32];
3338  struct ast_security_event_inval_password inval_password = {
3341  .common.service = "AMI",
3342  .common.account_id = username,
3343  .common.session_tv = &s->session->sessionstart_tv,
3344  .common.local_addr = {
3345  .addr = &s->tcptls_session->parent->local_address,
3346  .transport = mansession_get_transport(s),
3347  },
3348  .common.remote_addr = {
3349  .addr = &s->session->addr,
3350  .transport = mansession_get_transport(s),
3351  },
3352  .common.session_id = session_id,
3353  };
3354 
3355  snprintf(session_id, sizeof(session_id), "%p", s->session);
3356 
3357  ast_security_event_report(AST_SEC_EVT(&inval_password));
3358 }
3359 
3360 static void report_auth_success(const struct mansession *s)
3361 {
3362  char session_id[32];
3363  struct ast_security_event_successful_auth successful_auth = {
3366  .common.service = "AMI",
3367  .common.account_id = s->session->username,
3368  .common.session_tv = &s->session->sessionstart_tv,
3369  .common.local_addr = {
3370  .addr = &s->tcptls_session->parent->local_address,
3371  .transport = mansession_get_transport(s),
3372  },
3373  .common.remote_addr = {
3374  .addr = &s->session->addr,
3375  .transport = mansession_get_transport(s),
3376  },
3377  .common.session_id = session_id,
3378  };
3379 
3380  snprintf(session_id, sizeof(session_id), "%p", s->session);
3381 
3382  ast_security_event_report(AST_SEC_EVT(&successful_auth));
3383 }
3384 
3385 static void report_req_not_allowed(const struct mansession *s, const char *action)
3386 {
3387  char session_id[32];
3388  char request_type[64];
3389  struct ast_security_event_req_not_allowed req_not_allowed = {
3392  .common.service = "AMI",
3393  .common.account_id = s->session->username,
3394  .common.session_tv = &s->session->sessionstart_tv,
3395  .common.local_addr = {
3396  .addr = &s->tcptls_session->parent->local_address,
3397  .transport = mansession_get_transport(s),
3398  },
3399  .common.remote_addr = {
3400  .addr = &s->session->addr,
3401  .transport = mansession_get_transport(s),
3402  },
3403  .common.session_id = session_id,
3404 
3405  .request_type = request_type,
3406  };
3407 
3408  snprintf(session_id, sizeof(session_id), "%p", s->session);
3409  snprintf(request_type, sizeof(request_type), "Action: %s", action);
3410 
3411  ast_security_event_report(AST_SEC_EVT(&req_not_allowed));
3412 }
3413 
3414 static void report_req_bad_format(const struct mansession *s, const char *action)
3415 {
3416  char session_id[32];
3417  char request_type[64];
3418  struct ast_security_event_req_bad_format req_bad_format = {
3421  .common.service = "AMI",
3422  .common.account_id = s->session->username,
3423  .common.session_tv = &s->session->sessionstart_tv,
3424  .common.local_addr = {
3425  .addr = &s->tcptls_session->parent->local_address,
3426  .transport = mansession_get_transport(s),
3427  },
3428  .common.remote_addr = {
3429  .addr = &s->session->addr,
3430  .transport = mansession_get_transport(s),
3431  },
3432  .common.session_id = session_id,
3433 
3434  .request_type = request_type,
3435  };
3436 
3437  snprintf(session_id, sizeof(session_id), "%p", s->session);
3438  snprintf(request_type, sizeof(request_type), "Action: %s", action);
3439 
3440  ast_security_event_report(AST_SEC_EVT(&req_bad_format));
3441 }
3442 
3443 static void report_failed_challenge_response(const struct mansession *s,
3444  const char *response, const char *expected_response)
3445 {
3446  char session_id[32];
3447  struct ast_security_event_chal_resp_failed chal_resp_failed = {
3450  .common.service = "AMI",
3451  .common.account_id = s->session->username,
3452  .common.session_tv = &s->session->sessionstart_tv,
3453  .common.local_addr = {
3454  .addr = &s->tcptls_session->parent->local_address,
3455  .transport = mansession_get_transport(s),
3456  },
3457  .common.remote_addr = {
3458  .addr = &s->session->addr,
3459  .transport = mansession_get_transport(s),
3460  },
3461  .common.session_id = session_id,
3462 
3463  .challenge = s->session->challenge,
3464  .response = response,
3465  .expected_response = expected_response,
3466  };
3467 
3468  snprintf(session_id, sizeof(session_id), "%p", s->session);
3469 
3470  ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
3471 }
3472 
3473 static void report_session_limit(const struct mansession *s)
3474 {
3475  char session_id[32];
3476  struct ast_security_event_session_limit session_limit = {
3478  .common.version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
3479  .common.service = "AMI",
3480  .common.account_id = s->session->username,
3481  .common.session_tv = &s->session->sessionstart_tv,
3482  .common.local_addr = {
3483  .addr = &s->tcptls_session->parent->local_address,
3484  .transport = mansession_get_transport(s),
3485  },
3486  .common.remote_addr = {
3487  .addr = &s->session->addr,
3488  .transport = mansession_get_transport(s),
3489  },
3490  .common.session_id = session_id,
3491  };
3492 
3493  snprintf(session_id, sizeof(session_id), "%p", s->session);
3494 
3495  ast_security_event_report(AST_SEC_EVT(&session_limit));
3496 }
3497 
3498 /*
3499  * Here we start with action_ handlers for AMI actions,
3500  * and the internal functions used by them.
3501  * Generally, the handlers are called action_foo()
3502  */
3503 
3504 /* helper function for action_login() */
3505 static int authenticate(struct mansession *s, const struct message *m)
3506 {
3507  const char *username = astman_get_header(m, "Username");
3508  const char *password = astman_get_header(m, "Secret");
3509  int error = -1;
3510  struct ast_manager_user *user = NULL;
3511  regex_t *regex_filter;
3512  struct ao2_iterator filter_iter;
3513 
3514  if (ast_strlen_zero(username)) { /* missing username */
3515  return -1;
3516  }
3517 
3518  /* locate user in locked state */
3520 
3521  if (!(user = get_manager_by_name_locked(username))) {
3522  report_invalid_user(s, username);
3523  ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3524  } else if (user->acl && (ast_apply_acl(user->acl, &s->session->addr, "Manager User ACL: ") == AST_SENSE_DENY)) {
3525  report_failed_acl(s, username);
3526  ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3527  } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
3528  const char *key = astman_get_header(m, "Key");
3529  if (!ast_strlen_zero(key) && !ast_strlen_zero(s->session->challenge) && user->secret) {
3530  int x;
3531  int len = 0;
3532  char md5key[256] = "";
3533  struct MD5Context md5;
3534  unsigned char digest[16];
3535 
3536  MD5Init(&md5);
3537  MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
3538  MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
3539  MD5Final(digest, &md5);
3540  for (x = 0; x < 16; x++)
3541  len += sprintf(md5key + len, "%02hhx", digest[x]);
3542  if (!strcmp(md5key, key)) {
3543  error = 0;
3544  } else {
3545  report_failed_challenge_response(s, key, md5key);
3546  }
3547  } else {
3548  ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
3549  S_OR(s->session->challenge, ""));
3550  }
3551  } else if (user->secret) {
3552  if (!strcmp(password, user->secret)) {
3553  error = 0;
3554  } else {
3555  report_inval_password(s, username);
3556  }
3557  }
3558 
3559  if (error) {
3560  ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3562  return -1;
3563  }
3564 
3565  /* auth complete */
3566 
3567  /* All of the user parameters are copied to the session so that in the event
3568  * of a reload and a configuration change, the session parameters are not
3569  * changed. */
3570  ast_copy_string(s->session->username, username, sizeof(s->session->username));
3571  s->session->readperm = user->readperm;
3572  s->session->writeperm = user->writeperm;
3573  s->session->writetimeout = user->writetimeout;
3574  if (user->chanvars) {
3576  }
3577 
3578  filter_iter = ao2_iterator_init(user->whitefilters, 0);
3579  while ((regex_filter = ao2_iterator_next(&filter_iter))) {
3580  ao2_t_link(s->session->whitefilters, regex_filter, "add white user filter to session");
3581  ao2_t_ref(regex_filter, -1, "remove iterator ref");
3582  }
3583  ao2_iterator_destroy(&filter_iter);
3584 
3585  filter_iter = ao2_iterator_init(user->blackfilters, 0);
3586  while ((regex_filter = ao2_iterator_next(&filter_iter))) {
3587  ao2_t_link(s->session->blackfilters, regex_filter, "add black user filter to session");
3588  ao2_t_ref(regex_filter, -1, "remove iterator ref");
3589  }
3590  ao2_iterator_destroy(&filter_iter);
3591 
3592  s->session->sessionstart = time(NULL);
3594  set_eventmask(s, astman_get_header(m, "Events"));
3595 
3597 
3599  return 0;
3600 }
3601 
3602 static int action_ping(struct mansession *s, const struct message *m)
3603 {
3604  const char *actionid = astman_get_header(m, "ActionID");
3605  struct timeval now = ast_tvnow();
3606 
3607  astman_append(s, "Response: Success\r\n");
3608  if (!ast_strlen_zero(actionid)){
3609  astman_append(s, "ActionID: %s\r\n", actionid);
3610  }
3611  astman_append(
3612  s,
3613  "Ping: Pong\r\n"
3614  "Timestamp: %ld.%06lu\r\n"
3615  "\r\n",
3616  (long) now.tv_sec, (unsigned long) now.tv_usec);
3617  return 0;
3618 }
3619 
3620 static int action_getconfig(struct mansession *s, const struct message *m)
3621 {
3622  struct ast_config *cfg;
3623  const char *fn = astman_get_header(m, "Filename");
3624  const char *category = astman_get_header(m, "Category");
3625  const char *filter = astman_get_header(m, "Filter");
3626  const char *category_name;
3627  int catcount = 0;
3628  int lineno = 0;
3629  struct ast_category *cur_category = NULL;
3630  struct ast_variable *v;
3631  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3632 
3633  if (ast_strlen_zero(fn)) {
3634  astman_send_error(s, m, "Filename not specified");
3635  return 0;
3636  }
3637 
3638  cfg = ast_config_load2(fn, "manager", config_flags);
3639  if (cfg == CONFIG_STATUS_FILEMISSING) {
3640  astman_send_error(s, m, "Config file not found");
3641  return 0;
3642  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
3643  astman_send_error(s, m, "Config file has invalid format");
3644  return 0;
3645  }
3646 
3647  astman_start_ack(s, m);
3648  while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
3649  struct ast_str *templates;
3650 
3651  category_name = ast_category_get_name(cur_category);
3652  lineno = 0;
3653  astman_append(s, "Category-%06d: %s\r\n", catcount, category_name);
3654 
3655  if (ast_category_is_template(cur_category)) {
3656  astman_append(s, "IsTemplate-%06d: %d\r\n", catcount, 1);
3657  }
3658 
3659  if ((templates = ast_category_get_templates(cur_category))
3660  && ast_str_strlen(templates) > 0) {
3661  astman_append(s, "Templates-%06d: %s\r\n", catcount, ast_str_buffer(templates));
3662  ast_free(templates);
3663  }
3664 
3665  for (v = ast_category_first(cur_category); v; v = v->next) {
3666  astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
3667  }
3668 
3669  catcount++;
3670  }
3671 
3672  if (!ast_strlen_zero(category) && catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
3673  astman_append(s, "No categories found\r\n");
3674  }
3675 
3676  ast_config_destroy(cfg);
3677  astman_append(s, "\r\n");
3678 
3679  return 0;
3680 }
3681 
3682 static int action_listcategories(struct mansession *s, const struct message *m)
3683 {
3684  struct ast_config *cfg;
3685  const char *fn = astman_get_header(m, "Filename");
3686  const char *match = astman_get_header(m, "Match");
3687  struct ast_category *category = NULL;
3688  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3689  int catcount = 0;
3690 
3691  if (ast_strlen_zero(fn)) {
3692  astman_send_error(s, m, "Filename not specified");
3693  return 0;
3694  }
3695 
3696  if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
3697  astman_send_error(s, m, "Config file not found");
3698  return 0;
3699  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
3700  astman_send_error(s, m, "Config file has invalid format");
3701  return 0;
3702  }
3703 
3704  astman_start_ack(s, m);
3705  while ((category = ast_category_browse_filtered(cfg, NULL, category, match))) {
3706  astman_append(s, "Category-%06d: %s\r\n", catcount, ast_category_get_name(category));
3707  catcount++;
3708  }
3709 
3710  if (catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
3711  astman_append(s, "Error: no categories found\r\n");
3712  }
3713 
3714  ast_config_destroy(cfg);
3715  astman_append(s, "\r\n");
3716 
3717  return 0;
3718 }
3719 
3720 /*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
3721 static void json_escape(char *out, const char *in)
3722 {
3723  for (; *in; in++) {
3724  if (*in == '\\' || *in == '\"') {
3725  *out++ = '\\';
3726  }
3727  *out++ = *in;
3728  }
3729  *out = '\0';
3730 }
3731 
3732 /*!
3733  * \internal
3734  * \brief Append a JSON escaped string to the manager stream.
3735  *
3736  * \param s AMI stream to append a string.
3737  * \param str String to append to the stream after JSON escaping it.
3738  *
3739  * \return Nothing
3740  */
3741 static void astman_append_json(struct mansession *s, const char *str)
3742 {
3743  char *buf;
3744 
3745  buf = ast_alloca(2 * strlen(str) + 1);
3746  json_escape(buf, str);
3747  astman_append(s, "%s", buf);
3748 }
3749 
3750 static int action_getconfigjson(struct mansession *s, const struct message *m)
3751 {
3752  struct ast_config *cfg;
3753  const char *fn = astman_get_header(m, "Filename");
3754  const char *filter = astman_get_header(m, "Filter");
3755  const char *category = astman_get_header(m, "Category");
3756  struct ast_category *cur_category = NULL;
3757  const char *category_name;
3758  struct ast_variable *v;
3759  int comma1 = 0;
3760  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3761 
3762  if (ast_strlen_zero(fn)) {
3763  astman_send_error(s, m, "Filename not specified");
3764  return 0;
3765  }
3766 
3767  if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
3768  astman_send_error(s, m, "Config file not found");
3769  return 0;
3770  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
3771  astman_send_error(s, m, "Config file has invalid format");
3772  return 0;
3773  }
3774 
3775  astman_start_ack(s, m);
3776  astman_append(s, "JSON: {");
3777  while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
3778  int comma2 = 0;
3779  struct ast_str *templates;
3780 
3781  category_name = ast_category_get_name(cur_category);
3782  astman_append(s, "%s\"", comma1 ? "," : "");
3783  astman_append_json(s, category_name);
3784  astman_append(s, "\":{");
3785  comma1 = 1;
3786 
3787  if (ast_category_is_template(cur_category)) {
3788  astman_append(s, "\"istemplate\":1");
3789  comma2 = 1;
3790  }
3791 
3792  if ((templates = ast_category_get_templates(cur_category))
3793  && ast_str_strlen(templates) > 0) {
3794  astman_append(s, "%s", comma2 ? "," : "");
3795  astman_append(s, "\"templates\":\"%s\"", ast_str_buffer(templates));
3796  ast_free(templates);
3797  comma2 = 1;
3798  }
3799 
3800  for (v = ast_category_first(cur_category); v; v = v->next) {
3801  astman_append(s, "%s\"", comma2 ? "," : "");
3802  astman_append_json(s, v->name);
3803  astman_append(s, "\":\"");
3804  astman_append_json(s, v->value);
3805  astman_append(s, "\"");
3806  comma2 = 1;
3807  }
3808 
3809  astman_append(s, "}");
3810  }
3811  astman_append(s, "}\r\n\r\n");
3812 
3813  ast_config_destroy(cfg);
3814 
3815  return 0;
3816 }
3817 
3818 /*! \brief helper function for action_updateconfig */
3819 static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
3820 {
3821  int x;
3822  char hdr[40];
3823  const char *action, *cat, *var, *value, *match, *line, *options;
3824  struct ast_variable *v;
3825  struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
3826  enum error_type result = 0;
3827 
3828  for (x = 0; x < 100000; x++) { /* 100000 = the max number of allowed updates + 1 */
3829  unsigned int object = 0;
3830  char *dupoptions;
3831  int allowdups = 0;
3832  int istemplate = 0;
3833  int ignoreerror = 0;
3834  RAII_VAR(char *, inherit, NULL, ast_free);
3835  RAII_VAR(char *, catfilter, NULL, ast_free);
3836  char *token;
3837  int foundvar = 0;
3838  int foundcat = 0;
3839  struct ast_category *category = NULL;
3840 
3841  snprintf(hdr, sizeof(hdr), "Action-%06d", x);
3842  action = astman_get_header(m, hdr);
3843  if (ast_strlen_zero(action)) /* breaks the for loop if no action header */
3844  break; /* this could cause problems if actions come in misnumbered */
3845 
3846  snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
3847  cat = astman_get_header(m, hdr);
3848  if (ast_strlen_zero(cat)) { /* every action needs a category */
3849  result = UNSPECIFIED_CATEGORY;
3850  break;
3851  }
3852 
3853  snprintf(hdr, sizeof(hdr), "Var-%06d", x);
3854  var = astman_get_header(m, hdr);
3855 
3856  snprintf(hdr, sizeof(hdr), "Value-%06d", x);
3857  value = astman_get_header(m, hdr);
3858 
3859  if (!ast_strlen_zero(value) && *value == '>') {
3860  object = 1;
3861  value++;
3862  }
3863 
3864  snprintf(hdr, sizeof(hdr), "Match-%06d", x);
3865  match = astman_get_header(m, hdr);
3866 
3867  snprintf(hdr, sizeof(hdr), "Line-%06d", x);
3868  line = astman_get_header(m, hdr);
3869 
3870  snprintf(hdr, sizeof(hdr), "Options-%06d", x);
3871  options = astman_get_header(m, hdr);
3872  if (!ast_strlen_zero(options)) {
3873  char copy[strlen(options) + 1];
3874  strcpy(copy, options); /* safe */
3875  dupoptions = copy;
3876  while ((token = ast_strsep(&dupoptions, ',', AST_STRSEP_STRIP))) {
3877  if (!strcasecmp("allowdups", token)) {
3878  allowdups = 1;
3879  continue;
3880  }
3881  if (!strcasecmp("template", token)) {
3882  istemplate = 1;
3883  continue;
3884  }
3885  if (!strcasecmp("ignoreerror", token)) {
3886  ignoreerror = 1;
3887  continue;
3888  }
3889  if (ast_begins_with(token, "inherit")) {
3890  char *c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3891  c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3892  if (c) {
3893  inherit = ast_strdup(c);
3894  }
3895  continue;
3896  }
3897  if (ast_begins_with(token, "catfilter")) {
3898  char *c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3899  c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3900  if (c) {
3901  catfilter = ast_strdup(c);
3902  }
3903  continue;
3904  }
3905  }
3906  }
3907 
3908  if (!strcasecmp(action, "newcat")) {
3909  struct ast_category *template;
3910  char *tmpl_name = NULL;
3911 
3912  if (!allowdups) {
3913  if (ast_category_get(cfg, cat, "TEMPLATES=include")) {
3914  if (ignoreerror) {
3915  continue;
3916  } else {
3917  result = FAILURE_NEWCAT; /* already exist */
3918  break;
3919  }
3920  }
3921  }
3922 
3923  if (istemplate) {
3924  category = ast_category_new_template(cat, dfn, -1);
3925  } else {
3926  category = ast_category_new(cat, dfn, -1);
3927  }
3928 
3929  if (!category) {
3930  result = FAILURE_ALLOCATION;
3931  break;
3932  }
3933 
3934  if (inherit) {
3935  while ((tmpl_name = ast_strsep(&inherit, ',', AST_STRSEP_STRIP))) {
3936  if ((template = ast_category_get(cfg, tmpl_name, "TEMPLATES=restrict"))) {
3937  if (ast_category_inherit(category, template)) {
3938  result = FAILURE_ALLOCATION;
3939  break;
3940  }
3941  } else {
3942  ast_category_destroy(category);
3943  category = NULL;
3944  result = FAILURE_TEMPLATE; /* template not found */
3945  break;
3946  }
3947  }
3948  }
3949 
3950  if (category != NULL) {
3951  if (ast_strlen_zero(match)) {
3952  ast_category_append(cfg, category);
3953  } else {
3954  if (ast_category_insert(cfg, category, match)) {
3955  ast_category_destroy(category);
3956  result = FAILURE_NEWCAT;
3957  break;
3958  }
3959  }
3960  }
3961  } else if (!strcasecmp(action, "renamecat")) {
3962  if (ast_strlen_zero(value)) {
3963  result = UNSPECIFIED_ARGUMENT;
3964  break;
3965  }
3966 
3967  foundcat = 0;
3968  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3969  ast_category_rename(category, value);
3970  foundcat = 1;
3971  }
3972 
3973  if (!foundcat) {
3974  result = UNKNOWN_CATEGORY;
3975  break;
3976  }
3977  } else if (!strcasecmp(action, "delcat")) {
3978  foundcat = 0;
3979  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3980  category = ast_category_delete(cfg, category);
3981  foundcat = 1;
3982  }
3983 
3984  if (!foundcat && !ignoreerror) {
3985  result = UNKNOWN_CATEGORY;
3986  break;
3987  }
3988  } else if (!strcasecmp(action, "emptycat")) {
3989  foundcat = 0;
3990  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3991  ast_category_empty(category);
3992  foundcat = 1;
3993  }
3994 
3995  if (!foundcat) {
3996  result = UNKNOWN_CATEGORY;
3997  break;
3998  }
3999  } else if (!strcasecmp(action, "update")) {
4000  if (ast_strlen_zero(var)) {
4001  result = UNSPECIFIED_ARGUMENT;
4002  break;
4003  }
4004 
4005  foundcat = 0;
4006  foundvar = 0;
4007  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4008  if (!ast_variable_update(category, var, value, match, object)) {
4009  foundvar = 1;
4010  }
4011  foundcat = 1;
4012  }
4013 
4014  if (!foundcat) {
4015  result = UNKNOWN_CATEGORY;
4016  break;
4017  }
4018 
4019  if (!foundvar) {
4020  result = FAILURE_UPDATE;
4021  break;
4022  }
4023  } else if (!strcasecmp(action, "delete")) {
4024  if ((ast_strlen_zero(var) && ast_strlen_zero(line))) {
4025  result = UNSPECIFIED_ARGUMENT;
4026  break;
4027  }
4028 
4029  foundcat = 0;
4030  foundvar = 0;
4031  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4032  if (!ast_variable_delete(category, var, match, line)) {
4033  foundvar = 1;
4034  }
4035  foundcat = 1;
4036  }
4037 
4038  if (!foundcat) {
4039  result = UNKNOWN_CATEGORY;
4040  break;
4041  }
4042 
4043  if (!foundvar && !ignoreerror) {
4044  result = FAILURE_UPDATE;
4045  break;
4046  }
4047  } else if (!strcasecmp(action, "append")) {
4048  if (ast_strlen_zero(var)) {
4049  result = UNSPECIFIED_ARGUMENT;
4050  break;
4051  }
4052 
4053  foundcat = 0;
4054  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4055  if (!(v = ast_variable_new(var, value, dfn))) {
4056  result = FAILURE_ALLOCATION;
4057  break;
4058  }
4059  if (object || (match && !strcasecmp(match, "object"))) {
4060  v->object = 1;
4061  }
4062  ast_variable_append(category, v);
4063  foundcat = 1;
4064  }
4065 
4066  if (!foundcat) {
4067  result = UNKNOWN_CATEGORY;
4068  break;
4069  }
4070  } else if (!strcasecmp(action, "insert")) {
4071  if (ast_strlen_zero(var) || ast_strlen_zero(line)) {
4072  result = UNSPECIFIED_ARGUMENT;
4073  break;
4074  }
4075 
4076  foundcat = 0;
4077  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4078  if (!(v = ast_variable_new(var, value, dfn))) {
4079  result = FAILURE_ALLOCATION;
4080  break;
4081  }
4082  ast_variable_insert(category, v, line);
4083  foundcat = 1;
4084  }
4085 
4086  if (!foundcat) {
4087  result = UNKNOWN_CATEGORY;
4088  break;
4089  }
4090  }
4091  else {
4092  ast_log(LOG_WARNING, "Action-%06d: %s not handled\n", x, action);
4093  result = UNKNOWN_ACTION;
4094  break;
4095  }
4096  }
4097  ast_free(str1);
4098  ast_free(str2);
4099  return result;
4100 }
4101 
4102 static int action_updateconfig(struct mansession *s, const struct message *m)
4103 {
4104  struct ast_config *cfg;
4105  const char *sfn = astman_get_header(m, "SrcFilename");
4106  const char *dfn = astman_get_header(m, "DstFilename");
4107  int res;
4108  const char *rld = astman_get_header(m, "Reload");
4109  int preserve_effective_context = CONFIG_SAVE_FLAG_PRESERVE_EFFECTIVE_CONTEXT;
4110  const char *preserve_effective_context_string = astman_get_header(m, "PreserveEffectiveContext");
4111  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
4112  enum error_type result;
4113 
4114  if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
4115  astman_send_error(s, m, "Filename not specified");
4116  return 0;
4117  }
4118  if (!(cfg = ast_config_load2(sfn, "manager", config_flags))) {
4119  astman_send_error(s, m, "Config file not found");
4120  return 0;
4121  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
4122  astman_send_error(s, m, "Config file has invalid format");
4123  return 0;
4124  }
4125  result = handle_updates(s, m, cfg, dfn);
4126  if (!result) {
4127  ast_include_rename(cfg, sfn, dfn); /* change the include references from dfn to sfn, so things match up */
4128  if (!ast_strlen_zero(preserve_effective_context_string) && !ast_true(preserve_effective_context_string)) {
4129  preserve_effective_context = CONFIG_SAVE_FLAG_NONE;
4130  }
4131  res = ast_config_text_file_save2(dfn, cfg, "Manager", preserve_effective_context);
4132  ast_config_destroy(cfg);
4133  if (res) {
4134  astman_send_error(s, m, "Save of config failed");
4135  return 0;
4136  }
4137  astman_send_ack(s, m, NULL);
4138  if (!ast_strlen_zero(rld)) {
4139  if (ast_true(rld)) {
4140  rld = NULL;
4141  }
4142  ast_module_reload(rld);
4143  }
4144  } else {
4145  ast_config_destroy(cfg);
4146  switch(result) {
4147  case UNKNOWN_ACTION:
4148  astman_send_error(s, m, "Unknown action command");
4149  break;
4150  case UNKNOWN_CATEGORY:
4151  astman_send_error(s, m, "Given category does not exist");
4152  break;
4153  case UNSPECIFIED_CATEGORY:
4154  astman_send_error(s, m, "Category not specified");
4155  break;
4156  case UNSPECIFIED_ARGUMENT:
4157  astman_send_error(s, m, "Problem with category, value, or line (if required)");
4158  break;
4159  case FAILURE_ALLOCATION:
4160  astman_send_error(s, m, "Memory allocation failure, this should not happen");
4161  break;
4162  case FAILURE_NEWCAT:
4163  astman_send_error(s, m, "Create category did not complete successfully");
4164  break;
4165  case FAILURE_DELCAT:
4166  astman_send_error(s, m, "Delete category did not complete successfully");
4167  break;
4168  case FAILURE_EMPTYCAT:
4169  astman_send_error(s, m, "Empty category did not complete successfully");
4170  break;
4171  case FAILURE_UPDATE:
4172  astman_send_error(s, m, "Update did not complete successfully");
4173  break;
4174  case FAILURE_DELETE:
4175  astman_send_error(s, m, "Delete did not complete successfully");
4176  break;
4177  case FAILURE_APPEND:
4178  astman_send_error(s, m, "Append did not complete successfully");
4179  break;
4180  case FAILURE_TEMPLATE:
4181  astman_send_error(s, m, "Template category not found");
4182  break;
4183  }
4184  }
4185  return 0;
4186 }
4187 
4188 static int action_createconfig(struct mansession *s, const struct message *m)
4189 {
4190  int fd;
4191  const char *fn = astman_get_header(m, "Filename");
4192  struct ast_str *filepath = ast_str_alloca(PATH_MAX);
4193  ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
4194  ast_str_append(&filepath, 0, "%s", fn);
4195 
4196  if ((fd = open(ast_str_buffer(filepath), O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
4197  close(fd);
4198  astman_send_ack(s, m, "New configuration file created successfully");
4199  } else {
4200  astman_send_error(s, m, strerror(errno));
4201  }
4202 
4203  return 0;
4204 }
4205 
4206 static int action_waitevent(struct mansession *s, const struct message *m)
4207 {
4208  const char *timeouts = astman_get_header(m, "Timeout");
4209  int timeout = -1;
4210  int x;
4211  int needexit = 0;
4212  const char *id = astman_get_header(m, "ActionID");
4213  char idText[256];
4214 
4215  if (!ast_strlen_zero(id)) {
4216  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
4217  } else {
4218  idText[0] = '\0';
4219  }
4220 
4221  if (!ast_strlen_zero(timeouts)) {
4222  sscanf(timeouts, "%30i", &timeout);
4223  if (timeout < -1) {
4224  timeout = -1;
4225  }
4226  /* XXX maybe put an upper bound, or prevent the use of 0 ? */
4227  }
4228 
4231  pthread_kill(s->session->waiting_thread, SIGURG);
4232  }
4234 
4235  ao2_lock(s->session);
4236 
4237  if (s->session->managerid) { /* AMI-over-HTTP session */
4238  /*
4239  * Make sure the timeout is within the expire time of the session,
4240  * as the client will likely abort the request if it does not see
4241  * data coming after some amount of time.
4242  */
4243  time_t now = time(NULL);
4244  int max = s->session->sessiontimeout - now - 10;
4245 
4246  if (max < 0) { /* We are already late. Strange but possible. */
4247  max = 0;
4248  }
4249  if (timeout < 0 || timeout > max) {
4250  timeout = max;
4251  }
4252  if (!s->session->send_events) { /* make sure we record events */
4253  s->session->send_events = -1;
4254  }
4255  }
4256  ao2_unlock(s->session);
4257 
4259  s->session->waiting_thread = pthread_self(); /* let new events wake up this thread */
4261  ast_debug(1, "Starting waiting for an event!\n");
4262 
4263  for (x = 0; x < timeout || timeout < 0; x++) {
4264  ao2_lock(s->session);
4265  if (AST_RWLIST_NEXT(s->session->last_ev, eq_next)) {
4266  needexit = 1;
4267  }
4268  if (s->session->needdestroy) {
4269  needexit = 1;
4270  }
4271  ao2_unlock(s->session);
4272  /* We can have multiple HTTP session point to the same mansession entry.
4273  * The way we deal with it is not very nice: newcomers kick out the previous
4274  * HTTP session. XXX this needs to be improved.
4275  */
4277  if (s->session->waiting_thread != pthread_self()) {
4278  needexit = 1;
4279  }
4281  if (needexit) {
4282  break;
4283  }
4284  if (s->session->managerid == 0) { /* AMI session */
4286  break;
4287  }
4288  } else { /* HTTP session */
4289  sleep(1);
4290  }
4291  }
4292  ast_debug(1, "Finished waiting for an event!\n");
4293 
4295  if (s->session->waiting_thread == pthread_self()) {
4296  struct eventqent *eqe = s->session->last_ev;
4297 
4300 
4301  ao2_lock(s->session);
4302  astman_send_response(s, m, "Success", "Waiting for Event completed.");
4303  while ((eqe = advance_event(eqe))) {
4304  if (((s->session->readperm & eqe->category) == eqe->category)
4305  && ((s->session->send_events & eqe->category) == eqe->category)
4306  && match_filter(s, eqe->eventdata)) {
4307  astman_append(s, "%s", eqe->eventdata);
4308  }
4309  s->session->last_ev = eqe;
4310  }
4311  astman_append(s,
4312  "Event: WaitEventComplete\r\n"
4313  "%s"
4314  "\r\n", idText);
4315  ao2_unlock(s->session);
4316  } else {
4318  ast_debug(1, "Abandoning event request!\n");
4319  }
4320 
4321  return 0;
4322 }
4323 
4324 static int action_listcommands(struct mansession *s, const struct message *m)
4325 {
4326  struct manager_action *cur;
4328 
4329  astman_start_ack(s, m);
4331  AST_RWLIST_TRAVERSE(&actions, cur, list) {
4332  if ((s->session->writeperm & cur->authority) || cur->authority == 0) {
4333  astman_append(s, "%s: %s (Priv: %s)\r\n",
4334  cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
4335  }
4336  }
4338  astman_append(s, "\r\n");
4339 
4340  return 0;
4341 }
4342 
4343 static int action_events(struct mansession *s, const struct message *m)
4344 {
4345  const char *mask = astman_get_header(m, "EventMask");
4346  int res, x;
4347  const char *id = astman_get_header(m, "ActionID");
4348  char id_text[256];
4349 
4350  if (!ast_strlen_zero(id)) {
4351  snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
4352  } else {
4353  id_text[0] = '\0';
4354  }
4355 
4356  res = set_eventmask(s, mask);
4357  if (broken_events_action) {
4358  /* if this option is set we should not return a response on
4359  * error, or when all events are set */
4360 
4361  if (res > 0) {
4362  for (x = 0; x < ARRAY_LEN(perms); x++) {
4363  if (!strcasecmp(perms[x].label, "all") && res == perms[x].num) {
4364  return 0;
4365  }
4366  }
4367  astman_append(s, "Response: Success\r\n%s"
4368  "Events: On\r\n\r\n", id_text);
4369  } else if (res == 0)
4370  astman_append(s, "Response: Success\r\n%s"
4371  "Events: Off\r\n\r\n", id_text);
4372  return 0;
4373  }
4374 
4375  if (res > 0)
4376  astman_append(s, "Response: Success\r\n%s"
4377  "Events: On\r\n\r\n", id_text);
4378  else if (res == 0)
4379  astman_append(s, "Response: Success\r\n%s"
4380  "Events: Off\r\n\r\n", id_text);
4381  else
4382  astman_send_error(s, m, "Invalid event mask");
4383 
4384  return 0;
4385 }
4386 
4387 static int action_logoff(struct mansession *s, const struct message *m)
4388 {
4389  astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
4390  return -1;
4391 }
4392 
4393 static int action_login(struct mansession *s, const struct message *m)
4394 {
4395 
4396  /* still authenticated - don't process again */
4397  if (s->session->authenticated) {
4398  astman_send_ack(s, m, "Already authenticated");
4399  return 0;
4400  }
4401 
4402  if (authenticate(s, m)) {
4403  sleep(1);
4404  astman_send_error(s, m, "Authentication failed");
4405  return -1;
4406  }
4407  s->session->authenticated = 1;
4409  if (manager_displayconnects(s->session)) {
4410  ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_sockaddr_stringify_addr(&s->session->addr));
4411  }
4412  astman_send_ack(s, m, "Authentication accepted");
4417  const char *cat_str = authority_to_str(EVENT_FLAG_SYSTEM, &auth);
4418  long uptime = 0;
4419  long lastreloaded = 0;
4420  struct timeval tmp;
4421  struct timeval curtime = ast_tvnow();
4422 
4423  if (ast_startuptime.tv_sec) {
4424  tmp = ast_tvsub(curtime, ast_startuptime);
4425  uptime = tmp.tv_sec;
4426  }
4427 
4428  if (ast_lastreloadtime.tv_sec) {
4429  tmp = ast_tvsub(curtime, ast_lastreloadtime);
4430  lastreloaded = tmp.tv_sec;
4431  }
4432 
4433  astman_append(s, "Event: FullyBooted\r\n"
4434  "Privilege: %s\r\n"
4435  "Uptime: %ld\r\n"
4436  "LastReload: %ld\r\n"
4437  "Status: Fully Booted\r\n\r\n", cat_str, uptime, lastreloaded);
4438  }
4439  return 0;
4440 }
4441 
4442 static int action_challenge(struct mansession *s, const struct message *m)
4443 {
4444  const char *authtype = astman_get_header(m, "AuthType");
4445 
4446  if (!strcasecmp(authtype, "MD5")) {
4447  if (ast_strlen_zero(s->session->challenge)) {
4448  snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
4449  }
4450  mansession_lock(s);
4451  astman_start_ack(s, m);
4452  astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
4453  mansession_unlock(s);
4454  } else {
4455  astman_send_error(s, m, "Must specify AuthType");
4456  }
4457  return 0;
4458 }
4459 
4460 static int action_hangup(struct mansession *s, const struct message *m)
4461 {
4462  struct ast_channel *c = NULL;
4463  int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
4464  const char *id = astman_get_header(m, "ActionID");
4465  const char *name_or_regex = astman_get_header(m, "Channel");
4466  const char *cause = astman_get_header(m, "Cause");
4467  char idText[256];
4468  regex_t regexbuf;
4469  struct ast_channel_iterator *iter = NULL;
4470  struct ast_str *regex_string;
4471  int channels_matched = 0;
4472 
4473  if (ast_strlen_zero(name_or_regex)) {
4474  astman_send_error(s, m, "No channel specified");
4475  return 0;
4476  }
4477 
4478  if (!ast_strlen_zero(id)) {
4479  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
4480  } else {
4481  idText[0] = '\0';
4482  }
4483 
4484  if (!ast_strlen_zero(cause)) {
4485  char *endptr;
4486  causecode = strtol(cause, &endptr, 10);
4487  if (causecode < 0 || causecode > 127 || *endptr != '\0') {
4488  ast_log(LOG_NOTICE, "Invalid 'Cause: %s' in manager action Hangup\n", cause);
4489  /* keep going, better to hangup without cause than to not hang up at all */
4490  causecode = 0; /* do not set channel's hangupcause */
4491  }
4492  }
4493 
4494  /************************************************/
4495  /* Regular explicit match channel byname hangup */
4496 
4497  if (name_or_regex[0] != '/') {
4498  if (!(c = ast_channel_get_by_name(name_or_regex))) {
4499  ast_log(LOG_NOTICE, "Request to hangup non-existent channel: %s\n",
4500  name_or_regex);
4501  astman_send_error(s, m, "No such channel");
4502  return 0;
4503  }
4504 
4505  ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
4506  (s->session->managerid ? "HTTP " : ""),
4507  s->session->username,
4509  ast_channel_name(c));
4510 
4512  c = ast_channel_unref(c);
4513 
4514  astman_send_ack(s, m, "Channel Hungup");
4515 
4516  return 0;
4517  }
4518 
4519  /***********************************************/
4520  /* find and hangup any channels matching regex */
4521 
4522  regex_string = ast_str_create(strlen(name_or_regex));
4523  if (!regex_string) {
4524  astman_send_error(s, m, "Memory Allocation Failure");
4525  return 0;
4526  }
4527 
4528  /* Make "/regex/" into "regex" */
4529  if (ast_regex_string_to_regex_pattern(name_or_regex, &regex_string) != 0) {
4530  astman_send_error(s, m, "Regex format invalid, Channel param should be /regex/");
4531  ast_free(regex_string);
4532  return 0;
4533  }
4534 
4535  /* if regex compilation fails, hangup fails */
4536  if (regcomp(&regexbuf, ast_str_buffer(regex_string), REG_EXTENDED | REG_NOSUB)) {
4537  astman_send_error_va(s, m, "Regex compile failed on: %s", name_or_regex);
4538  ast_free(regex_string);
4539  return 0;
4540  }
4541 
4542  astman_send_listack(s, m, "Channels hung up will follow", "start");
4543 
4545  if (iter) {
4546  for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
4547  if (regexec(&regexbuf, ast_channel_name(c), 0, NULL, 0)) {
4548  continue;
4549  }
4550 
4551  ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
4552  (s->session->managerid ? "HTTP " : ""),
4553  s->session->username,
4555  ast_channel_name(c));
4556 
4558  channels_matched++;
4559 
4560  astman_append(s,
4561  "Event: ChannelHungup\r\n"
4562  "Channel: %s\r\n"
4563  "%s"
4564  "\r\n", ast_channel_name(c), idText);
4565  }
4567  }
4568 
4569  regfree(&regexbuf);
4570  ast_free(regex_string);
4571 
4572  astman_send_list_complete(s, m, "ChannelsHungupListComplete", channels_matched);
4573 
4574  return 0;
4575 }
4576 
4577 static int action_setvar(struct mansession *s, const struct message *m)
4578 {
4579  struct ast_channel *c = NULL;
4580  const char *name = astman_get_header(m, "Channel");
4581  const char *varname = astman_get_header(m, "Variable");
4582  const char *varval = astman_get_header(m, "Value");
4583  int res = 0;
4584 
4585  if (ast_strlen_zero(varname)) {
4586  astman_send_error(s, m, "No variable specified");
4587  return 0;
4588  }
4589 
4590  if (!ast_strlen_zero(name)) {
4591  if (!(c = ast_channel_get_by_name(name))) {
4592  astman_send_error(s, m, "No such channel");
4593  return 0;
4594  }
4595  }
4596 
4597  res = pbx_builtin_setvar_helper(c, varname, S_OR(varval, ""));
4598 
4599  if (c) {
4600  c = ast_channel_unref(c);
4601  }
4602  if (res == 0) {
4603  astman_send_ack(s, m, "Variable Set");
4604  } else {
4605  astman_send_error(s, m, "Variable not set");
4606  }
4607  return 0;
4608 }
4609 
4610 static int action_getvar(struct mansession *s, const struct message *m)
4611 {
4612  struct ast_channel *c = NULL;
4613  const char *name = astman_get_header(m, "Channel");
4614  const char *varname = astman_get_header(m, "Variable");
4615  char *varval;
4616  char workspace[1024];
4617 
4618  if (ast_strlen_zero(varname)) {
4619  astman_send_error(s, m, "No variable specified");
4620  return 0;
4621  }
4622 
4623  /* We don't want users with insufficient permissions using certain functions. */
4625  astman_send_error(s, m, "GetVar Access Forbidden: Variable");
4626  return 0;
4627  }
4628 
4629  if (!ast_strlen_zero(name)) {
4630  if (!(c = ast_channel_get_by_name(name))) {
4631  astman_send_error(s, m, "No such channel");
4632  return 0;
4633  }
4634  }
4635 
4636  workspace[0] = '\0';
4637  if (varname[strlen(varname) - 1] == ')') {
4638  if (!c) {
4640  if (c) {
4641  ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
4642  } else
4643  ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
4644  } else {
4645  ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
4646  }
4647  varval = workspace;
4648  } else {
4649  pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
4650  }
4651 
4652  if (c) {
4653  c = ast_channel_unref(c);
4654  }
4655 
4656  astman_start_ack(s, m);
4657  astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, S_OR(varval, ""));
4658 
4659  return 0;
4660 }
4661 
4662 static void generate_status(struct mansession *s, struct ast_channel *chan, char **vars, int varc, int all_variables, char *id_text, int *count)
4663 {
4664  struct timeval now;
4665  long elapsed_seconds;
4666  struct ast_bridge *bridge;
4667  RAII_VAR(struct ast_str *, variable_str, NULL, ast_free);
4668  struct ast_str *write_transpath = ast_str_alloca(256);
4669  struct ast_str *read_transpath = ast_str_alloca(256);
4670  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
4671  struct ast_party_id effective_id;
4672  int i;
4673  RAII_VAR(struct ast_channel_snapshot *, snapshot,
4675  ao2_cleanup);
4676  RAII_VAR(struct ast_str *, snapshot_str, NULL, ast_free);
4677 
4678  if (!snapshot) {
4679  return;
4680  }
4681 
4682  snapshot_str = ast_manager_build_channel_state_string(snapshot);
4683  if (!snapshot_str) {
4684  return;
4685  }
4686 
4687  if (all_variables) {
4688  variable_str = ast_str_create(2048);
4689  } else {
4690  variable_str = ast_str_create(1024);
4691  }
4692  if (!variable_str) {
4693  return;
4694  }
4695 
4696  now = ast_tvnow();
4697  elapsed_seconds = ast_tvdiff_sec(now, ast_channel_creationtime(chan));
4698 
4699  /* Even if all_variables has been specified, explicitly requested variables
4700  * may be global variables or dialplan functions */
4701  for (i = 0; i < varc; i++) {
4702  char valbuf[512], *ret = NULL;
4703 
4704  if (vars[i][strlen(vars[i]) - 1] == ')') {
4705  if (ast_func_read(chan, vars[i], valbuf, sizeof(valbuf)) < 0) {
4706  valbuf[0] = '\0';
4707  }
4708  ret = valbuf;
4709  } else {
4710  pbx_retrieve_variable(chan, vars[i], &ret, valbuf, sizeof(valbuf), NULL);
4711  }
4712 
4713  ast_str_append(&variable_str, 0, "Variable: %s=%s\r\n", vars[i], ret);
4714  }
4715 
4716  /* Walk all channel variables and add them */
4717  if (all_variables) {
4718  struct ast_var_t *variables;
4719 
4720  AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
4721  ast_str_append(&variable_str, 0, "Variable: %s=%s\r\n",
4722  ast_var_name(variables), ast_var_value(variables));
4723  }
4724  }
4725 
4726  bridge = ast_channel_get_bridge(chan);
4727  effective_id = ast_channel_connected_effective_id(chan);
4728 
4729  astman_append(s,
4730  "Event: Status\r\n"
4731  "Privilege: Call\r\n"
4732  "%s"
4733  "Type: %s\r\n"
4734  "DNID: %s\r\n"
4735  "EffectiveConnectedLineNum: %s\r\n"
4736  "EffectiveConnectedLineName: %s\r\n"
4737  "TimeToHangup: %ld\r\n"
4738  "BridgeID: %s\r\n"
4739  "Application: %s\r\n"
4740  "Data: %s\r\n"
4741  "Nativeformats: %s\r\n"
4742  "Readformat: %s\r\n"
4743  "Readtrans: %s\r\n"
4744  "Writeformat: %s\r\n"
4745  "Writetrans: %s\r\n"
4746  "Callgroup: %llu\r\n"
4747  "Pickupgroup: %llu\r\n"
4748  "Seconds: %ld\r\n"
4749  "%s"
4750  "%s"
4751  "\r\n",
4752  ast_str_buffer(snapshot_str),
4753  ast_channel_tech(chan)->type,
4754  S_OR(ast_channel_dialed(chan)->number.str, ""),
4755  S_COR(effective_id.number.valid, effective_id.number.str, "<unknown>"),
4756  S_COR(effective_id.name.valid, effective_id.name.str, "<unknown>"),
4757  (long)ast_channel_whentohangup(chan)->tv_sec,
4758  bridge ? bridge->uniqueid : "",
4759  ast_channel_appl(chan),
4760  ast_channel_data(chan),
4763  ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath),
4765  ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath),
4766  ast_channel_callgroup(chan),
4768  (long)elapsed_seconds,
4769  ast_str_buffer(variable_str),
4770  id_text);
4771  ++*count;
4772 
4773  ao2_cleanup(bridge);
4774 }
4775 
4776 /*! \brief Manager "status" command to show channels */
4777 static int action_status(struct mansession *s, const struct message *m)
4778 {
4779  const char *name = astman_get_header(m, "Channel");
4780  const char *chan_variables = astman_get_header(m, "Variables");
4781  const char *all_chan_variables = astman_get_header(m, "AllVariables");
4782  int all_variables = 0;
4783  const char *id = astman_get_header(m, "ActionID");
4784  char *variables = ast_strdupa(S_OR(chan_variables, ""));
4785  struct ast_channel *chan;
4786  int channels = 0;
4787  int all = ast_strlen_zero(name); /* set if we want all channels */
4788  char id_text[256];
4789  struct ast_channel_iterator *it_chans = NULL;
4790  AST_DECLARE_APP_ARGS(vars,
4791  AST_APP_ARG(name)[100];
4792  );
4793 
4794  if (!ast_strlen_zero(all_chan_variables)) {
4795  all_variables = ast_true(all_chan_variables);
4796  }
4797 
4799  astman_send_error(s, m, "Status Access Forbidden: Variables");
4800  return 0;
4801  }
4802 
4803  if (all) {
4804  if (!(it_chans = ast_channel_iterator_all_new())) {
4805  astman_send_error(s, m, "Memory Allocation Failure");
4806  return 1;
4807  }
4808  chan = ast_channel_iterator_next(it_chans);
4809  } else {
4810  chan = ast_channel_get_by_name(name);
4811  if (!chan) {
4812  astman_send_error(s, m, "No such channel");
4813  return 0;
4814  }
4815  }
4816 
4817  astman_send_listack(s, m, "Channel status will follow", "start");
4818 
4819  if (!ast_strlen_zero(id)) {
4820  snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
4821  } else {
4822  id_text[0] = '\0';
4823  }
4824 
4825  if (!ast_strlen_zero(chan_variables)) {
4826  AST_STANDARD_APP_ARGS(vars, variables);
4827  }
4828 
4829  /* if we look by name, we break after the first iteration */
4830  for (; chan; all ? chan = ast_channel_iterator_next(it_chans) : 0) {
4831  ast_channel_lock(chan);
4832 
4833  generate_status(s, chan, vars.name, vars.argc, all_variables, id_text, &channels);
4834 
4835  ast_channel_unlock(chan);
4836  chan = ast_channel_unref(chan);
4837  }
4838 
4839  if (it_chans) {
4840  ast_channel_iterator_destroy(it_chans);
4841  }
4842 
4843  astman_send_list_complete_start(s, m, "StatusComplete", channels);
4844  astman_append(s, "Items: %d\r\n", channels);
4846 
4847  return 0;
4848 }
4849 
4850 /*!
4851  * \brief Queue a given read action containing a payload onto a channel
4852  *
4853  * This queues a READ_ACTION control frame that contains a given "payload", or
4854  * data to be triggered and handled on the channel's read side. This ensures
4855  * the "action" is handled by the channel's media reading thread.
4856  *
4857  * \param chan The channel to queue the action on
4858  * \param payload The read action's payload
4859  * \param payload_size The size of the given payload
4860  * \param action The type of read action to queue
4861  *
4862  * \return -1 on error, 0 on success
4863  */
4864 static int queue_read_action_payload(struct ast_channel *chan, const unsigned char *payload,
4865  size_t payload_size, enum ast_frame_read_action action)
4866 {
4867  struct ast_control_read_action_payload *obj;
4868  size_t obj_size;
4869  int res;
4870 
4871  obj_size = payload_size + sizeof(*obj);
4872 
4873  obj = ast_malloc(obj_size);
4874  if (!obj) {
4875  return -1;
4876  }
4877 
4878  obj->action = action;
4879  obj->payload_size = payload_size;
4880  memcpy(obj->payload, payload, payload_size);
4881 
4882  res = ast_queue_control_data(chan, AST_CONTROL_READ_ACTION, obj, obj_size);
4883 
4884  ast_free(obj);
4885  return res;
4886 }
4887 
4888 /*!
4889  * \brief Queue a read action to send a text message
4890  *
4891  * \param chan The channel to queue the action on
4892  * \param body The body of the message
4893  *
4894  * \return -1 on error, 0 on success
4895  */
4896 static int queue_sendtext(struct ast_channel *chan, const char *body)
4897 {
4898  return queue_read_action_payload(chan, (const unsigned char *)body,
4899  strlen(body) + 1, AST_FRAME_READ_ACTION_SEND_TEXT);
4900 }
4901 
4902 /*!
4903  * \brief Queue a read action to send a text data message
4904  *
4905  * \param chan The channel to queue the action on
4906  * \param body The body of the message
4907  * \param content_type The message's content type
4908  *
4909  * \return -1 on error, 0 on success
4910  */
4911 static int queue_sendtext_data(struct ast_channel *chan, const char *body,
4912  const char *content_type)
4913 {
4914  int res;
4915  struct ast_msg_data *obj;
4916 
4918  NULL, NULL, content_type, body);
4919  if (!obj) {
4920  return -1;
4921  }
4922 
4923  res = queue_read_action_payload(chan, (const unsigned char *)obj,
4925 
4926  ast_free(obj);
4927  return res;
4928 }
4929 
4930 static int action_sendtext(struct mansession *s, const struct message *m)
4931 {
4932  struct ast_channel *c;
4933  const char *name = astman_get_header(m, "Channel");
4934  const char *textmsg = astman_get_header(m, "Message");
4935  const char *content_type = astman_get_header(m, "Content-Type");
4936  int res;
4937 
4938  if (ast_strlen_zero(name)) {
4939  astman_send_error(s, m, "No channel specified");
4940  return 0;
4941  }
4942 
4943  if (ast_strlen_zero(textmsg)) {
4944  astman_send_error(s, m, "No Message specified");
4945  return 0;
4946  }
4947 
4948  c = ast_channel_get_by_name(name);
4949  if (!c) {
4950  astman_send_error(s, m, "No such channel");
4951  return 0;
4952  }
4953 
4954  /*
4955  * If the "extra" data is not available, then send using "string" only.
4956  * Doing such maintains backward compatibilities.
4957  */
4958  res = ast_strlen_zero(content_type) ? queue_sendtext(c, textmsg) :
4959  queue_sendtext_data(c, textmsg, content_type);
4960 
4961  ast_channel_unref(c);
4962 
4963  if (res >= 0) {
4964  astman_send_ack(s, m, "Success");
4965  } else {
4966  astman_send_error(s, m, "Failure");
4967  }
4968 
4969  return 0;
4970 }
4971 
4972 /*! \brief action_redirect: The redirect manager command */
4973 static int action_redirect(struct mansession *s, const struct message *m)
4974 {
4975  char buf[256];
4976  const char *name = astman_get_header(m, "Channel");
4977  const char *name2 = astman_get_header(m, "ExtraChannel");
4978  const char *exten = astman_get_header(m, "Exten");
4979  const char *exten2 = astman_get_header(m, "ExtraExten");
4980  const char *context = astman_get_header(m, "Context");
4981  const char *context2 = astman_get_header(m, "ExtraContext");
4982  const char *priority = astman_get_header(m, "Priority");
4983  const char *priority2 = astman_get_header(m, "ExtraPriority");
4984  struct ast_channel *chan;
4985  struct ast_channel *chan2;
4986  int pi = 0;
4987  int pi2 = 0;
4988  int res;
4989  int chan1_wait = 0;
4990  int chan2_wait = 0;
4991 
4992  if (ast_strlen_zero(name)) {
4993  astman_send_error(s, m, "Channel not specified");
4994  return 0;
4995  }
4996 
4997  if (ast_strlen_zero(context)) {
4998  astman_send_error(s, m, "Context not specified");
4999  return 0;
5000  }
5001  if (ast_strlen_zero(exten)) {
5002  astman_send_error(s, m, "Exten not specified");
5003  return 0;
5004  }
5005  if (ast_strlen_zero(priority)) {
5006  astman_send_error(s, m, "Priority not specified");
5007  return 0;
5008  }
5009  if (sscanf(priority, "%30d", &pi) != 1) {
5010  pi = ast_findlabel_extension(NULL, context, exten, priority, NULL);
5011  }
5012  if (pi < 1) {
5013  astman_send_error(s, m, "Priority is invalid");
5014  return 0;
5015  }
5016 
5017  if (!ast_strlen_zero(name2) && !ast_strlen_zero(context2)) {
5018  /* We have an ExtraChannel and an ExtraContext */
5019  if (ast_strlen_zero(exten2)) {
5020  astman_send_error(s, m, "ExtraExten not specified");
5021  return 0;
5022  }
5023  if (ast_strlen_zero(priority2)) {
5024  astman_send_error(s, m, "ExtraPriority not specified");
5025  return 0;
5026  }
5027  if (sscanf(priority2, "%30d", &pi2) != 1) {
5028  pi2 = ast_findlabel_extension(NULL, context2, exten2, priority2, NULL);
5029  }
5030  if (pi2 < 1) {
5031  astman_send_error(s, m, "ExtraPriority is invalid");
5032  return 0;
5033  }
5034  }
5035 
5036  chan = ast_channel_get_by_name(name);
5037  if (!chan) {
5038  snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
5039  astman_send_error(s, m, buf);
5040  return 0;
5041  }
5042  if (ast_check_hangup_locked(chan)) {
5043  astman_send_error(s, m, "Redirect failed, channel not up.");
5044  chan = ast_channel_unref(chan);
5045  return 0;
5046  }
5047 
5048  if (ast_strlen_zero(name2)) {
5049  /* Single channel redirect in progress. */
5050  res = ast_async_goto(chan, context, exten, pi);
5051  if (!res) {
5052  astman_send_ack(s, m, "Redirect successful");
5053  } else {
5054  astman_send_error(s, m, "Redirect failed");
5055  }
5056  chan = ast_channel_unref(chan);
5057  return 0;
5058  }
5059 
5060  chan2 = ast_channel_get_by_name(name2);
5061  if (!chan2) {
5062  snprintf(buf, sizeof(buf), "ExtraChannel does not exist: %s", name2);
5063  astman_send_error(s, m, buf);
5064  chan = ast_channel_unref(chan);
5065  return 0;
5066  }
5067  if (ast_check_hangup_locked(chan2)) {
5068  astman_send_error(s, m, "Redirect failed, extra channel not up.");
5069  chan2 = ast_channel_unref(chan2);
5070  chan = ast_channel_unref(chan);
5071  return 0;
5072  }
5073 
5074  /* Dual channel redirect in progress. */
5075  ast_channel_lock(chan);
5076  if (ast_channel_is_bridged(chan)) {
5078  chan1_wait = 1;
5079  }
5080  ast_channel_unlock(chan);
5081 
5082  ast_channel_lock(chan2);
5083  if (ast_channel_is_bridged(chan2)) {
5085  chan2_wait = 1;
5086  }
5087  ast_channel_unlock(chan2);
5088 
5089  res = ast_async_goto(chan, context, exten, pi);
5090  if (!res) {
5091  if (!ast_strlen_zero(context2)) {
5092  res = ast_async_goto(chan2, context2, exten2, pi2);
5093  } else {
5094  res = ast_async_goto(chan2, context, exten, pi);
5095  }
5096  if (!res) {
5097  astman_send_ack(s, m, "Dual Redirect successful");
5098  } else {
5099  astman_send_error(s, m, "Secondary redirect failed");
5100  }
5101  } else {
5102  astman_send_error(s, m, "Redirect failed");
5103  }
5104 
5105  /* Release the bridge wait. */
5106  if (chan1_wait) {
5108  }
5109  if (chan2_wait) {
5111  }
5112 
5113  chan2 = ast_channel_unref(chan2);
5114  chan = ast_channel_unref(chan);
5115  return 0;
5116 }
5117 
5118 static int action_blind_transfer(struct mansession *s, const struct message *m)
5119 {
5120  const char *name = astman_get_header(m, "Channel");
5121  const char *exten = astman_get_header(m, "Exten");
5122  const char *context = astman_get_header(m, "Context");
5123  struct ast_channel *chan;
5124 
5125  if (ast_strlen_zero(name)) {
5126  astman_send_error(s, m, "No channel specified");
5127  return 0;
5128  }
5129 
5130  if (ast_strlen_zero(exten)) {
5131  astman_send_error(s, m, "No extension specified");
5132  return 0;
5133  }
5134 
5135  chan = ast_channel_get_by_name(name);
5136  if (!chan) {
5137  astman_send_error(s, m, "Channel specified does not exist");
5138  return 0;
5139  }
5140 
5141  if (ast_strlen_zero(context)) {
5142  context = ast_channel_context(chan);
5143  }
5144 
5145  switch (ast_bridge_transfer_blind(1, chan, exten, context, NULL, NULL)) {
5147  astman_send_error(s, m, "Transfer not permitted");
5148  break;
5150  astman_send_error(s, m, "Transfer invalid");
5151  break;
5153  astman_send_error(s, m, "Transfer failed");
5154  break;
5156  astman_send_ack(s, m, "Transfer succeeded");
5157  break;
5158  }
5159 
5160  ast_channel_unref(chan);
5161  return 0;
5162 }
5163 
5164 static int action_atxfer(struct mansession *s, const struct message *m)
5165 {
5166  const char *name = astman_get_header(m, "Channel");
5167  const char *exten = astman_get_header(m, "Exten");
5168  const char *context = astman_get_header(m, "Context");
5169  struct ast_channel *chan = NULL;
5170  char feature_code[AST_FEATURE_MAX_LEN];
5171  const char *digit;
5172 
5173  if (ast_strlen_zero(name)) {
5174  astman_send_error(s, m, "No channel specified");
5175  return 0;
5176  }
5177  if (ast_strlen_zero(exten)) {
5178  astman_send_error(s, m, "No extension specified");
5179  return 0;
5180  }
5181 
5182  if (!(chan = ast_channel_get_by_name(name))) {
5183  astman_send_error(s, m, "Channel specified does not exist");
5184  return 0;
5185  }
5186 
5187  ast_channel_lock(chan);
5188  if (ast_get_builtin_feature(chan, "atxfer", feature_code, sizeof(feature_code)) ||
5189  ast_strlen_zero(feature_code)) {
5190  ast_channel_unlock(chan);
5191  astman_send_error(s, m, "No attended transfer feature code found");
5192  ast_channel_unref(chan);
5193  return 0;
5194  }
5195  ast_channel_unlock(chan);
5196 
5197  if (!ast_strlen_zero(context)) {
5198  pbx_builtin_setvar_helper(chan, "TRANSFER_CONTEXT", context);
5199  }
5200 
5201  for (digit = feature_code; *digit; ++digit) {
5202  struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
5203  ast_queue_frame(chan, &f);
5204  }
5205 
5206  for (digit = exten; *digit; ++digit) {
5207  struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
5208  ast_queue_frame(chan, &f);
5209  }
5210 
5211  chan = ast_channel_unref(chan);
5212 
5213  astman_send_ack(s, m, "Atxfer successfully queued");
5214 
5215  return 0;
5216 }
5217 
5218 static int action_cancel_atxfer(struct mansession *s, const struct message *m)
5219 {
5220  const char *name = astman_get_header(m, "Channel");
5221  struct ast_channel *chan = NULL;
5222  char *feature_code;
5223  const char *digit;
5224 
5225  if (ast_strlen_zero(name)) {
5226  astman_send_error(s, m, "No channel specified");
5227  return 0;
5228  }
5229 
5230  if (!(chan = ast_channel_get_by_name(name))) {
5231  astman_send_error(s, m, "Channel specified does not exist");
5232  return 0;
5233  }
5234 
5235  ast_channel_lock(chan);
5236  feature_code = ast_get_chan_features_atxferabort(chan);
5237  ast_channel_unlock(chan);
5238 
5239  if (!feature_code) {
5240  astman_send_error(s, m, "No disconnect feature code found");
5241  ast_channel_unref(chan);
5242  return 0;
5243  }
5244 
5245  for (digit = feature_code; *digit; ++digit) {
5246  struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
5247  ast_queue_frame(chan, &f);
5248  }
5249  ast_free(feature_code);
5250 
5251  chan = ast_channel_unref(chan);
5252 
5253  astman_send_ack(s, m, "CancelAtxfer successfully queued");
5254 
5255  return 0;
5256 }
5257 
5258 
5259 static int check_blacklist(const char *cmd)
5260 {
5261  char *cmd_copy, *cur_cmd;
5262  char *cmd_words[AST_MAX_CMD_LEN] = { NULL, };
5263  int i;
5264 
5265  cmd_copy = ast_strdupa(cmd);
5266  for (i = 0; i < MAX_BLACKLIST_CMD_LEN && (cur_cmd = strsep(&cmd_copy, " ")); i++) {
5267  cur_cmd = ast_strip(cur_cmd);
5268  if (ast_strlen_zero(cur_cmd)) {
5269  i--;
5270  continue;
5271  }
5272 
5273  cmd_words[i] = cur_cmd;
5274  }
5275 
5276  for (i = 0; i < ARRAY_LEN(command_blacklist); i++) {
5277  int j, match = 1;
5278 
5279  for (j = 0; command_blacklist[i].words[j]; j++) {
5280  if (ast_strlen_zero(cmd_words[j]) || strcasecmp(cmd_words[j], command_blacklist[i].words[j])) {
5281  match = 0;
5282  break;
5283  }
5284  }
5285 
5286  if (match) {
5287  return 1;
5288  }
5289  }
5290 
5291  return 0;
5292 }
5293 
5294 /*! \brief Manager command "command" - execute CLI command */
5295 static int action_command(struct mansession *s, const struct message *m)
5296 {
5297  const char *cmd = astman_get_header(m, "Command");
5298  char *buf = NULL, *final_buf = NULL, *delim, *output;
5299  char template[] = "/tmp/ast-ami-XXXXXX"; /* template for temporary file */
5300  int fd, ret;
5301  off_t len;
5302 
5303  if (ast_strlen_zero(cmd)) {
5304  astman_send_error(s, m, "No command provided");
5305  return 0;
5306  }
5307 
5308  if (check_blacklist(cmd)) {
5309  astman_send_error(s, m, "Command blacklisted");
5310  return 0;
5311  }
5312 
5313  if ((fd = mkstemp(template)) < 0) {
5314  astman_send_error_va(s, m, "Failed to create temporary file: %s", strerror(errno));
5315  return 0;
5316  }
5317 
5318  ret = ast_cli_command(fd, cmd);
5319  astman_send_response_full(s, m, ret == RESULT_SUCCESS ? "Success" : "Error", MSG_MOREDATA, NULL);
5320 
5321  /* Determine number of characters available */
5322  if ((len = lseek(fd, 0, SEEK_END)) < 0) {
5323  astman_append(s, "Message: Failed to determine number of characters: %s\r\n", strerror(errno));
5324  goto action_command_cleanup;
5325  }
5326 
5327  /* This has a potential to overflow the stack. Hence, use the heap. */
5328  buf = ast_malloc(len + 1);
5329  final_buf = ast_malloc(len + 1);
5330 
5331  if (!buf || !final_buf) {
5332  astman_append(s, "Message: Memory allocation failure\r\n");
5333  goto action_command_cleanup;
5334  }
5335 
5336  if (lseek(fd, 0, SEEK_SET) < 0) {
5337  astman_append(s, "Message: Failed to set position on temporary file: %s\r\n", strerror(errno));