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