Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
24  *
25  * OpenSSL http://www.openssl.org - for AMI/SSL
26  *
27  * At the moment this file contains a number of functions, namely:
28  *
29  * - data structures storing AMI state
30  * - AMI-related API functions, used by internal asterisk components
31  * - handlers for AMI-related CLI functions
32  * - handlers for AMI functions (available through the AMI socket)
33  * - the code for the main AMI listener thread and individual session threads
34  * - the http handlers invoked for AMI-over-HTTP by the threads in main/http.c
35  *
36  * \ref amiconf
37  */
38 
39 /*! \li \ref manager.c uses the configuration file \ref manager.conf and \ref users.conf
40  * \addtogroup configuration_file
41  */
42 
43 /*! \page manager.conf manager.conf
44  * \verbinclude manager.conf.sample
45  */
46 
47 /*! \page users.conf users.conf
48  * \verbinclude users.conf.sample
49  */
50 
51 /*** MODULEINFO
52  <support_level>core</support_level>
53  ***/
54 
55 #include "asterisk.h"
56 
57 #include "asterisk/paths.h" /* use various ast_config_AST_* */
58 #include <ctype.h>
59 #include <sys/time.h>
60 #include <signal.h>
61 #include <sys/mman.h>
62 #include <sys/types.h>
63 #include <regex.h>
64 
65 #include "asterisk/channel.h"
66 #include "asterisk/file.h"
67 #include "asterisk/manager.h"
68 #include "asterisk/module.h"
69 #include "asterisk/config.h"
70 #include "asterisk/callerid.h"
71 #include "asterisk/lock.h"
72 #include "asterisk/cli.h"
73 #include "asterisk/app.h"
74 #include "asterisk/mwi.h"
75 #include "asterisk/pbx.h"
76 #include "asterisk/md5.h"
77 #include "asterisk/acl.h"
78 #include "asterisk/utils.h"
79 #include "asterisk/tcptls.h"
80 #include "asterisk/http.h"
81 #include "asterisk/ast_version.h"
82 #include "asterisk/threadstorage.h"
83 #include "asterisk/linkedlists.h"
84 #include "asterisk/term.h"
85 #include "asterisk/astobj2.h"
86 #include "asterisk/features.h"
88 #include "asterisk/aoc.h"
89 #include "asterisk/strings.h"
90 #include "asterisk/stringfields.h"
91 #include "asterisk/presencestate.h"
95 #include "asterisk/test.h"
96 #include "asterisk/json.h"
97 #include "asterisk/bridge.h"
99 #include "asterisk/rtp_engine.h"
100 #include "asterisk/format_cache.h"
101 #include "asterisk/translate.h"
102 #include "asterisk/taskprocessor.h"
103 #include "asterisk/message.h"
104 
105 /*** DOCUMENTATION
106  <manager name="Ping" language="en_US">
107  <synopsis>
108  Keepalive command.
109  </synopsis>
110  <syntax>
111  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
112  </syntax>
113  <description>
114  <para>A 'Ping' action will ellicit a 'Pong' response. Used to keep the
115  manager connection open.</para>
116  </description>
117  </manager>
118  <manager name="Events" language="en_US">
119  <synopsis>
120  Control Event Flow.
121  </synopsis>
122  <syntax>
123  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
124  <parameter name="EventMask" required="true">
125  <enumlist>
126  <enum name="on">
127  <para>If all events should be sent.</para>
128  </enum>
129  <enum name="off">
130  <para>If no events should be sent.</para>
131  </enum>
132  <enum name="system,call,log,...">
133  <para>To select which flags events should have to be sent.</para>
134  </enum>
135  </enumlist>
136  </parameter>
137  </syntax>
138  <description>
139  <para>Enable/Disable sending of events to this manager client.</para>
140  </description>
141  </manager>
142  <manager name="Logoff" language="en_US">
143  <synopsis>
144  Logoff Manager.
145  </synopsis>
146  <syntax>
147  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
148  </syntax>
149  <description>
150  <para>Logoff the current manager session.</para>
151  </description>
152  <see-also>
153  <ref type="manager">Login</ref>
154  </see-also>
155  </manager>
156  <manager name="Login" language="en_US">
157  <synopsis>
158  Login Manager.
159  </synopsis>
160  <syntax>
161  <parameter name="ActionID">
162  <para>ActionID for this transaction. Will be returned.</para>
163  </parameter>
164  <parameter name="Username" required="true">
165  <para>Username to login with as specified in manager.conf.</para>
166  </parameter>
167  <parameter name="Secret">
168  <para>Secret to login with as specified in manager.conf.</para>
169  </parameter>
170  </syntax>
171  <description>
172  <para>Login Manager.</para>
173  </description>
174  <see-also>
175  <ref type="manager">Logoff</ref>
176  </see-also>
177  </manager>
178  <manager name="Challenge" language="en_US">
179  <synopsis>
180  Generate Challenge for MD5 Auth.
181  </synopsis>
182  <syntax>
183  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
184  <parameter name="AuthType" required="true">
185  <para>Digest algorithm to use in the challenge. Valid values are:</para>
186  <enumlist>
187  <enum name="MD5" />
188  </enumlist>
189  </parameter>
190  </syntax>
191  <description>
192  <para>Generate a challenge for MD5 authentication.</para>
193  </description>
194  </manager>
195  <manager name="Hangup" language="en_US">
196  <synopsis>
197  Hangup channel.
198  </synopsis>
199  <syntax>
200  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
201  <parameter name="Channel" required="true">
202  <para>The exact channel name to be hungup, or to use a regular expression, set this parameter to: /regex/</para>
203  <para>Example exact channel: SIP/provider-0000012a</para>
204  <para>Example regular expression: /^SIP/provider-.*$/</para>
205  </parameter>
206  <parameter name="Cause">
207  <para>Numeric hangup cause.</para>
208  </parameter>
209  </syntax>
210  <description>
211  <para>Hangup a channel.</para>
212  </description>
213  </manager>
214  <manager name="Status" language="en_US">
215  <synopsis>
216  List channel status.
217  </synopsis>
218  <syntax>
219  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
220  <parameter name="Channel" required="false">
221  <para>The name of the channel to query for status.</para>
222  </parameter>
223  <parameter name="Variables">
224  <para>Comma <literal>,</literal> separated list of variable to include.</para>
225  </parameter>
226  <parameter name="AllVariables">
227  <para>If set to "true", the Status event will include all channel variables for
228  the requested channel(s).</para>
229  <enumlist>
230  <enum name="true"/>
231  <enum name="false"/>
232  </enumlist>
233  </parameter>
234  </syntax>
235  <description>
236  <para>Will return the status information of each channel along with the
237  value for the specified channel variables.</para>
238  </description>
239  <responses>
240  <list-elements>
241  <xi:include xpointer="xpointer(/docs/managerEvent[@name='Status'])" />
242  </list-elements>
243  <xi:include xpointer="xpointer(/docs/managerEvent[@name='StatusComplete'])" />
244  </responses>
245  </manager>
246  <managerEvent language="en_US" name="Status">
247  <managerEventInstance class="EVENT_FLAG_CALL">
248  <synopsis>Raised in response to a Status command.</synopsis>
249  <syntax>
250  <parameter name="ActionID" required="false"/>
251  <channel_snapshot/>
252  <parameter name="Type">
253  <para>Type of channel</para>
254  </parameter>
255  <parameter name="DNID">
256  <para>Dialed number identifier</para>
257  </parameter>
258  <parameter name="EffectiveConnectedLineNum">
259  </parameter>
260  <parameter name="EffectiveConnectedLineName">
261  </parameter>
262  <parameter name="TimeToHangup">
263  <para>Absolute lifetime of the channel</para>
264  </parameter>
265  <parameter name="BridgeID">
266  <para>Identifier of the bridge the channel is in, may be empty if not in one</para>
267  </parameter>
268  <parameter name="Application">
269  <para>Application currently executing on the channel</para>
270  </parameter>
271  <parameter name="Data">
272  <para>Data given to the currently executing channel</para>
273  </parameter>
274  <parameter name="Nativeformats">
275  <para>Media formats the connected party is willing to send or receive</para>
276  </parameter>
277  <parameter name="Readformat">
278  <para>Media formats that frames from the channel are received in</para>
279  </parameter>
280  <parameter name="Readtrans">
281  <para>Translation path for media received in native formats</para>
282  </parameter>
283  <parameter name="Writeformat">
284  <para>Media formats that frames to the channel are accepted in</para>
285  </parameter>
286  <parameter name="Writetrans">
287  <para>Translation path for media sent to the connected party</para>
288  </parameter>
289  <parameter name="Callgroup">
290  <para>Configured call group on the channel</para>
291  </parameter>
292  <parameter name="Pickupgroup">
293  <para>Configured pickup group on the channel</para>
294  </parameter>
295  <parameter name="Seconds">
296  <para>Number of seconds the channel has been active</para>
297  </parameter>
298  </syntax>
299  <see-also>
300  <ref type="manager">Status</ref>
301  </see-also>
302  </managerEventInstance>
303  </managerEvent>
304  <managerEvent language="en_US" name="StatusComplete">
305  <managerEventInstance class="EVENT_FLAG_CALL">
306  <synopsis>Raised in response to a Status command.</synopsis>
307  <syntax>
308  <parameter name="Items">
309  <para>Number of Status events returned</para>
310  </parameter>
311  </syntax>
312  <see-also>
313  <ref type="manager">Status</ref>
314  </see-also>
315  </managerEventInstance>
316  </managerEvent>
317  <manager name="Setvar" language="en_US">
318  <synopsis>
319  Sets a channel variable or function value.
320  </synopsis>
321  <syntax>
322  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
323  <parameter name="Channel">
324  <para>Channel to set variable for.</para>
325  </parameter>
326  <parameter name="Variable" required="true">
327  <para>Variable name, function or expression.</para>
328  </parameter>
329  <parameter name="Value" required="true">
330  <para>Variable or function value.</para>
331  </parameter>
332  </syntax>
333  <description>
334  <para>This command can be used to set the value of channel variables or dialplan
335  functions.</para>
336  <note>
337  <para>If a channel name is not provided then the variable is considered global.</para>
338  </note>
339  </description>
340  <see-also>
341  <ref type="manager">Getvar</ref>
342  </see-also>
343  </manager>
344  <manager name="Getvar" language="en_US">
345  <synopsis>
346  Gets a channel variable or function value.
347  </synopsis>
348  <syntax>
349  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
350  <parameter name="Channel">
351  <para>Channel to read variable from.</para>
352  </parameter>
353  <parameter name="Variable" required="true">
354  <para>Variable name, function or expression.</para>
355  </parameter>
356  </syntax>
357  <description>
358  <para>Get the value of a channel variable or function return.</para>
359  <note>
360  <para>If a channel name is not provided then the variable is considered global.</para>
361  </note>
362  </description>
363  <see-also>
364  <ref type="manager">Setvar</ref>
365  </see-also>
366  </manager>
367  <manager name="GetConfig" language="en_US">
368  <synopsis>
369  Retrieve configuration.
370  </synopsis>
371  <syntax>
372  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
373  <parameter name="Filename" required="true">
374  <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
375  </parameter>
376  <parameter name="Category">
377  <para>Category in configuration file.</para>
378  </parameter>
379  <parameter name="Filter">
380  <para>A comma separated list of
381  <replaceable>name_regex</replaceable>=<replaceable>value_regex</replaceable>
382  expressions which will cause only categories whose variables match all expressions
383  to be considered. The special variable name <literal>TEMPLATES</literal>
384  can be used to control whether templates are included. Passing
385  <literal>include</literal> as the value will include templates
386  along with normal categories. Passing
387  <literal>restrict</literal> as the value will restrict the operation to
388  ONLY templates. Not specifying a <literal>TEMPLATES</literal> expression
389  results in the default behavior which is to not include templates.</para>
390  </parameter>
391  </syntax>
392  <description>
393  <para>This action will dump the contents of a configuration
394  file by category and contents or optionally by specified category only.
395  In the case where a category name is non-unique, a filter may be specified
396  to match only categories with matching variable values.</para>
397  </description>
398  <see-also>
399  <ref type="manager">GetConfigJSON</ref>
400  <ref type="manager">UpdateConfig</ref>
401  <ref type="manager">CreateConfig</ref>
402  <ref type="manager">ListCategories</ref>
403  </see-also>
404  </manager>
405  <manager name="GetConfigJSON" language="en_US">
406  <synopsis>
407  Retrieve configuration (JSON format).
408  </synopsis>
409  <syntax>
410  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
411  <parameter name="Filename" required="true">
412  <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
413  </parameter>
414  <parameter name="Category">
415  <para>Category in configuration file.</para>
416  </parameter>
417  <parameter name="Filter">
418  <xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
419  </parameter>
420  </syntax>
421  <description>
422  <para>This action will dump the contents of a configuration file by category
423  and contents in JSON format or optionally by specified category only.
424  This only makes sense to be used using rawman over the HTTP interface.
425  In the case where a category name is non-unique, a filter may be specified
426  to match only categories with matching variable values.</para>
427  </description>
428  <see-also>
429  <ref type="manager">GetConfig</ref>
430  <ref type="manager">UpdateConfig</ref>
431  <ref type="manager">CreateConfig</ref>
432  <ref type="manager">ListCategories</ref>
433  </see-also>
434  </manager>
435  <manager name="UpdateConfig" language="en_US">
436  <synopsis>
437  Update basic configuration.
438  </synopsis>
439  <syntax>
440  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
441  <parameter name="SrcFilename" required="true">
442  <para>Configuration filename to read (e.g. <filename>foo.conf</filename>).</para>
443  </parameter>
444  <parameter name="DstFilename" required="true">
445  <para>Configuration filename to write (e.g. <filename>foo.conf</filename>)</para>
446  </parameter>
447  <parameter name="Reload">
448  <para>Whether or not a reload should take place (or name of specific module).</para>
449  </parameter>
450  <parameter name="PreserveEffectiveContext">
451  <para>Whether the effective category contents should be preserved on template change. Default is true (pre 13.2 behavior).</para>
452  </parameter>
453  <parameter name="Action-000000">
454  <para>Action to take.</para>
455  <para>0's represent 6 digit number beginning with 000000.</para>
456  <enumlist>
457  <enum name="NewCat" />
458  <enum name="RenameCat" />
459  <enum name="DelCat" />
460  <enum name="EmptyCat" />
461  <enum name="Update" />
462  <enum name="Delete" />
463  <enum name="Append" />
464  <enum name="Insert" />
465  </enumlist>
466  </parameter>
467  <parameter name="Cat-000000">
468  <para>Category to operate on.</para>
469  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
470  </parameter>
471  <parameter name="Var-000000">
472  <para>Variable to work on.</para>
473  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
474  </parameter>
475  <parameter name="Value-000000">
476  <para>Value to work on.</para>
477  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
478  </parameter>
479  <parameter name="Match-000000">
480  <para>Extra match required to match line.</para>
481  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
482  </parameter>
483  <parameter name="Line-000000">
484  <para>Line in category to operate on (used with delete and insert actions).</para>
485  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
486  </parameter>
487  <parameter name="Options-000000">
488  <para>A comma separated list of action-specific options.</para>
489  <enumlist>
490  <enum name="NewCat"><para>One or more of the following... </para>
491  <enumlist>
492  <enum name="allowdups"><para>Allow duplicate category names.</para></enum>
493  <enum name="template"><para>This category is a template.</para></enum>
494  <enum name="inherit=&quot;template[,...]&quot;"><para>Templates from which to inherit.</para></enum>
495  </enumlist>
496  </enum>
497  </enumlist>
498  <para> </para>
499  <para>The following actions share the same options...</para>
500  <enumlist>
501  <enum name="RenameCat"/>
502  <enum name="DelCat"/>
503  <enum name="EmptyCat"/>
504  <enum name="Update"/>
505  <enum name="Delete"/>
506  <enum name="Append"/>
507  <enum name="Insert"><para> </para>
508  <enumlist>
509  <enum name="catfilter=&quot;&lt;expression&gt;[,...]&quot;"><para> </para>
510  <xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
511  <para><literal>catfilter</literal> is most useful when a file
512  contains multiple categories with the same name and you wish to
513  operate on specific ones instead of all of them.</para>
514  </enum>
515  </enumlist>
516  </enum>
517  </enumlist>
518  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
519  </parameter>
520  </syntax>
521  <description>
522  <para>This action will modify, create, or delete configuration elements
523  in Asterisk configuration files.</para>
524  </description>
525  <see-also>
526  <ref type="manager">GetConfig</ref>
527  <ref type="manager">GetConfigJSON</ref>
528  <ref type="manager">CreateConfig</ref>
529  <ref type="manager">ListCategories</ref>
530  </see-also>
531  </manager>
532  <manager name="CreateConfig" language="en_US">
533  <synopsis>
534  Creates an empty file in the configuration directory.
535  </synopsis>
536  <syntax>
537  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
538  <parameter name="Filename" required="true">
539  <para>The configuration filename to create (e.g. <filename>foo.conf</filename>).</para>
540  </parameter>
541  </syntax>
542  <description>
543  <para>This action will create an empty file in the configuration
544  directory. This action is intended to be used before an UpdateConfig
545  action.</para>
546  </description>
547  <see-also>
548  <ref type="manager">GetConfig</ref>
549  <ref type="manager">GetConfigJSON</ref>
550  <ref type="manager">UpdateConfig</ref>
551  <ref type="manager">ListCategories</ref>
552  </see-also>
553  </manager>
554  <manager name="ListCategories" language="en_US">
555  <synopsis>
556  List categories in configuration file.
557  </synopsis>
558  <syntax>
559  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
560  <parameter name="Filename" required="true">
561  <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
562  </parameter>
563  </syntax>
564  <description>
565  <para>This action will dump the categories in a given file.</para>
566  </description>
567  <see-also>
568  <ref type="manager">GetConfig</ref>
569  <ref type="manager">GetConfigJSON</ref>
570  <ref type="manager">UpdateConfig</ref>
571  <ref type="manager">CreateConfig</ref>
572  </see-also>
573  </manager>
574  <manager name="Redirect" language="en_US">
575  <synopsis>
576  Redirect (transfer) a call.
577  </synopsis>
578  <syntax>
579  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
580  <parameter name="Channel" required="true">
581  <para>Channel to redirect.</para>
582  </parameter>
583  <parameter name="ExtraChannel">
584  <para>Second call leg to transfer (optional).</para>
585  </parameter>
586  <parameter name="Exten" required="true">
587  <para>Extension to transfer to.</para>
588  </parameter>
589  <parameter name="ExtraExten">
590  <para>Extension to transfer extrachannel to (optional).</para>
591  </parameter>
592  <parameter name="Context" required="true">
593  <para>Context to transfer to.</para>
594  </parameter>
595  <parameter name="ExtraContext">
596  <para>Context to transfer extrachannel to (optional).</para>
597  </parameter>
598  <parameter name="Priority" required="true">
599  <para>Priority to transfer to.</para>
600  </parameter>
601  <parameter name="ExtraPriority">
602  <para>Priority to transfer extrachannel to (optional).</para>
603  </parameter>
604  </syntax>
605  <description>
606  <para>Redirect (transfer) a call.</para>
607  </description>
608  <see-also>
609  <ref type="manager">BlindTransfer</ref>
610  </see-also>
611  </manager>
612  <manager name="Atxfer" language="en_US">
613  <synopsis>
614  Attended transfer.
615  </synopsis>
616  <syntax>
617  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
618  <parameter name="Channel" required="true">
619  <para>Transferer's channel.</para>
620  </parameter>
621  <parameter name="Exten" required="true">
622  <para>Extension to transfer to.</para>
623  </parameter>
624  <parameter name="Context">
625  <para>Context to transfer to.</para>
626  </parameter>
627  </syntax>
628  <description>
629  <para>Attended transfer.</para>
630  </description>
631  <see-also>
632  <ref type="managerEvent">AttendedTransfer</ref>
633  </see-also>
634  </manager>
635  <manager name="CancelAtxfer" language="en_US">
636  <synopsis>
637  Cancel an attended transfer.
638  </synopsis>
639  <syntax>
640  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
641  <parameter name="Channel" required="true">
642  <para>The transferer channel.</para>
643  </parameter>
644  </syntax>
645  <description>
646  <para>Cancel an attended transfer. Note, this uses the configured cancel attended transfer
647  feature option (atxferabort) to cancel the transfer. If not available this action will fail.
648  </para>
649  </description>
650  <see-also>
651  <ref type="managerEvent">AttendedTransfer</ref>
652  </see-also>
653  </manager>
654  <manager name="Originate" language="en_US">
655  <synopsis>
656  Originate a call.
657  </synopsis>
658  <syntax>
659  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
660  <parameter name="Channel" required="true">
661  <para>Channel name to call.</para>
662  </parameter>
663  <parameter name="Exten">
664  <para>Extension to use (requires <literal>Context</literal> and
665  <literal>Priority</literal>)</para>
666  </parameter>
667  <parameter name="Context">
668  <para>Context to use (requires <literal>Exten</literal> and
669  <literal>Priority</literal>)</para>
670  </parameter>
671  <parameter name="Priority">
672  <para>Priority to use (requires <literal>Exten</literal> and
673  <literal>Context</literal>)</para>
674  </parameter>
675  <parameter name="Application">
676  <para>Application to execute.</para>
677  </parameter>
678  <parameter name="Data">
679  <para>Data to use (requires <literal>Application</literal>).</para>
680  </parameter>
681  <parameter name="Timeout" default="30000">
682  <para>How long to wait for call to be answered (in ms.).</para>
683  </parameter>
684  <parameter name="CallerID">
685  <para>Caller ID to be set on the outgoing channel.</para>
686  </parameter>
687  <parameter name="Variable">
688  <para>Channel variable to set, multiple Variable: headers are allowed.</para>
689  </parameter>
690  <parameter name="Account">
691  <para>Account code.</para>
692  </parameter>
693  <parameter name="EarlyMedia">
694  <para>Set to <literal>true</literal> to force call bridge on early media..</para>
695  </parameter>
696  <parameter name="Async">
697  <para>Set to <literal>true</literal> for fast origination.</para>
698  </parameter>
699  <parameter name="Codecs">
700  <para>Comma-separated list of codecs to use for this call.</para>
701  </parameter>
702  <parameter name="ChannelId">
703  <para>Channel UniqueId to be set on the channel.</para>
704  </parameter>
705  <parameter name="OtherChannelId">
706  <para>Channel UniqueId to be set on the second local channel.</para>
707  </parameter>
708  </syntax>
709  <description>
710  <para>Generates an outgoing call to a
711  <replaceable>Extension</replaceable>/<replaceable>Context</replaceable>/<replaceable>Priority</replaceable>
712  or <replaceable>Application</replaceable>/<replaceable>Data</replaceable></para>
713  </description>
714  <see-also>
715  <ref type="managerEvent">OriginateResponse</ref>
716  </see-also>
717  </manager>
718  <managerEvent language="en_US" name="OriginateResponse">
719  <managerEventInstance class="EVENT_FLAG_CALL">
720  <synopsis>Raised in response to an Originate command.</synopsis>
721  <syntax>
722  <parameter name="ActionID" required="false"/>
723  <parameter name="Response">
724  <enumlist>
725  <enum name="Failure"/>
726  <enum name="Success"/>
727  </enumlist>
728  </parameter>
729  <parameter name="Channel"/>
730  <parameter name="Context"/>
731  <parameter name="Exten"/>
732  <parameter name="Application"/>
733  <parameter name="Data"/>
734  <parameter name="Reason"/>
735  <parameter name="Uniqueid"/>
736  <parameter name="CallerIDNum"/>
737  <parameter name="CallerIDName"/>
738  </syntax>
739  <see-also>
740  <ref type="manager">Originate</ref>
741  </see-also>
742  </managerEventInstance>
743  </managerEvent>
744  <manager name="Command" language="en_US">
745  <synopsis>
746  Execute Asterisk CLI Command.
747  </synopsis>
748  <syntax>
749  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
750  <parameter name="Command" required="true">
751  <para>Asterisk CLI command to run.</para>
752  </parameter>
753  </syntax>
754  <description>
755  <para>Run a CLI command.</para>
756  </description>
757  </manager>
758  <manager name="ExtensionState" language="en_US">
759  <synopsis>
760  Check Extension Status.
761  </synopsis>
762  <syntax>
763  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
764  <parameter name="Exten" required="true">
765  <para>Extension to check state on.</para>
766  </parameter>
767  <parameter name="Context" required="true">
768  <para>Context for extension.</para>
769  </parameter>
770  </syntax>
771  <description>
772  <para>Report the extension state for given extension. If the extension has a hint,
773  will use devicestate to check the status of the device connected to the extension.</para>
774  <para>Will return an <literal>Extension Status</literal> message. The response will include
775  the hint for the extension and the status.</para>
776  </description>
777  <see-also>
778  <ref type="managerEvent">ExtensionStatus</ref>
779  </see-also>
780  </manager>
781  <manager name="PresenceState" language="en_US">
782  <synopsis>
783  Check Presence State
784  </synopsis>
785  <syntax>
786  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
787  <parameter name="Provider" required="true">
788  <para>Presence Provider to check the state of</para>
789  </parameter>
790  </syntax>
791  <description>
792  <para>Report the presence state for the given presence provider.</para>
793  <para>Will return a <literal>Presence State</literal> message. The response will include the
794  presence state and, if set, a presence subtype and custom message.</para>
795  </description>
796  <see-also>
797  <ref type="managerEvent">PresenceStatus</ref>
798  </see-also>
799  </manager>
800  <manager name="AbsoluteTimeout" language="en_US">
801  <synopsis>
802  Set absolute timeout.
803  </synopsis>
804  <syntax>
805  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
806  <parameter name="Channel" required="true">
807  <para>Channel name to hangup.</para>
808  </parameter>
809  <parameter name="Timeout" required="true">
810  <para>Maximum duration of the call (sec).</para>
811  </parameter>
812  </syntax>
813  <description>
814  <para>Hangup a channel after a certain time. Acknowledges set time with
815  <literal>Timeout Set</literal> message.</para>
816  </description>
817  </manager>
818  <manager name="MailboxStatus" language="en_US">
819  <synopsis>
820  Check mailbox.
821  </synopsis>
822  <syntax>
823  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
824  <parameter name="Mailbox" required="true">
825  <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
826  </parameter>
827  </syntax>
828  <description>
829  <para>Checks a voicemail account for status.</para>
830  <para>Returns whether there are messages waiting.</para>
831  <para>Message: Mailbox Status.</para>
832  <para>Mailbox: <replaceable>mailboxid</replaceable>.</para>
833  <para>Waiting: <literal>0</literal> if messages waiting, <literal>1</literal>
834  if no messages waiting.</para>
835  </description>
836  <see-also>
837  <ref type="manager">MailboxCount</ref>
838  </see-also>
839  </manager>
840  <manager name="MailboxCount" language="en_US">
841  <synopsis>
842  Check Mailbox Message Count.
843  </synopsis>
844  <syntax>
845  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
846  <parameter name="Mailbox" required="true">
847  <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
848  </parameter>
849  </syntax>
850  <description>
851  <para>Checks a voicemail account for new messages.</para>
852  <para>Returns number of urgent, new and old messages.</para>
853  <para>Message: Mailbox Message Count</para>
854  <para>Mailbox: <replaceable>mailboxid</replaceable></para>
855  <para>UrgentMessages: <replaceable>count</replaceable></para>
856  <para>NewMessages: <replaceable>count</replaceable></para>
857  <para>OldMessages: <replaceable>count</replaceable></para>
858  </description>
859  <see-also>
860  <ref type="manager">MailboxStatus</ref>
861  </see-also>
862  </manager>
863  <manager name="ListCommands" language="en_US">
864  <synopsis>
865  List available manager commands.
866  </synopsis>
867  <syntax>
868  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
869  </syntax>
870  <description>
871  <para>Returns the action name and synopsis for every action that
872  is available to the user.</para>
873  </description>
874  </manager>
875  <manager name="SendText" language="en_US">
876  <synopsis>
877  Sends a text message to channel. A content type can be optionally specified. If not set
878  it is set to an empty string allowing a custom handler to default it as it sees fit.
879  </synopsis>
880  <syntax>
881  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
882  <parameter name="Channel" required="true">
883  <para>Channel to send message to.</para>
884  </parameter>
885  <parameter name="Message" required="true">
886  <para>Message to send.</para>
887  </parameter>
888  <parameter name="Content-Type" required="false" default="">
889  <para>The type of content in the message</para>
890  </parameter>
891  </syntax>
892  <description>
893  <para>Sends A Text Message to a channel while in a call.</para>
894  </description>
895  <see-also>
896  <ref type="application">SendText</ref>
897  </see-also>
898  </manager>
899  <manager name="UserEvent" language="en_US">
900  <synopsis>
901  Send an arbitrary event.
902  </synopsis>
903  <syntax>
904  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
905  <parameter name="UserEvent" required="true">
906  <para>Event string to send.</para>
907  </parameter>
908  <parameter name="Header1">
909  <para>Content1.</para>
910  </parameter>
911  <parameter name="HeaderN">
912  <para>ContentN.</para>
913  </parameter>
914  </syntax>
915  <description>
916  <para>Send an event to manager sessions.</para>
917  </description>
918  <see-also>
919  <ref type="managerEvent">UserEvent</ref>
920  <ref type="application">UserEvent</ref>
921  </see-also>
922  </manager>
923  <manager name="WaitEvent" language="en_US">
924  <synopsis>
925  Wait for an event to occur.
926  </synopsis>
927  <syntax>
928  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
929  <parameter name="Timeout" required="true">
930  <para>Maximum time (in seconds) to wait for events, <literal>-1</literal> means forever.</para>
931  </parameter>
932  </syntax>
933  <description>
934  <para>This action will ellicit a <literal>Success</literal> response. Whenever
935  a manager event is queued. Once WaitEvent has been called on an HTTP manager
936  session, events will be generated and queued.</para>
937  </description>
938  </manager>
939  <manager name="CoreSettings" language="en_US">
940  <synopsis>
941  Show PBX core settings (version etc).
942  </synopsis>
943  <syntax>
944  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
945  </syntax>
946  <description>
947  <para>Query for Core PBX settings.</para>
948  </description>
949  </manager>
950  <manager name="CoreStatus" language="en_US">
951  <synopsis>
952  Show PBX core status variables.
953  </synopsis>
954  <syntax>
955  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
956  </syntax>
957  <description>
958  <para>Query for Core PBX status.</para>
959  </description>
960  </manager>
961  <manager name="Reload" language="en_US">
962  <synopsis>
963  Send a reload event.
964  </synopsis>
965  <syntax>
966  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
967  <parameter name="Module">
968  <para>Name of the module to reload.</para>
969  </parameter>
970  </syntax>
971  <description>
972  <para>Send a reload event.</para>
973  </description>
974  <see-also>
975  <ref type="manager">ModuleLoad</ref>
976  </see-also>
977  </manager>
978  <managerEvent language="en_US" name="CoreShowChannel">
979  <managerEventInstance class="EVENT_FLAG_CALL">
980  <synopsis>Raised in response to a CoreShowChannels command.</synopsis>
981  <syntax>
982  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
983  <channel_snapshot/>
984  <parameter name="BridgeId">
985  <para>Identifier of the bridge the channel is in, may be empty if not in one</para>
986  </parameter>
987  <parameter name="Application">
988  <para>Application currently executing on the channel</para>
989  </parameter>
990  <parameter name="ApplicationData">
991  <para>Data given to the currently executing application</para>
992  </parameter>
993  <parameter name="Duration">
994  <para>The amount of time the channel has existed</para>
995  </parameter>
996  </syntax>
997  <see-also>
998  <ref type="manager">CoreShowChannels</ref>
999  <ref type="managerEvent">CoreShowChannelsComplete</ref>
1000  </see-also>
1001  </managerEventInstance>
1002  </managerEvent>
1003  <managerEvent language="en_US" name="CoreShowChannelsComplete">
1004  <managerEventInstance class="EVENT_FLAG_CALL">
1005  <synopsis>Raised at the end of the CoreShowChannel list produced by the CoreShowChannels command.</synopsis>
1006  <syntax>
1007  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1008  <parameter name="EventList">
1009  <para>Conveys the status of the command reponse list</para>
1010  </parameter>
1011  <parameter name="ListItems">
1012  <para>The total number of list items produced</para>
1013  </parameter>
1014  </syntax>
1015  <see-also>
1016  <ref type="manager">CoreShowChannels</ref>
1017  <ref type="managerEvent">CoreShowChannel</ref>
1018  </see-also>
1019  </managerEventInstance>
1020  </managerEvent>
1021  <manager name="CoreShowChannels" language="en_US">
1022  <synopsis>
1023  List currently active channels.
1024  </synopsis>
1025  <syntax>
1026  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1027  </syntax>
1028  <description>
1029  <para>List currently defined channels and some information about them.</para>
1030  </description>
1031  <responses>
1032  <list-elements>
1033  <xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannel'])" />
1034  </list-elements>
1035  <xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannelsComplete'])" />
1036  </responses>
1037  </manager>
1038  <manager name="LoggerRotate" language="en_US">
1039  <synopsis>
1040  Reload and rotate the Asterisk logger.
1041  </synopsis>
1042  <syntax>
1043  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1044  </syntax>
1045  <description>
1046  <para>Reload and rotate the logger. Analogous to the CLI command 'logger rotate'.</para>
1047  </description>
1048  </manager>
1049  <manager name="ModuleLoad" language="en_US">
1050  <synopsis>
1051  Module management.
1052  </synopsis>
1053  <syntax>
1054  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1055  <parameter name="Module">
1056  <para>Asterisk module name (including .so extension) or subsystem identifier:</para>
1057  <enumlist>
1058  <enum name="cdr" />
1059  <enum name="dnsmgr" />
1060  <enum name="extconfig" />
1061  <enum name="enum" />
1062  <enum name="acl" />
1063  <enum name="manager" />
1064  <enum name="http" />
1065  <enum name="logger" />
1066  <enum name="features" />
1067  <enum name="dsp" />
1068  <enum name="udptl" />
1069  <enum name="indications" />
1070  <enum name="cel" />
1071  <enum name="plc" />
1072  </enumlist>
1073  </parameter>
1074  <parameter name="LoadType" required="true">
1075  <para>The operation to be done on module. Subsystem identifiers may only
1076  be reloaded.</para>
1077  <enumlist>
1078  <enum name="load" />
1079  <enum name="unload" />
1080  <enum name="reload" />
1081  </enumlist>
1082  <para>If no module is specified for a <literal>reload</literal> loadtype,
1083  all modules are reloaded.</para>
1084  </parameter>
1085  </syntax>
1086  <description>
1087  <para>Loads, unloads or reloads an Asterisk module in a running system.</para>
1088  </description>
1089  <see-also>
1090  <ref type="manager">Reload</ref>
1091  <ref type="manager">ModuleCheck</ref>
1092  </see-also>
1093  </manager>
1094  <manager name="ModuleCheck" language="en_US">
1095  <synopsis>
1096  Check if module is loaded.
1097  </synopsis>
1098  <syntax>
1099  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1100  <parameter name="Module" required="true">
1101  <para>Asterisk module name (not including extension).</para>
1102  </parameter>
1103  </syntax>
1104  <description>
1105  <para>Checks if Asterisk module is loaded. Will return Success/Failure.
1106  For success returns, the module revision number is included.</para>
1107  </description>
1108  <see-also>
1109  <ref type="manager">ModuleLoad</ref>
1110  </see-also>
1111  </manager>
1112  <manager name="AOCMessage" language="en_US">
1113  <synopsis>
1114  Generate an Advice of Charge message on a channel.
1115  </synopsis>
1116  <syntax>
1117  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1118  <parameter name="Channel" required="true">
1119  <para>Channel name to generate the AOC message on.</para>
1120  </parameter>
1121  <parameter name="ChannelPrefix">
1122  <para>Partial channel prefix. By using this option one can match the beginning part
1123  of a channel name without having to put the entire name in. For example
1124  if a channel name is SIP/snom-00000001 and this value is set to SIP/snom, then
1125  that channel matches and the message will be sent. Note however that only
1126  the first matched channel has the message sent on it. </para>
1127  </parameter>
1128  <parameter name="MsgType" required="true">
1129  <para>Defines what type of AOC message to create, AOC-D or AOC-E</para>
1130  <enumlist>
1131  <enum name="D" />
1132  <enum name="E" />
1133  </enumlist>
1134  </parameter>
1135  <parameter name="ChargeType" required="true">
1136  <para>Defines what kind of charge this message represents.</para>
1137  <enumlist>
1138  <enum name="NA" />
1139  <enum name="FREE" />
1140  <enum name="Currency" />
1141  <enum name="Unit" />
1142  </enumlist>
1143  </parameter>
1144  <parameter name="UnitAmount(0)">
1145  <para>This represents the amount of units charged. The ETSI AOC standard specifies that
1146  this value along with the optional UnitType value are entries in a list. To accommodate this
1147  these values take an index value starting at 0 which can be used to generate this list of
1148  unit entries. For Example, If two unit entires were required this could be achieved by setting the
1149  paramter UnitAmount(0)=1234 and UnitAmount(1)=5678. Note that UnitAmount at index 0 is
1150  required when ChargeType=Unit, all other entries in the list are optional.
1151  </para>
1152  </parameter>
1153  <parameter name="UnitType(0)">
1154  <para>Defines the type of unit. ETSI AOC standard specifies this as an integer
1155  value between 1 and 16, but this value is left open to accept any positive
1156  integer. Like the UnitAmount parameter, this value represents a list entry
1157  and has an index parameter that starts at 0.
1158  </para>
1159  </parameter>
1160  <parameter name="CurrencyName">
1161  <para>Specifies the currency's name. Note that this value is truncated after 10 characters.</para>
1162  </parameter>
1163  <parameter name="CurrencyAmount">
1164  <para>Specifies the charge unit amount as a positive integer. This value is required
1165  when ChargeType==Currency.</para>
1166  </parameter>
1167  <parameter name="CurrencyMultiplier">
1168  <para>Specifies the currency multiplier. This value is required when ChargeType==Currency.</para>
1169  <enumlist>
1170  <enum name="OneThousandth" />
1171  <enum name="OneHundredth" />
1172  <enum name="OneTenth" />
1173  <enum name="One" />
1174  <enum name="Ten" />
1175  <enum name="Hundred" />
1176  <enum name="Thousand" />
1177  </enumlist>
1178  </parameter>
1179  <parameter name="TotalType" default="Total">
1180  <para>Defines what kind of AOC-D total is represented.</para>
1181  <enumlist>
1182  <enum name="Total" />
1183  <enum name="SubTotal" />
1184  </enumlist>
1185  </parameter>
1186  <parameter name="AOCBillingId">
1187  <para>Represents a billing ID associated with an AOC-D or AOC-E message. Note
1188  that only the first 3 items of the enum are valid AOC-D billing IDs</para>
1189  <enumlist>
1190  <enum name="Normal" />
1191  <enum name="ReverseCharge" />
1192  <enum name="CreditCard" />
1193  <enum name="CallFwdUnconditional" />
1194  <enum name="CallFwdBusy" />
1195  <enum name="CallFwdNoReply" />
1196  <enum name="CallDeflection" />
1197  <enum name="CallTransfer" />
1198  </enumlist>
1199  </parameter>
1200  <parameter name="ChargingAssociationId">
1201  <para>Charging association identifier. This is optional for AOC-E and can be
1202  set to any value between -32768 and 32767</para>
1203  </parameter>
1204  <parameter name="ChargingAssociationNumber">
1205  <para>Represents the charging association party number. This value is optional
1206  for AOC-E.</para>
1207  </parameter>
1208  <parameter name="ChargingAssociationPlan">
1209  <para>Integer representing the charging plan associated with the ChargingAssociationNumber.
1210  The value is bits 7 through 1 of the Q.931 octet containing the type-of-number and
1211  numbering-plan-identification fields.</para>
1212  </parameter>
1213  </syntax>
1214  <description>
1215  <para>Generates an AOC-D or AOC-E message on a channel.</para>
1216  </description>
1217  <see-also>
1218  <ref type="managerEvent">AOC-D</ref>
1219  <ref type="managerEvent">AOC-E</ref>
1220  </see-also>
1221  </manager>
1222  <function name="AMI_CLIENT" language="en_US">
1223  <synopsis>
1224  Checks attributes of manager accounts
1225  </synopsis>
1226  <syntax>
1227  <parameter name="loginname" required="true">
1228  <para>Login name, specified in manager.conf</para>
1229  </parameter>
1230  <parameter name="field" required="true">
1231  <para>The manager account attribute to return</para>
1232  <enumlist>
1233  <enum name="sessions"><para>The number of sessions for this AMI account</para></enum>
1234  </enumlist>
1235  </parameter>
1236  </syntax>
1237  <description>
1238  <para>
1239  Currently, the only supported parameter is "sessions" which will return the current number of
1240  active sessions for this AMI account.
1241  </para>
1242  </description>
1243  </function>
1244  <manager name="Filter" language="en_US">
1245  <synopsis>
1246  Dynamically add filters for the current manager session.
1247  </synopsis>
1248  <syntax>
1249  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1250  <parameter name="Operation">
1251  <enumlist>
1252  <enum name="Add">
1253  <para>Add a filter.</para>
1254  </enum>
1255  </enumlist>
1256  </parameter>
1257  <parameter name="Filter">
1258  <para>Filters can be whitelist or blacklist</para>
1259  <para>Example whitelist filter: "Event: Newchannel"</para>
1260  <para>Example blacklist filter: "!Channel: DAHDI.*"</para>
1261  <para>This filter option is used to whitelist or blacklist events per user to be
1262  reported with regular expressions and are allowed if both the regex matches
1263  and the user has read access as defined in manager.conf. Filters are assumed to be for whitelisting
1264  unless preceeded by an exclamation point, which marks it as being black.
1265  Evaluation of the filters is as follows:</para>
1266  <para>- If no filters are configured all events are reported as normal.</para>
1267  <para>- If there are white filters only: implied black all filter processed first, then white filters.</para>
1268  <para>- If there are black filters only: implied white all filter processed first, then black filters.</para>
1269  <para>- If there are both white and black filters: implied black all filter processed first, then white
1270  filters, and lastly black filters.</para>
1271  </parameter>
1272  </syntax>
1273  <description>
1274  <para>The filters added are only used for the current session.
1275  Once the connection is closed the filters are removed.</para>
1276  <para>This comand requires the system permission because
1277  this command can be used to create filters that may bypass
1278  filters defined in manager.conf</para>
1279  </description>
1280  <see-also>
1281  <ref type="manager">FilterList</ref>
1282  </see-also>
1283  </manager>
1284  <manager name="FilterList" language="en_US">
1285  <synopsis>
1286  Show current event filters for this session
1287  </synopsis>
1288  <description>
1289  <para>The filters displayed are for the current session. Only those filters defined in
1290  manager.conf will be present upon starting a new session.</para>
1291  </description>
1292  <see-also>
1293  <ref type="manager">Filter</ref>
1294  </see-also>
1295  </manager>
1296  <manager name="BlindTransfer" language="en_US">
1297  <synopsis>
1298  Blind transfer channel(s) to the given destination
1299  </synopsis>
1300  <syntax>
1301  <parameter name="Channel" required="true">
1302  </parameter>
1303  <parameter name="Context">
1304  </parameter>
1305  <parameter name="Exten">
1306  </parameter>
1307  </syntax>
1308  <description>
1309  <para>Redirect all channels currently bridged to the specified channel to the specified destination.</para>
1310  </description>
1311  <see-also>
1312  <ref type="manager">Redirect</ref>
1313  <ref type="managerEvent">BlindTransfer</ref>
1314  </see-also>
1315  </manager>
1316  <managerEvent name="ExtensionStatus" language="en_US">
1317  <managerEventInstance class="EVENT_FLAG_CALL">
1318  <synopsis>Raised when a hint changes due to a device state change.</synopsis>
1319  <syntax>
1320  <parameter name="Exten">
1321  <para>Name of the extension.</para>
1322  </parameter>
1323  <parameter name="Context">
1324  <para>Context that owns the extension.</para>
1325  </parameter>
1326  <parameter name="Hint">
1327  <para>Hint set for the extension</para>
1328  </parameter>
1329  <parameter name="Status">
1330  <para>Numerical value of the extension status. Extension
1331  status is determined by the combined device state of all items
1332  contained in the hint.</para>
1333  <enumlist>
1334  <enum name="-2">
1335  <para>The extension was removed from the dialplan.</para>
1336  </enum>
1337  <enum name="-1">
1338  <para>The extension's hint was removed from the dialplan.</para>
1339  </enum>
1340  <enum name="0">
1341  <para><literal>Idle</literal> - Related device(s) are in an idle
1342  state.</para>
1343  </enum>
1344  <enum name="1">
1345  <para><literal>InUse</literal> - Related device(s) are in active
1346  calls but may take more calls.</para>
1347  </enum>
1348  <enum name="2">
1349  <para><literal>Busy</literal> - Related device(s) are in active
1350  calls and may not take any more calls.</para>
1351  </enum>
1352  <enum name="4">
1353  <para><literal>Unavailable</literal> - Related device(s) are
1354  not reachable.</para>
1355  </enum>
1356  <enum name="8">
1357  <para><literal>Ringing</literal> - Related device(s) are
1358  currently ringing.</para>
1359  </enum>
1360  <enum name="9">
1361  <para><literal>InUse&amp;Ringing</literal> - Related device(s)
1362  are currently ringing and in active calls.</para>
1363  </enum>
1364  <enum name="16">
1365  <para><literal>Hold</literal> - Related device(s) are
1366  currently on hold.</para>
1367  </enum>
1368  <enum name="17">
1369  <para><literal>InUse&amp;Hold</literal> - Related device(s)
1370  are currently on hold and in active calls.</para>
1371  </enum>
1372  </enumlist>
1373  </parameter>
1374  <parameter name="StatusText">
1375  <para>Text representation of <literal>Status</literal>.</para>
1376  <enumlist>
1377  <enum name="Idle" />
1378  <enum name="InUse" />
1379  <enum name="Busy" />
1380  <enum name="Unavailable" />
1381  <enum name="Ringing" />
1382  <enum name="InUse&amp;Ringing" />
1383  <enum name="Hold" />
1384  <enum name="InUse&amp;Hold" />
1385  <enum name="Unknown">
1386  <para>Status does not match any of the above values.</para>
1387  </enum>
1388  </enumlist>
1389  </parameter>
1390  </syntax>
1391  <see-also>
1392  <ref type="manager">ExtensionState</ref>
1393  </see-also>
1394  </managerEventInstance>
1395  </managerEvent>
1396  <managerEvent name="PresenceStatus" language="en_US">
1397  <managerEventInstance class="EVENT_FLAG_CALL">
1398  <synopsis>Raised when a hint changes due to a presence state change.</synopsis>
1399  <syntax>
1400  <parameter name="Exten" />
1401  <parameter name="Context" />
1402  <parameter name="Hint" />
1403  <parameter name="Status" />
1404  <parameter name="Subtype" />
1405  <parameter name="Message" />
1406  </syntax>
1407  <see-also>
1408  <ref type="manager">PresenceState</ref>
1409  </see-also>
1410  </managerEventInstance>
1411  </managerEvent>
1412  ***/
1413 
1414 /*! \addtogroup Group_AMI AMI functions
1415 */
1416 /*! @{
1417  Doxygen group */
1418 
1432 };
1433 
1438 };
1439 
1440 /*!
1441  * Linked list of events.
1442  * Global events are appended to the list by append_event().
1443  * The usecount is the number of stored pointers to the element,
1444  * excluding the list pointers. So an element that is only in
1445  * the list has a usecount of 0, not 1.
1446  *
1447  * Clients have a pointer to the last event processed, and for each
1448  * of these clients we track the usecount of the elements.
1449  * If we have a pointer to an entry in the list, it is safe to navigate
1450  * it forward because elements will not be deleted, but only appended.
1451  * The worst that can happen is seeing the pointer still NULL.
1452  *
1453  * When the usecount of an element drops to 0, and the element is the
1454  * first in the list, we can remove it. Removal is done within the
1455  * main thread, which is woken up for the purpose.
1456  *
1457  * For simplicity of implementation, we make sure the list is never empty.
1458  */
1459 struct eventqent {
1460  int usecount; /*!< # of clients who still need the event */
1462  unsigned int seq; /*!< sequence number */
1463  struct timeval tv; /*!< When event was allocated */
1464  AST_RWLIST_ENTRY(eventqent) eq_next;
1465  char eventdata[1]; /*!< really variable size, allocated by append_event() */
1466 };
1467 
1469 
1470 static int displayconnects = 1;
1471 static int allowmultiplelogin = 1;
1472 static int timestampevents;
1473 static int httptimeout = 60;
1474 static int broken_events_action = 0;
1475 static int manager_enabled = 0;
1476 static int subscribed = 0;
1477 static int webmanager_enabled = 0;
1478 static int manager_debug = 0; /*!< enable some debugging code in the manager */
1479 static int authtimeout;
1480 static int authlimit;
1481 static char *manager_channelvars;
1482 
1483 #define DEFAULT_REALM "asterisk"
1484 static char global_realm[MAXHOSTNAMELEN]; /*!< Default realm */
1485 
1486 static int unauth_sessions = 0;
1488 
1489 /*! \brief A \ref stasis_topic that all topics AMI cares about will be forwarded to */
1491 
1492 /*! \brief The \ref stasis_message_router for all \ref stasis messages */
1494 
1495 /*! \brief The \ref stasis_subscription for forwarding the RTP topic to the AMI topic */
1497 
1498 /*! \brief The \ref stasis_subscription for forwarding the Security topic to the AMI topic */
1500 
1501 #ifdef TEST_FRAMEWORK
1502 /*! \brief The \ref stasis_subscription for forwarding the Test topic to the AMI topic */
1504 #endif
1505 
1506 #define MGR_SHOW_TERMINAL_WIDTH 80
1507 
1508 #define MAX_VARS 128
1509 
1510 /*! \brief Fake event class used to end sessions at shutdown */
1511 #define EVENT_FLAG_SHUTDOWN -1
1512 
1513 /*! \brief
1514  * Descriptor for a manager session, either on the AMI socket or over HTTP.
1515  *
1516  * \note
1517  * AMI session have managerid == 0; the entry is created upon a connect,
1518  * and destroyed with the socket.
1519  * HTTP sessions have managerid != 0, the value is used as a search key
1520  * to lookup sessions (using the mansession_id cookie, or nonce key from
1521  * Digest Authentication http header).
1522  */
1523 #define MAX_BLACKLIST_CMD_LEN 2
1524 static const struct {
1525  const char *words[AST_MAX_CMD_LEN];
1526 } command_blacklist[] = {
1527  {{ "module", "load", NULL }},
1528  {{ "module", "unload", NULL }},
1529  {{ "restart", "gracefully", NULL }},
1530 };
1531 
1532 static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
1533 
1535 {
1536  if (!acl_change_sub) {
1537  acl_change_sub = stasis_subscribe(ast_security_topic(),
1541  }
1542 }
1543 
1545 {
1546  acl_change_sub = stasis_unsubscribe_and_join(acl_change_sub);
1547 }
1548 
1549 /* In order to understand what the heck is going on with the
1550  * mansession_session and mansession structs, we need to have a bit of a history
1551  * lesson.
1552  *
1553  * In the beginning, there was the mansession. The mansession contained data that was
1554  * intrinsic to a manager session, such as the time that it started, the name of the logged-in
1555  * user, etc. In addition to these parameters were the f and fd parameters. For typical manager
1556  * sessions, these were used to represent the TCP socket over which the AMI session was taking
1557  * place. It makes perfect sense for these fields to be a part of the session-specific data since
1558  * the session actually defines this information.
1559  *
1560  * Then came the HTTP AMI sessions. With these, the f and fd fields need to be opened and closed
1561  * for every single action that occurs. Thus the f and fd fields aren't really specific to the session
1562  * but rather to the action that is being executed. Because a single session may execute many commands
1563  * at once, some sort of safety needed to be added in order to be sure that we did not end up with fd
1564  * leaks from one action overwriting the f and fd fields used by a previous action before the previous action
1565  * has had a chance to properly close its handles.
1566  *
1567  * The initial idea to solve this was to use thread synchronization, but this prevented multiple actions
1568  * from being run at the same time in a single session. Some manager actions may block for a long time, thus
1569  * creating a large queue of actions to execute. In addition, this fix did not address the basic architectural
1570  * issue that for HTTP manager sessions, the f and fd variables are not really a part of the session, but are
1571  * part of the action instead.
1572  *
1573  * The new idea was to create a structure on the stack for each HTTP Manager action. This structure would
1574  * contain the action-specific information, such as which file to write to. In order to maintain expectations
1575  * of action handlers and not have to change the public API of the manager code, we would need to name this
1576  * new stacked structure 'mansession' and contain within it the old mansession struct that we used to use.
1577  * We renamed the old mansession struct 'mansession_session' to hopefully convey that what is in this structure
1578  * is session-specific data. The structure that it is wrapped in, called a 'mansession' really contains action-specific
1579  * data.
1580  */
1582  /*! \todo XXX need to document which fields it is protecting */
1583  struct ast_sockaddr addr; /*!< address we are connecting from */
1584  struct ast_iostream *stream; /*!< AMI stream */
1585  int inuse; /*!< number of HTTP sessions using this entry */
1586  int needdestroy; /*!< Whether an HTTP session should be destroyed */
1587  pthread_t waiting_thread; /*!< Sleeping thread using this descriptor */
1588  uint32_t managerid; /*!< Unique manager identifier, 0 for AMI sessions */
1589  time_t sessionstart; /*!< Session start time */
1590  struct timeval sessionstart_tv; /*!< Session start time */
1591  time_t sessiontimeout; /*!< Session timeout if HTTP */
1592  char username[80]; /*!< Logged in username */
1593  char challenge[10]; /*!< Authentication challenge */
1594  int authenticated; /*!< Authentication status */
1595  int readperm; /*!< Authorization for reading */
1596  int writeperm; /*!< Authorization for writing */
1597  char inbuf[1025]; /*!< Buffer - we use the extra byte to add a '\\0' and simplify parsing */
1598  int inlen; /*!< number of buffered bytes */
1599  struct ao2_container *whitefilters; /*!< Manager event filters - white list */
1600  struct ao2_container *blackfilters; /*!< Manager event filters - black list */
1601  struct ast_variable *chanvars; /*!< Channel variables to set for originate */
1602  int send_events; /*!< XXX what ? */
1603  struct eventqent *last_ev; /*!< last event processed. */
1604  int writetimeout; /*!< Timeout for ast_carefulwrite() */
1605  time_t authstart;
1606  int pending_event; /*!< Pending events indicator in case when waiting_thread is NULL */
1607  time_t noncetime; /*!< Timer for nonce value expiration */
1608  unsigned long oldnonce; /*!< Stale nonce value */
1609  unsigned long nc; /*!< incremental nonce counter */
1610  ast_mutex_t notify_lock; /*!< Lock for notifying this session of events */
1611  AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore) datastores; /*!< Data stores on the session */
1613 };
1614 
1618 };
1619 
1620 /*! \brief In case you didn't read that giant block of text above the mansession_session struct, the
1621  * \ref struct mansession is named this solely to keep the API the same in Asterisk. This structure really
1622  * represents data that is different from Manager action to Manager action. The mansession_session pointer
1623  * contained within points to session-specific data.
1624  */
1625 struct mansession {
1630  unsigned int write_error:1;
1633 };
1634 
1635 /*! Active manager connection sessions container. */
1636 static AO2_GLOBAL_OBJ_STATIC(mgr_sessions);
1637 
1638 /*! \brief user descriptor, as read from the config file.
1639  *
1640  * \note It is still missing some fields -- e.g. we can have multiple permit and deny
1641  * lines which are not supported here, and readperm/writeperm/writetimeout
1642  * are not stored.
1643  */
1645  char username[80];
1646  char *secret; /*!< Secret for logging in */
1647  int readperm; /*!< Authorization for reading */
1648  int writeperm; /*!< Authorization for writing */
1649  int writetimeout; /*!< Per user Timeout for ast_carefulwrite() */
1650  int displayconnects; /*!< XXX unused */
1651  int allowmultiplelogin; /*!< Per user option*/
1652  int keep; /*!< mark entries created on a reload */
1653  struct ao2_container *whitefilters; /*!< Manager event filters - white list */
1654  struct ao2_container *blackfilters; /*!< Manager event filters - black list */
1655  struct ast_acl_list *acl; /*!< ACL setting */
1656  char *a1_hash; /*!< precalculated A1 for Digest auth */
1657  struct ast_variable *chanvars; /*!< Channel variables to set for originate */
1659 };
1660 
1661 /*! \brief list of users found in the config file */
1663 
1664 /*! \brief list of actions registered */
1666 
1667 /*! \brief list of hooks registered */
1669 
1670 #ifdef AST_XML_DOCS
1671 /*! \brief A container of event documentation nodes */
1672 static AO2_GLOBAL_OBJ_STATIC(event_docs);
1673 #endif
1674 
1675 static int __attribute__((format(printf, 9, 0))) __manager_event_sessions(
1676  struct ao2_container *sessions,
1677  int category,
1678  const char *event,
1679  int chancount,
1680  struct ast_channel **chans,
1681  const char *file,
1682  int line,
1683  const char *func,
1684  const char *fmt,
1685  ...);
1686 static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters);
1687 
1688 static int match_filter(struct mansession *s, char *eventdata);
1689 
1690 /*!
1691  * @{ \brief Define AMI message types.
1692  */
1694 /*! @} */
1695 
1696 /*!
1697  * \internal
1698  * \brief Find a registered action object.
1699  *
1700  * \param name Name of AMI action to find.
1701  *
1702  * \return Reffed action found or NULL
1703  */
1704 static struct manager_action *action_find(const char *name)
1705 {
1706  struct manager_action *act;
1707 
1709  AST_RWLIST_TRAVERSE(&actions, act, list) {
1710  if (!strcasecmp(name, act->action)) {
1711  ao2_t_ref(act, +1, "found action object");
1712  break;
1713  }
1714  }
1716 
1717  return act;
1718 }
1719 
1721 {
1722  return manager_topic;
1723 }
1724 
1726 {
1727  return stasis_router;
1728 }
1729 
1730 static void manager_json_value_str_append(struct ast_json *value, const char *key,
1731  struct ast_str **res)
1732 {
1733  switch (ast_json_typeof(value)) {
1734  case AST_JSON_STRING:
1735  ast_str_append(res, 0, "%s: %s\r\n", key, ast_json_string_get(value));
1736  break;
1737  case AST_JSON_INTEGER:
1738  ast_str_append(res, 0, "%s: %jd\r\n", key, ast_json_integer_get(value));
1739  break;
1740  case AST_JSON_TRUE:
1741  ast_str_append(res, 0, "%s: True\r\n", key);
1742  break;
1743  case AST_JSON_FALSE:
1744  ast_str_append(res, 0, "%s: False\r\n", key);
1745  break;
1746  default:
1747  ast_str_append(res, 0, "%s: \r\n", key);
1748  break;
1749  }
1750 }
1751 
1752 static void manager_json_to_ast_str(struct ast_json *obj, const char *key,
1753  struct ast_str **res, key_exclusion_cb exclusion_cb);
1754 
1755 static void manager_json_array_with_key(struct ast_json *obj, const char* key,
1756  size_t index, struct ast_str **res,
1757  key_exclusion_cb exclusion_cb)
1758 {
1759  struct ast_str *key_str = ast_str_alloca(64);
1760  ast_str_set(&key_str, 0, "%s(%zu)", key, index);
1762  res, exclusion_cb);
1763 }
1764 
1765 static void manager_json_obj_with_key(struct ast_json *obj, const char* key,
1766  const char *parent_key, struct ast_str **res,
1767  key_exclusion_cb exclusion_cb)
1768 {
1769  if (parent_key) {
1770  struct ast_str *key_str = ast_str_alloca(64);
1771  ast_str_set(&key_str, 0, "%s/%s", parent_key, key);
1773  res, exclusion_cb);
1774  return;
1775  }
1776 
1777  manager_json_to_ast_str(obj, key, res, exclusion_cb);
1778 }
1779 
1780 void manager_json_to_ast_str(struct ast_json *obj, const char *key,
1781  struct ast_str **res, key_exclusion_cb exclusion_cb)
1782 {
1783  struct ast_json_iter *i;
1784 
1785  /* If obj or res is not given, just return */
1786  if (!obj || !res) {
1787  return;
1788  }
1789 
1790  if (!*res && !(*res = ast_str_create(1024))) {
1791  return;
1792  }
1793 
1794  if (exclusion_cb && key && exclusion_cb(key)) {
1795  return;
1796  }
1797 
1798  if (ast_json_typeof(obj) != AST_JSON_OBJECT &&
1799  ast_json_typeof(obj) != AST_JSON_ARRAY) {
1800  manager_json_value_str_append(obj, key, res);
1801  return;
1802  }
1803 
1804  if (ast_json_typeof(obj) == AST_JSON_ARRAY) {
1805  size_t j;
1806  for (j = 0; j < ast_json_array_size(obj); ++j) {
1808  key, j, res, exclusion_cb);
1809  }
1810  return;
1811  }
1812 
1813  for (i = ast_json_object_iter(obj); i;
1814  i = ast_json_object_iter_next(obj, i)) {
1817  key, res, exclusion_cb);
1818  }
1819 }
1820 
1822 {
1823  struct ast_str *res = ast_str_create(1024);
1824 
1825  if (!ast_json_is_null(blob)) {
1826  manager_json_to_ast_str(blob, NULL, &res, exclusion_cb);
1827  }
1828 
1829  return res;
1830 }
1831 
1832 #define manager_event_sessions(sessions, category, event, contents , ...) \
1833  __manager_event_sessions(sessions, category, event, 0, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, contents , ## __VA_ARGS__)
1834 
1835 #define any_manager_listeners(sessions) \
1836  ((sessions && ao2_container_count(sessions)) || !AST_RWLIST_EMPTY(&manager_hooks))
1837 
1838 static void manager_default_msg_cb(void *data, struct stasis_subscription *sub,
1839  struct stasis_message *message)
1840 {
1841  struct ao2_container *sessions;
1842  struct ast_manager_event_blob *ev;
1843 
1844  if (!stasis_message_can_be_ami(message)) {
1845  /* Not an AMI message; disregard */
1846  return;
1847  }
1848 
1849  sessions = ao2_global_obj_ref(mgr_sessions);
1850  if (!any_manager_listeners(sessions)) {
1851  /* Nobody is listening */
1852  ao2_cleanup(sessions);
1853  return;
1854  }
1855 
1856  ev = stasis_message_to_ami(message);
1857  if (!ev) {
1858  /* Conversion failure */
1859  ao2_cleanup(sessions);
1860  return;
1861  }
1862 
1864  "%s", ev->extra_fields);
1865  ao2_ref(ev, -1);
1866  ao2_cleanup(sessions);
1867 }
1868 
1869 static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub,
1870  struct stasis_message *message)
1871 {
1872  struct ast_json_payload *payload;
1873  int class_type;
1874  const char *type;
1875  struct ast_json *event;
1876  struct ast_str *event_buffer;
1877  struct ao2_container *sessions;
1878 
1879  sessions = ao2_global_obj_ref(mgr_sessions);
1880  if (!any_manager_listeners(sessions)) {
1881  /* Nobody is listening */
1882  ao2_cleanup(sessions);
1883  return;
1884  }
1885 
1886  payload = stasis_message_data(message);
1887  class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type"));
1888  type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
1889  event = ast_json_object_get(payload->json, "event");
1890 
1891  event_buffer = ast_manager_str_from_json_object(event, NULL);
1892  if (!event_buffer) {
1893  ast_log(AST_LOG_WARNING, "Error while creating payload for event %s\n", type);
1894  ao2_cleanup(sessions);
1895  return;
1896  }
1897  manager_event_sessions(sessions, class_type, type,
1898  "%s", ast_str_buffer(event_buffer));
1899  ast_free(event_buffer);
1900  ao2_cleanup(sessions);
1901 }
1902 
1903 void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
1904 {
1905  RAII_VAR(struct ast_json *, event_info, NULL, ast_json_unref);
1906  RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
1907  RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
1908 
1909  if (!obj || !ast_manager_get_generic_type()) {
1910  return;
1911  }
1912 
1913  ast_json_ref(obj);
1914  event_info = ast_json_pack("{s: s, s: i, s: o}",
1915  "type", type,
1916  "class_type", class_type,
1917  "event", obj);
1918  if (!event_info) {
1919  return;
1920  }
1921 
1922  payload = ast_json_payload_create(event_info);
1923  if (!payload) {
1924  return;
1925  }
1927  if (!message) {
1928  return;
1929  }
1931 }
1932 
1933 /*! \brief Add a custom hook to be called when an event is fired */
1935 {
1937  AST_RWLIST_INSERT_TAIL(&manager_hooks, hook, list);
1939 }
1940 
1941 /*! \brief Delete a custom hook to be called when an event is fired */
1943 {
1945  AST_RWLIST_REMOVE(&manager_hooks, hook, list);
1947 }
1948 
1950 {
1951  return manager_enabled;
1952 }
1953 
1955 {
1956  return (webmanager_enabled && manager_enabled);
1957 }
1958 
1959 /*!
1960  * Grab a reference to the last event, update usecount as needed.
1961  * Can handle a NULL pointer.
1962  */
1963 static struct eventqent *grab_last(void)
1964 {
1965  struct eventqent *ret;
1966 
1968  ret = AST_RWLIST_LAST(&all_events);
1969  /* the list is never empty now, but may become so when
1970  * we optimize it in the future, so be prepared.
1971  */
1972  if (ret) {
1974  }
1976  return ret;
1977 }
1978 
1979 /*!
1980  * Purge unused events. Remove elements from the head
1981  * as long as their usecount is 0 and there is a next element.
1982  */
1983 static void purge_events(void)
1984 {
1985  struct eventqent *ev;
1986  struct timeval now = ast_tvnow();
1987 
1989  while ( (ev = AST_RWLIST_FIRST(&all_events)) &&
1990  ev->usecount == 0 && AST_RWLIST_NEXT(ev, eq_next)) {
1992  ast_free(ev);
1993  }
1994 
1996  /* Never release the last event */
1997  if (!AST_RWLIST_NEXT(ev, eq_next)) {
1998  break;
1999  }
2000 
2001  /* 2.5 times whatever the HTTP timeout is (maximum 2.5 hours) is the maximum time that we will definitely cache an event */
2002  if (ev->usecount == 0 && ast_tvdiff_sec(now, ev->tv) > (httptimeout > 3600 ? 3600 : httptimeout) * 2.5) {
2003  AST_RWLIST_REMOVE_CURRENT(eq_next);
2004  ast_free(ev);
2005  }
2006  }
2009 }
2010 
2011 /*!
2012  * helper functions to convert back and forth between
2013  * string and numeric representation of set of flags
2014  */
2015 static const struct permalias {
2016  int num;
2017  const char *label;
2018 } perms[] = {
2019  { EVENT_FLAG_SYSTEM, "system" },
2020  { EVENT_FLAG_CALL, "call" },
2021  { EVENT_FLAG_LOG, "log" },
2022  { EVENT_FLAG_VERBOSE, "verbose" },
2023  { EVENT_FLAG_COMMAND, "command" },
2024  { EVENT_FLAG_AGENT, "agent" },
2025  { EVENT_FLAG_USER, "user" },
2026  { EVENT_FLAG_CONFIG, "config" },
2027  { EVENT_FLAG_DTMF, "dtmf" },
2028  { EVENT_FLAG_REPORTING, "reporting" },
2029  { EVENT_FLAG_CDR, "cdr" },
2030  { EVENT_FLAG_DIALPLAN, "dialplan" },
2031  { EVENT_FLAG_ORIGINATE, "originate" },
2032  { EVENT_FLAG_AGI, "agi" },
2033  { EVENT_FLAG_CC, "cc" },
2034  { EVENT_FLAG_AOC, "aoc" },
2035  { EVENT_FLAG_TEST, "test" },
2036  { EVENT_FLAG_SECURITY, "security" },
2037  { EVENT_FLAG_MESSAGE, "message" },
2038  { INT_MAX, "all" },
2039  { 0, "none" },
2040 };
2041 
2042 /*! Maximum string length of the AMI authority permission string buildable from perms[]. */
2043 #define MAX_AUTH_PERM_STRING 150
2044 
2045 /*! \brief Checks to see if a string which can be used to evaluate functions should be rejected */
2046 static int function_capable_string_allowed_with_auths(const char *evaluating, int writepermlist)
2047 {
2048  if (!(writepermlist & EVENT_FLAG_SYSTEM)
2049  && (
2050  strstr(evaluating, "SHELL") || /* NoOp(${SHELL(rm -rf /)}) */
2051  strstr(evaluating, "EVAL") /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
2052  )) {
2053  return 0;
2054  }
2055  return 1;
2056 }
2057 
2058 /*! \brief Convert authority code to a list of options for a user. This will only
2059  * display those authority codes that have an explicit match on authority */
2060 static const char *user_authority_to_str(int authority, struct ast_str **res)
2061 {
2062  int i;
2063  char *sep = "";
2064 
2065  ast_str_reset(*res);
2066  for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
2067  if ((authority & perms[i].num) == perms[i].num) {
2068  ast_str_append(res, 0, "%s%s", sep, perms[i].label);
2069  sep = ",";
2070  }
2071  }
2072 
2073  if (ast_str_strlen(*res) == 0) {
2074  /* replace empty string with something sensible */
2075  ast_str_append(res, 0, "<none>");
2076  }
2077 
2078  return ast_str_buffer(*res);
2079 }
2080 
2081 
2082 /*! \brief Convert authority code to a list of options. Note that the EVENT_FLAG_ALL
2083  * authority will always be returned. */
2084 static const char *authority_to_str(int authority, struct ast_str **res)
2085 {
2086  int i;
2087  char *sep = "";
2088 
2089  ast_str_reset(*res);
2090  if (authority != EVENT_FLAG_SHUTDOWN) {
2091  for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
2092  if (authority & perms[i].num) {
2093  ast_str_append(res, 0, "%s%s", sep, perms[i].label);
2094  sep = ",";
2095  }
2096  }
2097  }
2098 
2099  if (ast_str_strlen(*res) == 0) {
2100  /* replace empty string with something sensible */
2101  ast_str_append(res, 0, "<none>");
2102  }
2103 
2104  return ast_str_buffer(*res);
2105 }
2106 
2107 /*! Tells you if smallstr exists inside bigstr
2108  which is delim by delim and uses no buf or stringsep
2109  ast_instring("this|that|more","this",'|') == 1;
2110 
2111  feel free to move this to app.c -anthm */
2112 static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
2113 {
2114  const char *val = bigstr, *next;
2115 
2116  do {
2117  if ((next = strchr(val, delim))) {
2118  if (!strncmp(val, smallstr, (next - val))) {
2119  return 1;
2120  } else {
2121  continue;
2122  }
2123  } else {
2124  return !strcmp(smallstr, val);
2125  }
2126  } while (*(val = (next + 1)));
2127 
2128  return 0;
2129 }
2130 
2131 static int get_perm(const char *instr)
2132 {
2133  int x = 0, ret = 0;
2134 
2135  if (!instr) {
2136  return 0;
2137  }
2138 
2139  for (x = 0; x < ARRAY_LEN(perms); x++) {
2140  if (ast_instring(instr, perms[x].label, ',')) {
2141  ret |= perms[x].num;
2142  }
2143  }
2144 
2145  return ret;
2146 }
2147 
2148 /*!
2149  * A number returns itself, false returns 0, true returns all flags,
2150  * other strings return the flags that are set.
2151  */
2152 static int strings_to_mask(const char *string)
2153 {
2154  const char *p;
2155 
2156  if (ast_strlen_zero(string)) {
2157  return -1;
2158  }
2159 
2160  for (p = string; *p; p++) {
2161  if (*p < '0' || *p > '9') {
2162  break;
2163  }
2164  }
2165  if (!*p) { /* all digits */
2166  return atoi(string);
2167  }
2168  if (ast_false(string)) {
2169  return 0;
2170  }
2171  if (ast_true(string)) { /* all permissions */
2172  int x, ret = 0;
2173  for (x = 0; x < ARRAY_LEN(perms); x++) {
2174  ret |= perms[x].num;
2175  }
2176  return ret;
2177  }
2178  return get_perm(string);
2179 }
2180 
2181 /*! \brief Unreference manager session object.
2182  If no more references, then go ahead and delete it */
2184 {
2185  int refcount = ao2_ref(s, -1);
2186  if (manager_debug) {
2187  ast_debug(1, "Mansession: %p refcount now %d\n", s, refcount - 1);
2188  }
2189  return NULL;
2190 }
2191 
2192 static void event_filter_destructor(void *obj)
2193 {
2194  regex_t *regex_filter = obj;
2195  regfree(regex_filter);
2196 }
2197 
2198 static void session_destructor(void *obj)
2199 {
2200  struct mansession_session *session = obj;
2201  struct eventqent *eqe = session->last_ev;
2202  struct ast_datastore *datastore;
2203 
2204  /* Get rid of each of the data stores on the session */
2205  while ((datastore = AST_LIST_REMOVE_HEAD(&session->datastores, entry))) {
2206  /* Free the data store */
2207  ast_datastore_free(datastore);
2208  }
2209 
2210  if (eqe) {
2211  ast_atomic_fetchadd_int(&eqe->usecount, -1);
2212  }
2213  if (session->chanvars) {
2214  ast_variables_destroy(session->chanvars);
2215  }
2216 
2217  if (session->whitefilters) {
2218  ao2_t_ref(session->whitefilters, -1, "decrement ref for white container, should be last one");
2219  }
2220 
2221  if (session->blackfilters) {
2222  ao2_t_ref(session->blackfilters, -1, "decrement ref for black container, should be last one");
2223  }
2224 
2225  ast_mutex_destroy(&session->notify_lock);
2226 }
2227 
2228 /*! \brief Allocate manager session structure and add it to the list of sessions */
2230 {
2231  struct ao2_container *sessions;
2232  struct mansession_session *newsession;
2233 
2234  newsession = ao2_alloc(sizeof(*newsession), session_destructor);
2235  if (!newsession) {
2236  return NULL;
2237  }
2238 
2241  if (!newsession->whitefilters || !newsession->blackfilters) {
2242  ao2_ref(newsession, -1);
2243  return NULL;
2244  }
2245 
2246  newsession->waiting_thread = AST_PTHREADT_NULL;
2247  newsession->writetimeout = 100;
2248  newsession->send_events = -1;
2249  ast_sockaddr_copy(&newsession->addr, addr);
2250 
2251  ast_mutex_init(&newsession->notify_lock);
2252 
2253  sessions = ao2_global_obj_ref(mgr_sessions);
2254  if (sessions) {
2255  ao2_link(sessions, newsession);
2256  ao2_ref(sessions, -1);
2257  }
2258 
2259  return newsession;
2260 }
2261 
2262 static int mansession_cmp_fn(void *obj, void *arg, int flags)
2263 {
2264  struct mansession_session *s = obj;
2265  char *str = arg;
2266  return !strcasecmp(s->username, str) ? CMP_MATCH : 0;
2267 }
2268 
2269 static void session_destroy(struct mansession_session *s)
2270 {
2271  struct ao2_container *sessions;
2272 
2273  sessions = ao2_global_obj_ref(mgr_sessions);
2274  if (sessions) {
2275  ao2_unlink(sessions, s);
2276  ao2_ref(sessions, -1);
2277  }
2278  unref_mansession(s);
2279 }
2280 
2281 
2282 static int check_manager_session_inuse(const char *name)
2283 {
2284  struct ao2_container *sessions;
2285  struct mansession_session *session;
2286  int inuse = 0;
2287 
2288  sessions = ao2_global_obj_ref(mgr_sessions);
2289  if (sessions) {
2290  session = ao2_find(sessions, (char *) name, 0);
2291  ao2_ref(sessions, -1);
2292  if (session) {
2293  unref_mansession(session);
2294  inuse = 1;
2295  }
2296  }
2297  return inuse;
2298 }
2299 
2300 
2301 /*!
2302  * lookup an entry in the list of registered users.
2303  * must be called with the list lock held.
2304  */
2306 {
2307  struct ast_manager_user *user = NULL;
2308 
2309  AST_RWLIST_TRAVERSE(&users, user, list) {
2310  if (!strcasecmp(user->username, name)) {
2311  break;
2312  }
2313  }
2314 
2315  return user;
2316 }
2317 
2318 /*! \brief Get displayconnects config option.
2319  * \param session manager session to get parameter from.
2320  * \return displayconnects config option value.
2321  */
2323 {
2324  struct ast_manager_user *user = NULL;
2325  int ret = 0;
2326 
2328  if ((user = get_manager_by_name_locked(session->username))) {
2329  ret = user->displayconnects;
2330  }
2332 
2333  return ret;
2334 }
2335 
2336 #ifdef AST_XML_DOCS
2337 static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance);
2338 #endif
2339 
2340 static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2341 {
2342  struct manager_action *cur;
2343  struct ast_str *authority;
2344  int num;
2345  int l;
2346  const char *auth_str;
2347 #ifdef AST_XML_DOCS
2348  char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64];
2349  char arguments_title[64], privilege_title[64], final_response_title[64], list_responses_title[64];
2350 #endif
2351 
2352  switch (cmd) {
2353  case CLI_INIT:
2354  e->command = "manager show command";
2355  e->usage =
2356  "Usage: manager show command <actionname> [<actionname> [<actionname> [...]]]\n"
2357  " Shows the detailed description for a specific Asterisk manager interface command.\n";
2358  return NULL;
2359  case CLI_GENERATE:
2360  l = strlen(a->word);
2362  AST_RWLIST_TRAVERSE(&actions, cur, list) {
2363  if (!strncasecmp(a->word, cur->action, l)) {
2365  break;
2366  }
2367  }
2368  }
2370  return NULL;
2371  }
2372  if (a->argc < 4) {
2373  return CLI_SHOWUSAGE;
2374  }
2375 
2376  authority = ast_str_alloca(MAX_AUTH_PERM_STRING);
2377 
2378 #ifdef AST_XML_DOCS
2379  /* setup the titles */
2380  term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2381  term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
2382  term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
2383  term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
2384  term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
2385  term_color(privilege_title, "[Privilege]\n", COLOR_MAGENTA, 0, 40);
2386  term_color(final_response_title, "[Final Response]\n", COLOR_MAGENTA, 0, 40);
2387  term_color(list_responses_title, "[List Responses]\n", COLOR_MAGENTA, 0, 40);
2388 #endif
2389 
2391  AST_RWLIST_TRAVERSE(&actions, cur, list) {
2392  for (num = 3; num < a->argc; num++) {
2393  if (!strcasecmp(cur->action, a->argv[num])) {
2394  auth_str = authority_to_str(cur->authority, &authority);
2395 
2396 #ifdef AST_XML_DOCS
2397  if (cur->docsrc == AST_XML_DOC) {
2398  char *syntax = ast_xmldoc_printable(S_OR(cur->syntax, "Not available"), 1);
2399  char *synopsis = ast_xmldoc_printable(S_OR(cur->synopsis, "Not available"), 1);
2400  char *description = ast_xmldoc_printable(S_OR(cur->description, "Not available"), 1);
2401  char *arguments = ast_xmldoc_printable(S_OR(cur->arguments, "Not available"), 1);
2402  char *seealso = ast_xmldoc_printable(S_OR(cur->seealso, "Not available"), 1);
2403  char *privilege = ast_xmldoc_printable(S_OR(auth_str, "Not available"), 1);
2404  char *responses = ast_xmldoc_printable("None", 1);
2405 
2406  if (!syntax || !synopsis || !description || !arguments
2407  || !seealso || !privilege || !responses) {
2408  ast_free(syntax);
2409  ast_free(synopsis);
2410  ast_free(description);
2411  ast_free(arguments);
2412  ast_free(seealso);
2413  ast_free(privilege);
2414  ast_free(responses);
2415  ast_cli(a->fd, "Allocation failure.\n");
2417 
2418  return CLI_FAILURE;
2419  }
2420 
2421  ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s",
2422  syntax_title, syntax,
2423  synopsis_title, synopsis,
2424  description_title, description,
2425  arguments_title, arguments,
2426  seealso_title, seealso,
2427  privilege_title, privilege,
2428  list_responses_title);
2429 
2430  if (!cur->list_responses) {
2431  ast_cli(a->fd, "%s\n\n", responses);
2432  } else {
2433  struct ast_xml_doc_item *temp;
2434  for (temp = cur->list_responses; temp; temp = AST_LIST_NEXT(temp, next)) {
2435  ast_cli(a->fd, "Event: %s\n", temp->name);
2436  print_event_instance(a, temp);
2437  }
2438  }
2439 
2440  ast_cli(a->fd, "%s", final_response_title);
2441 
2442  if (!cur->final_response) {
2443  ast_cli(a->fd, "%s\n\n", responses);
2444  } else {
2445  ast_cli(a->fd, "Event: %s\n", cur->final_response->name);
2447  }
2448 
2449  ast_free(syntax);
2450  ast_free(synopsis);
2451  ast_free(description);
2452  ast_free(arguments);
2453  ast_free(seealso);
2454  ast_free(privilege);
2455  ast_free(responses);
2456  } else
2457 #endif
2458  {
2459  ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
2460  cur->action, cur->synopsis,
2461  auth_str,
2462  S_OR(cur->description, ""));
2463  }
2464  }
2465  }
2466  }
2468 
2469  return CLI_SUCCESS;
2470 }
2471 
2472 static char *handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2473 {
2474  switch (cmd) {
2475  case CLI_INIT:
2476  e->command = "manager set debug [on|off]";
2477  e->usage = "Usage: manager set debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
2478  return NULL;
2479  case CLI_GENERATE:
2480  return NULL;
2481  }
2482 
2483  if (a->argc == 3) {
2484  ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
2485  } else if (a->argc == 4) {
2486  if (!strcasecmp(a->argv[3], "on")) {
2487  manager_debug = 1;
2488  } else if (!strcasecmp(a->argv[3], "off")) {
2489  manager_debug = 0;
2490  } else {
2491  return CLI_SHOWUSAGE;
2492  }
2493  }
2494  return CLI_SUCCESS;
2495 }
2496 
2497 static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2498 {
2499  struct ast_manager_user *user = NULL;
2500  int l;
2501  struct ast_str *rauthority = ast_str_alloca(MAX_AUTH_PERM_STRING);
2502  struct ast_str *wauthority = ast_str_alloca(MAX_AUTH_PERM_STRING);
2503  struct ast_variable *v;
2504 
2505  switch (cmd) {
2506  case CLI_INIT:
2507  e->command = "manager show user";
2508  e->usage =
2509  " Usage: manager show user <user>\n"
2510  " Display all information related to the manager user specified.\n";
2511  return NULL;
2512  case CLI_GENERATE:
2513  l = strlen(a->word);
2514  if (a->pos != 3) {
2515  return NULL;
2516  }
2518  AST_RWLIST_TRAVERSE(&users, user, list) {
2519  if (!strncasecmp(a->word, user->username, l)) {
2521  break;
2522  }
2523  }
2524  }
2526  return NULL;
2527  }
2528 
2529  if (a->argc != 4) {
2530  return CLI_SHOWUSAGE;
2531  }
2532 
2534 
2535  if (!(user = get_manager_by_name_locked(a->argv[3]))) {
2536  ast_cli(a->fd, "There is no manager called %s\n", a->argv[3]);
2538  return CLI_SUCCESS;
2539  }
2540 
2541  ast_cli(a->fd, "\n");
2542  ast_cli(a->fd,
2543  " username: %s\n"
2544  " secret: %s\n"
2545  " ACL: %s\n"
2546  " read perm: %s\n"
2547  " write perm: %s\n"
2548  " displayconnects: %s\n"
2549  "allowmultiplelogin: %s\n",
2550  S_OR(user->username, "(N/A)"),
2551  (user->secret ? "<Set>" : "(N/A)"),
2552  ((user->acl && !ast_acl_list_is_empty(user->acl)) ? "yes" : "no"),
2553  user_authority_to_str(user->readperm, &rauthority),
2554  user_authority_to_str(user->writeperm, &wauthority),
2555  (user->displayconnects ? "yes" : "no"),
2556  (user->allowmultiplelogin ? "yes" : "no"));
2557  ast_cli(a->fd, " Variables: \n");
2558  for (v = user->chanvars ; v ; v = v->next) {
2559  ast_cli(a->fd, " %s = %s\n", v->name, v->value);
2560  }
2561  if (!ast_acl_list_is_empty(user->acl)) {
2562  ast_acl_output(a->fd, user->acl, NULL);
2563  }
2564 
2566 
2567  return CLI_SUCCESS;
2568 }
2569 
2570 static char *handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2571 {
2572  struct ast_manager_user *user = NULL;
2573  int count_amu = 0;
2574  switch (cmd) {
2575  case CLI_INIT:
2576  e->command = "manager show users";
2577  e->usage =
2578  "Usage: manager show users\n"
2579  " Prints a listing of all managers that are currently configured on that\n"
2580  " system.\n";
2581  return NULL;
2582  case CLI_GENERATE:
2583  return NULL;
2584  }
2585  if (a->argc != 3) {
2586  return CLI_SHOWUSAGE;
2587  }
2588 
2590 
2591  /* If there are no users, print out something along those lines */
2592  if (AST_RWLIST_EMPTY(&users)) {
2593  ast_cli(a->fd, "There are no manager users.\n");
2595  return CLI_SUCCESS;
2596  }
2597 
2598  ast_cli(a->fd, "\nusername\n--------\n");
2599 
2600  AST_RWLIST_TRAVERSE(&users, user, list) {
2601  ast_cli(a->fd, "%s\n", user->username);
2602  count_amu++;
2603  }
2604 
2606 
2607  ast_cli(a->fd,"-------------------\n"
2608  "%d manager users configured.\n", count_amu);
2609  return CLI_SUCCESS;
2610 }
2611 
2612 /*! \brief CLI command manager list commands */
2613 static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2614 {
2615  struct manager_action *cur;
2616  int name_len = 1;
2617  int space_remaining;
2618 #define HSMC_FORMAT " %-*.*s %-.*s\n"
2619  switch (cmd) {
2620  case CLI_INIT:
2621  e->command = "manager show commands";
2622  e->usage =
2623  "Usage: manager show commands\n"
2624  " Prints a listing of all the available Asterisk manager interface commands.\n";
2625  return NULL;
2626  case CLI_GENERATE:
2627  return NULL;
2628  }
2629 
2631  AST_RWLIST_TRAVERSE(&actions, cur, list) {
2632  int incoming_len = strlen(cur->action);
2633  if (incoming_len > name_len) {
2634  name_len = incoming_len;
2635  }
2636  }
2637 
2638  space_remaining = MGR_SHOW_TERMINAL_WIDTH - name_len - 4;
2639  if (space_remaining < 0) {
2640  space_remaining = 0;
2641  }
2642 
2643  ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, "Action", space_remaining, "Synopsis");
2644  ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, "------", space_remaining, "--------");
2645 
2646  AST_RWLIST_TRAVERSE(&actions, cur, list) {
2647  ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, cur->action, space_remaining, cur->synopsis);
2648  }
2650 
2651  return CLI_SUCCESS;
2652 }
2653 
2654 /*! \brief CLI command manager list connected */
2655 static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2656 {
2657  struct ao2_container *sessions;
2658  struct mansession_session *session;
2659  time_t now = time(NULL);
2660 #define HSMCONN_FORMAT1 " %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
2661 #define HSMCONN_FORMAT2 " %-15.15s %-55.55s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
2662  int count = 0;
2663  struct ao2_iterator i;
2664 
2665  switch (cmd) {
2666  case CLI_INIT:
2667  e->command = "manager show connected";
2668  e->usage =
2669  "Usage: manager show connected\n"
2670  " Prints a listing of the users that are currently connected to the\n"
2671  "Asterisk manager interface.\n";
2672  return NULL;
2673  case CLI_GENERATE:
2674  return NULL;
2675  }
2676 
2677  ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
2678 
2679  sessions = ao2_global_obj_ref(mgr_sessions);
2680  if (sessions) {
2681  i = ao2_iterator_init(sessions, 0);
2682  ao2_ref(sessions, -1);
2683  while ((session = ao2_iterator_next(&i))) {
2684  ao2_lock(session);
2685  ast_cli(a->fd, HSMCONN_FORMAT2, session->username,
2686  ast_sockaddr_stringify_addr(&session->addr),
2687  (int) (session->sessionstart),
2688  (int) (now - session->sessionstart),
2689  session->stream ? ast_iostream_get_fd(session->stream) : -1,
2690  session->inuse,
2691  session->readperm,
2692  session->writeperm);
2693  count++;
2694  ao2_unlock(session);
2695  unref_mansession(session);
2696  }
2698  }
2699  ast_cli(a->fd, "%d users connected.\n", count);
2700 
2701  return CLI_SUCCESS;
2702 }
2703 
2704 /*! \brief CLI command manager list eventq */
2705 /* Should change to "manager show connected" */
2706 static char *handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2707 {
2708  struct eventqent *s;
2709  switch (cmd) {
2710  case CLI_INIT:
2711  e->command = "manager show eventq";
2712  e->usage =
2713  "Usage: manager show eventq\n"
2714  " Prints a listing of all events pending in the Asterisk manger\n"
2715  "event queue.\n";
2716  return NULL;
2717  case CLI_GENERATE:
2718  return NULL;
2719  }
2721  AST_RWLIST_TRAVERSE(&all_events, s, eq_next) {
2722  ast_cli(a->fd, "Usecount: %d\n", s->usecount);
2723  ast_cli(a->fd, "Category: %d\n", s->category);
2724  ast_cli(a->fd, "Event:\n%s", s->eventdata);
2725  }
2727 
2728  return CLI_SUCCESS;
2729 }
2730 
2731 static int reload_module(void);
2732 
2733 /*! \brief CLI command manager reload */
2734 static char *handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2735 {
2736  switch (cmd) {
2737  case CLI_INIT:
2738  e->command = "manager reload";
2739  e->usage =
2740  "Usage: manager reload\n"
2741  " Reloads the manager configuration.\n";
2742  return NULL;
2743  case CLI_GENERATE:
2744  return NULL;
2745  }
2746  if (a->argc > 2) {
2747  return CLI_SHOWUSAGE;
2748  }
2749  reload_module();
2750  return CLI_SUCCESS;
2751 }
2752 
2753 static struct eventqent *advance_event(struct eventqent *e)
2754 {
2755  struct eventqent *next;
2756 
2758  if ((next = AST_RWLIST_NEXT(e, eq_next))) {
2759  ast_atomic_fetchadd_int(&next->usecount, 1);
2761  }
2763  return next;
2764 }
2765 
2766 #define GET_HEADER_FIRST_MATCH 0
2767 #define GET_HEADER_LAST_MATCH 1
2768 #define GET_HEADER_SKIP_EMPTY 2
2769 
2770 /*!
2771  * \brief Return a matching header value.
2772  *
2773  * \details
2774  * Generic function to return either the first or the last
2775  * matching header from a list of variables, possibly skipping
2776  * empty strings.
2777  *
2778  * \note At the moment there is only one use of this function in
2779  * this file, so we make it static.
2780  *
2781  * \note Never returns NULL.
2782  */
2783 static const char *__astman_get_header(const struct message *m, char *var, int mode)
2784 {
2785  int x, l = strlen(var);
2786  const char *result = "";
2787 
2788  if (!m) {
2789  return result;
2790  }
2791 
2792  for (x = 0; x < m->hdrcount; x++) {
2793  const char *h = m->headers[x];
2794  if (!strncasecmp(var, h, l) && h[l] == ':') {
2795  const char *value = h + l + 1;
2796  value = ast_skip_blanks(value); /* ignore leading spaces in the value */
2797  /* found a potential candidate */
2798  if ((mode & GET_HEADER_SKIP_EMPTY) && ast_strlen_zero(value)) {
2799  continue; /* not interesting */
2800  }
2801  if (mode & GET_HEADER_LAST_MATCH) {
2802  result = value; /* record the last match so far */
2803  } else {
2804  return value;
2805  }
2806  }
2807  }
2808 
2809  return result;
2810 }
2811 
2812 /*!
2813  * \brief Return the first matching variable from an array.
2814  *
2815  * \note This is the legacy function and is implemented in
2816  * therms of __astman_get_header().
2817  *
2818  * \note Never returns NULL.
2819  */
2820 const char *astman_get_header(const struct message *m, char *var)
2821 {
2823 }
2824 
2825 /*!
2826  * \brief Append additional headers into the message structure from params.
2827  *
2828  * \note You likely want to initialize m->hdrcount to 0 before calling this.
2829  */
2830 static void astman_append_headers(struct message *m, const struct ast_variable *params)
2831 {
2832  const struct ast_variable *v;
2833 
2834  for (v = params; v && m->hdrcount < ARRAY_LEN(m->headers); v = v->next) {
2835  if (ast_asprintf((char**)&m->headers[m->hdrcount], "%s: %s", v->name, v->value) > -1) {
2836  ++m->hdrcount;
2837  }
2838  }
2839 }
2840 
2841 /*!
2842  * \brief Free headers inside message structure, but not the message structure itself.
2843  */
2844 static void astman_free_headers(struct message *m)
2845 {
2846  while (m->hdrcount) {
2847  --m->hdrcount;
2848  ast_free((void *) m->headers[m->hdrcount]);
2849  m->headers[m->hdrcount] = NULL;
2850  }
2851 }
2852 
2853 /*!
2854  * \internal
2855  * \brief Process one "Variable:" header value string.
2856  *
2857  * \param head Current list of AMI variables to get new values added.
2858  * \param hdr_val Header value string to process.
2859  *
2860  * \return New variable list head.
2861  */
2862 static struct ast_variable *man_do_variable_value(struct ast_variable *head, const char *hdr_val)
2863 {
2864  char *parse;
2866  AST_APP_ARG(vars)[64];
2867  );
2868 
2869  hdr_val = ast_skip_blanks(hdr_val); /* ignore leading spaces in the value */
2870  parse = ast_strdupa(hdr_val);
2871 
2872  /* Break the header value string into name=val pair items. */
2873  AST_STANDARD_APP_ARGS(args, parse);
2874  if (args.argc) {
2875  int y;
2876 
2877  /* Process each name=val pair item. */
2878  for (y = 0; y < args.argc; y++) {
2879  struct ast_variable *cur;
2880  char *var;
2881  char *val;
2882 
2883  if (!args.vars[y]) {
2884  continue;
2885  }
2886  var = val = args.vars[y];
2887  strsep(&val, "=");
2888 
2889  /* XXX We may wish to trim whitespace from the strings. */
2890  if (!val || ast_strlen_zero(var)) {
2891  continue;
2892  }
2893 
2894  /* Create new variable list node and prepend it to the list. */
2895  cur = ast_variable_new(var, val, "");
2896  if (cur) {
2897  cur->next = head;
2898  head = cur;
2899  }
2900  }
2901  }
2902 
2903  return head;
2904 }
2905 
2906 struct ast_variable *astman_get_variables(const struct message *m)
2907 {
2909 }
2910 
2911 struct ast_variable *astman_get_variables_order(const struct message *m,
2912  enum variable_orders order)
2913 {
2914  int varlen;
2915  int x;
2916  struct ast_variable *head = NULL;
2917 
2918  static const char var_hdr[] = "Variable:";
2919 
2920  /* Process all "Variable:" headers. */
2921  varlen = strlen(var_hdr);
2922  for (x = 0; x < m->hdrcount; x++) {
2923  if (strncasecmp(var_hdr, m->headers[x], varlen)) {
2924  continue;
2925  }
2926  head = man_do_variable_value(head, m->headers[x] + varlen);
2927  }
2928 
2929  if (order == ORDER_NATURAL) {
2930  head = ast_variables_reverse(head);
2931  }
2932 
2933  return head;
2934 }
2935 
2936 /*! \brief access for hooks to send action messages to ami */
2937 int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
2938 {
2939  const char *action;
2940  int ret = 0;
2941  struct manager_action *act_found;
2942  struct mansession s = {.session = NULL, };
2943  struct message m = { 0 };
2944  char *dup_str;
2945  char *src;
2946  int x = 0;
2947  int curlen;
2948 
2949  if (hook == NULL) {
2950  return -1;
2951  }
2952 
2953  /* Create our own copy of the AMI action msg string. */
2954  src = dup_str = ast_strdup(msg);
2955  if (!dup_str) {
2956  return -1;
2957  }
2958 
2959  /* convert msg string to message struct */
2960  curlen = strlen(src);
2961  for (x = 0; x < curlen; x++) {
2962  int cr; /* set if we have \r */
2963  if (src[x] == '\r' && x+1 < curlen && src[x+1] == '\n')
2964  cr = 2; /* Found. Update length to include \r\n */
2965  else if (src[x] == '\n')
2966  cr = 1; /* also accept \n only */
2967  else
2968  continue;
2969  /* don't keep empty lines */
2970  if (x && m.hdrcount < ARRAY_LEN(m.headers)) {
2971  /* ... but trim \r\n and terminate the header string */
2972  src[x] = '\0';
2973  m.headers[m.hdrcount++] = src;
2974  }
2975  x += cr;
2976  curlen -= x; /* remaining size */
2977  src += x; /* update pointer */
2978  x = -1; /* reset loop */
2979  }
2980 
2981  action = astman_get_header(&m, "Action");
2982 
2983  do {
2984  if (!strcasecmp(action, "login")) {
2985  break;
2986  }
2987 
2988  act_found = action_find(action);
2989  if (!act_found) {
2990  break;
2991  }
2992 
2993  /*
2994  * we have to simulate a session for this action request
2995  * to be able to pass it down for processing
2996  * This is necessary to meet the previous design of manager.c
2997  */
2998  s.hook = hook;
2999 
3000  ret = -1;
3001  ao2_lock(act_found);
3002  if (act_found->registered && act_found->func) {
3003  struct ast_module *mod_ref = ast_module_running_ref(act_found->module);
3004 
3005  ao2_unlock(act_found);
3006  /* If the action is in a module it must be running. */
3007  if (!act_found->module || mod_ref) {
3008  ret = act_found->func(&s, &m);
3009  ast_module_unref(mod_ref);
3010  }
3011  } else {
3012  ao2_unlock(act_found);
3013  }
3014  ao2_t_ref(act_found, -1, "done with found action object");
3015  } while (0);
3016 
3017  ast_free(dup_str);
3018  return ret;
3019 }
3020 
3021 /*!
3022  * helper function to send a string to the socket.
3023  * Return -1 on error (e.g. buffer full).
3024  */
3025 static int send_string(struct mansession *s, char *string)
3026 {
3027  struct ast_iostream *stream;
3028  int len, res;
3029 
3030  /* It's a result from one of the hook's action invocation */
3031  if (s->hook) {
3032  /*
3033  * to send responses, we're using the same function
3034  * as for receiving events. We call the event "HookResponse"
3035  */
3036  s->hook->helper(EVENT_FLAG_HOOKRESPONSE, "HookResponse", string);
3037  return 0;
3038  }
3039 
3040  stream = s->stream ? s->stream : s->session->stream;
3041 
3042  len = strlen(string);
3044  res = ast_iostream_write(stream, string, len);
3046 
3047  if (res < len) {
3048  s->write_error = 1;
3049  }
3050 
3051  return res;
3052 }
3053 
3054 /*!
3055  * \brief thread local buffer for astman_append
3056  *
3057  * \note This can not be defined within the astman_append() function
3058  * because it declares a couple of functions that get used to
3059  * initialize the thread local storage key.
3060  */
3062 
3064 
3065 /*! \brief initial allocated size for the astman_append_buf and astman_send_*_va */
3066 #define ASTMAN_APPEND_BUF_INITSIZE 256
3067 
3068 static void astman_flush(struct mansession *s, struct ast_str *buf)
3069 {
3070  if (s->hook || (s->tcptls_session && s->tcptls_session->stream)) {
3071  send_string(s, ast_str_buffer(buf));
3072  } else {
3073  ast_verbose("No connection stream in astman_append, should not happen\n");
3074  }
3075 }
3076 
3077 /*!
3078  * utility functions for creating AMI replies
3079  */
3080 void astman_append(struct mansession *s, const char *fmt, ...)
3081 {
3082  int res;
3083  va_list ap;
3084  struct ast_str *buf;
3085 
3087  return;
3088  }
3089 
3090  va_start(ap, fmt);
3091  res = ast_str_set_va(&buf, 0, fmt, ap);
3092  va_end(ap);
3093  if (res == AST_DYNSTR_BUILD_FAILED) {
3094  return;
3095  }
3096 
3097  if (s->hook || (s->tcptls_session != NULL && s->tcptls_session->stream != NULL)) {
3098  send_string(s, ast_str_buffer(buf));
3099  } else {
3100  ast_verbose("No connection stream in astman_append, should not happen\n");
3101  }
3102 }
3103 
3104 /*! \note NOTE: XXX this comment is unclear and possibly wrong.
3105  Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
3106  hold the session lock _or_ be running in an action callback (in which case s->session->busy will
3107  be non-zero). In either of these cases, there is no need to lock-protect the session's
3108  fd, since no other output will be sent (events will be queued), and no input will
3109  be read until either the current action finishes or get_input() obtains the session
3110  lock.
3111  */
3112 
3113 /*! \todo XXX MSG_MOREDATA should go to a header file. */
3114 #define MSG_MOREDATA ((char *)astman_send_response)
3115 
3116 /*! \brief send a response with an optional message,
3117  * and terminate it with an empty line.
3118  * m is used only to grab the 'ActionID' field.
3119  *
3120  * Use the explicit constant MSG_MOREDATA to remove the empty line.
3121  * XXX MSG_MOREDATA should go to a header file.
3122  */
3123 static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
3124 {
3125  const char *id = astman_get_header(m, "ActionID");
3126  struct ast_str *buf;
3127 
3129  if (!buf) {
3130  return;
3131  }
3132 
3133  ast_str_set(&buf, 0, "Response: %s\r\n", resp);
3134 
3135  if (!ast_strlen_zero(id)) {
3136  ast_str_append(&buf, 0, "ActionID: %s\r\n", id);
3137  }
3138 
3139  if (listflag) {
3140  /* Start, complete, cancelled */
3141  ast_str_append(&buf, 0, "EventList: %s\r\n", listflag);
3142  }
3143 
3144  if (msg != MSG_MOREDATA) {
3145  if (msg) {
3146  ast_str_append(&buf, 0, "Message: %s\r\n", msg);
3147  }
3148  ast_str_append(&buf, 0, "\r\n");
3149  }
3150 
3151  astman_flush(s, buf);
3152 }
3153 
3154 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
3155 {
3156  astman_send_response_full(s, m, resp, msg, NULL);
3157 }
3158 
3159 void astman_send_error(struct mansession *s, const struct message *m, char *error)
3160 {
3161  astman_send_response_full(s, m, "Error", error, NULL);
3162 }
3163 
3164 void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt, ...)
3165 {
3166  int res;
3167  va_list ap;
3168  struct ast_str *buf;
3169  char *msg;
3170 
3172  return;
3173  }
3174 
3175  va_start(ap, fmt);
3176  res = ast_str_set_va(&buf, 0, fmt, ap);
3177  va_end(ap);
3178  if (res == AST_DYNSTR_BUILD_FAILED) {
3179  return;
3180  }
3181 
3182  /* astman_append will use the same underlying buffer, so copy the message out
3183  * before sending the response */
3184  msg = ast_str_buffer(buf);
3185  if (msg) {
3186  msg = ast_strdupa(msg);
3187  }
3188  astman_send_response_full(s, m, "Error", msg, NULL);
3189 }
3190 
3191 void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
3192 {
3193  astman_send_response_full(s, m, "Success", msg, NULL);
3194 }
3195 
3196 static void astman_start_ack(struct mansession *s, const struct message *m)
3197 {
3198  astman_send_response_full(s, m, "Success", MSG_MOREDATA, NULL);
3199 }
3200 
3201 void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
3202 {
3203  astman_send_response_full(s, m, "Success", msg, listflag);
3204 }
3205 
3206 static struct ast_str *astman_send_list_complete_start_common(struct mansession *s, const struct message *m, const char *event_name, int count)
3207 {
3208  const char *id = astman_get_header(m, "ActionID");
3209  struct ast_str *buf;
3210 
3212  if (!buf) {
3213  return NULL;
3214  }
3215 
3216  ast_str_set(&buf, 0, "Event: %s\r\n", event_name);
3217  if (!ast_strlen_zero(id)) {
3218  ast_str_append(&buf, 0, "ActionID: %s\r\n", id);
3219  }
3220  ast_str_append(&buf, 0,
3221  "EventList: Complete\r\n"
3222  "ListItems: %d\r\n",
3223  count);
3224 
3225  return buf;
3226 }
3227 
3228 static void astman_send_list_complete(struct mansession *s, const struct message *m, const char *event_name, int count)
3229 {
3230  struct ast_str *buf = astman_send_list_complete_start_common(s, m, event_name, count);
3231  if (buf) {
3232  ast_str_append(&buf, 0, "\r\n");
3233  astman_flush(s, buf);
3234  }
3235 }
3236 
3237 void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
3238 {
3239  struct ast_str *buf = astman_send_list_complete_start_common(s, m, event_name, count);
3240  if (buf) {
3241  astman_flush(s, buf);
3242  }
3243 }
3244 
3246 {
3247  astman_append(s, "\r\n");
3248 }
3249 
3250 /*! \brief Lock the 'mansession' structure. */
3251 static void mansession_lock(struct mansession *s)
3252 {
3253  ast_mutex_lock(&s->lock);
3254 }
3255 
3256 /*! \brief Unlock the 'mansession' structure. */
3257 static void mansession_unlock(struct mansession *s)
3258 {
3259  ast_mutex_unlock(&s->lock);
3260 }
3261 
3262 /*! \brief
3263  Rather than braindead on,off this now can also accept a specific int mask value
3264  or a ',' delim list of mask strings (the same as manager.conf) -anthm
3265 */
3266 static int set_eventmask(struct mansession *s, const char *eventmask)
3267 {
3268  int maskint = strings_to_mask(eventmask);
3269 
3270  ao2_lock(s->session);
3271  if (maskint >= 0) {
3272  s->session->send_events = maskint;
3273  }
3274  ao2_unlock(s->session);
3275 
3276  return maskint;
3277 }
3278 
3280 {
3283 }
3284 
3285 static void report_invalid_user(const struct mansession *s, const char *username)
3286 {
3287  char session_id[32];
3288  struct ast_security_event_inval_acct_id inval_acct_id = {
3290  .common.version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
3291  .common.service = "AMI",
3292  .common.account_id = username,
3293  .common.session_tv = &s->session->sessionstart_tv,
3294  .common.local_addr = {
3295  .addr = &s->tcptls_session->parent->local_address,
3296  .transport = mansession_get_transport(s),
3297  },
3298  .common.remote_addr = {
3299  .addr = &s->session->addr,
3300  .transport = mansession_get_transport(s),
3301  },
3302  .common.session_id = session_id,
3303  };
3304 
3305  snprintf(session_id, sizeof(session_id), "%p", s);
3306 
3307  ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
3308 }
3309 
3310 static void report_failed_acl(const struct mansession *s, const char *username)
3311 {
3312  char session_id[32];
3313  struct ast_security_event_failed_acl failed_acl_event = {
3315  .common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
3316  .common.service = "AMI",
3317  .common.account_id = username,
3318  .common.session_tv = &s->session->sessionstart_tv,
3319  .common.local_addr = {
3320  .addr = &s->tcptls_session->parent->local_address,
3321  .transport = mansession_get_transport(s),
3322  },
3323  .common.remote_addr = {
3324  .addr = &s->session->addr,
3325  .transport = mansession_get_transport(s),
3326  },
3327  .common.session_id = session_id,
3328  };
3329 
3330  snprintf(session_id, sizeof(session_id), "%p", s->session);
3331 
3332  ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
3333 }
3334 
3335 static void report_inval_password(const struct mansession *s, const char *username)
3336 {
3337  char session_id[32];
3338  struct ast_security_event_inval_password inval_password = {
3341  .common.service = "AMI",
3342  .common.account_id = username,
3343  .common.session_tv = &s->session->sessionstart_tv,
3344  .common.local_addr = {
3345  .addr = &s->tcptls_session->parent->local_address,
3346  .transport = mansession_get_transport(s),
3347  },
3348  .common.remote_addr = {
3349  .addr = &s->session->addr,
3350  .transport = mansession_get_transport(s),
3351  },
3352  .common.session_id = session_id,
3353  };
3354 
3355  snprintf(session_id, sizeof(session_id), "%p", s->session);
3356 
3357  ast_security_event_report(AST_SEC_EVT(&inval_password));
3358 }
3359 
3360 static void report_auth_success(const struct mansession *s)
3361 {
3362  char session_id[32];
3363  struct ast_security_event_successful_auth successful_auth = {
3366  .common.service = "AMI",
3367  .common.account_id = s->session->username,
3368  .common.session_tv = &s->session->sessionstart_tv,
3369  .common.local_addr = {
3370  .addr = &s->tcptls_session->parent->local_address,
3371  .transport = mansession_get_transport(s),
3372  },
3373  .common.remote_addr = {
3374  .addr = &s->session->addr,
3375  .transport = mansession_get_transport(s),
3376  },
3377  .common.session_id = session_id,
3378  };
3379 
3380  snprintf(session_id, sizeof(session_id), "%p", s->session);
3381 
3382  ast_security_event_report(AST_SEC_EVT(&successful_auth));
3383 }
3384 
3385 static void report_req_not_allowed(const struct mansession *s, const char *action)
3386 {
3387  char session_id[32];
3388  char request_type[64];
3389  struct ast_security_event_req_not_allowed req_not_allowed = {
3392  .common.service = "AMI",
3393  .common.account_id = s->session->username,
3394  .common.session_tv = &s->session->sessionstart_tv,
3395  .common.local_addr = {
3396  .addr = &s->tcptls_session->parent->local_address,
3397  .transport = mansession_get_transport(s),
3398  },
3399  .common.remote_addr = {
3400  .addr = &s->session->addr,
3401  .transport = mansession_get_transport(s),
3402  },
3403  .common.session_id = session_id,
3404 
3405  .request_type = request_type,
3406  };
3407 
3408  snprintf(session_id, sizeof(session_id), "%p", s->session);
3409  snprintf(request_type, sizeof(request_type), "Action: %s", action);
3410 
3411  ast_security_event_report(AST_SEC_EVT(&req_not_allowed));
3412 }
3413 
3414 static void report_req_bad_format(const struct mansession *s, const char *action)
3415 {
3416  char session_id[32];
3417  char request_type[64];
3418  struct ast_security_event_req_bad_format req_bad_format = {
3421  .common.service = "AMI",
3422  .common.account_id = s->session->username,
3423  .common.session_tv = &s->session->sessionstart_tv,
3424  .common.local_addr = {
3425  .addr = &s->tcptls_session->parent->local_address,
3426  .transport = mansession_get_transport(s),
3427  },
3428  .common.remote_addr = {
3429  .addr = &s->session->addr,
3430  .transport = mansession_get_transport(s),
3431  },
3432  .common.session_id = session_id,
3433 
3434  .request_type = request_type,
3435  };
3436 
3437  snprintf(session_id, sizeof(session_id), "%p", s->session);
3438  snprintf(request_type, sizeof(request_type), "Action: %s", action);
3439 
3440  ast_security_event_report(AST_SEC_EVT(&req_bad_format));
3441 }
3442 
3443 static void report_failed_challenge_response(const struct mansession *s,
3444  const char *response, const char *expected_response)
3445 {
3446  char session_id[32];
3447  struct ast_security_event_chal_resp_failed chal_resp_failed = {
3450  .common.service = "AMI",
3451  .common.account_id = s->session->username,
3452  .common.session_tv = &s->session->sessionstart_tv,
3453  .common.local_addr = {
3454  .addr = &s->tcptls_session->parent->local_address,
3455  .transport = mansession_get_transport(s),
3456  },
3457  .common.remote_addr = {
3458  .addr = &s->session->addr,
3459  .transport = mansession_get_transport(s),
3460  },
3461  .common.session_id = session_id,
3462 
3463  .challenge = s->session->challenge,
3464  .response = response,
3465  .expected_response = expected_response,
3466  };
3467 
3468  snprintf(session_id, sizeof(session_id), "%p", s->session);
3469 
3470  ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
3471 }
3472 
3473 static void report_session_limit(const struct mansession *s)
3474 {
3475  char session_id[32];
3476  struct ast_security_event_session_limit session_limit = {
3478  .common.version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
3479  .common.service = "AMI",
3480  .common.account_id = s->session->username,
3481  .common.session_tv = &s->session->sessionstart_tv,
3482  .common.local_addr = {
3483  .addr = &s->tcptls_session->parent->local_address,
3484  .transport = mansession_get_transport(s),
3485  },
3486  .common.remote_addr = {
3487  .addr = &s->session->addr,
3488  .transport = mansession_get_transport(s),
3489  },
3490  .common.session_id = session_id,
3491  };
3492 
3493  snprintf(session_id, sizeof(session_id), "%p", s->session);
3494 
3495  ast_security_event_report(AST_SEC_EVT(&session_limit));
3496 }
3497 
3498 /*
3499  * Here we start with action_ handlers for AMI actions,
3500  * and the internal functions used by them.
3501  * Generally, the handlers are called action_foo()
3502  */
3503 
3504 /* helper function for action_login() */
3505 static int authenticate(struct mansession *s, const struct message *m)
3506 {
3507  const char *username = astman_get_header(m, "Username");
3508  const char *password = astman_get_header(m, "Secret");
3509  int error = -1;
3510  struct ast_manager_user *user = NULL;
3511  regex_t *regex_filter;
3512  struct ao2_iterator filter_iter;
3513 
3514  if (ast_strlen_zero(username)) { /* missing username */
3515  return -1;
3516  }
3517 
3518  /* locate user in locked state */
3520 
3521  if (!(user = get_manager_by_name_locked(username))) {
3522  report_invalid_user(s, username);
3523  ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3524  } else if (user->acl && (ast_apply_acl(user->acl, &s->session->addr, "Manager User ACL: ") == AST_SENSE_DENY)) {
3525  report_failed_acl(s, username);
3526  ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3527  } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
3528  const char *key = astman_get_header(m, "Key");
3529  if (!ast_strlen_zero(key) && !ast_strlen_zero(s->session->challenge) && user->secret) {
3530  int x;
3531  int len = 0;
3532  char md5key[256] = "";
3533  struct MD5Context md5;
3534  unsigned char digest[16];
3535 
3536  MD5Init(&md5);
3537  MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
3538  MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
3539  MD5Final(digest, &md5);
3540  for (x = 0; x < 16; x++)
3541  len += sprintf(md5key + len, "%02hhx", digest[x]);
3542  if (!strcmp(md5key, key)) {
3543  error = 0;
3544  } else {
3545  report_failed_challenge_response(s, key, md5key);
3546  }
3547  } else {
3548  ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
3549  S_OR(s->session->challenge, ""));
3550  }
3551  } else if (user->secret) {
3552  if (!strcmp(password, user->secret)) {
3553  error = 0;
3554  } else {
3555  report_inval_password(s, username);
3556  }
3557  }
3558 
3559  if (error) {
3560  ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3562  return -1;
3563  }
3564 
3565  /* auth complete */
3566 
3567  /* All of the user parameters are copied to the session so that in the event
3568  * of a reload and a configuration change, the session parameters are not
3569  * changed. */
3570  ast_copy_string(s->session->username, username, sizeof(s->session->username));
3571  s->session->readperm = user->readperm;
3572  s->session->writeperm = user->writeperm;
3573  s->session->writetimeout = user->writetimeout;
3574  if (user->chanvars) {
3576  }
3577 
3578  filter_iter = ao2_iterator_init(user->whitefilters, 0);
3579  while ((regex_filter = ao2_iterator_next(&filter_iter))) {
3580  ao2_t_link(s->session->whitefilters, regex_filter, "add white user filter to session");
3581  ao2_t_ref(regex_filter, -1, "remove iterator ref");
3582  }
3583  ao2_iterator_destroy(&filter_iter);
3584 
3585  filter_iter = ao2_iterator_init(user->blackfilters, 0);
3586  while ((regex_filter = ao2_iterator_next(&filter_iter))) {
3587  ao2_t_link(s->session->blackfilters, regex_filter, "add black user filter to session");
3588  ao2_t_ref(regex_filter, -1, "remove iterator ref");
3589  }
3590  ao2_iterator_destroy(&filter_iter);
3591 
3592  s->session->sessionstart = time(NULL);
3594  set_eventmask(s, astman_get_header(m, "Events"));
3595 
3597 
3599  return 0;
3600 }
3601 
3602 static int action_ping(struct mansession *s, const struct message *m)
3603 {
3604  const char *actionid = astman_get_header(m, "ActionID");
3605  struct timeval now = ast_tvnow();
3606 
3607  astman_append(s, "Response: Success\r\n");
3608  if (!ast_strlen_zero(actionid)){
3609  astman_append(s, "ActionID: %s\r\n", actionid);
3610  }
3611  astman_append(
3612  s,
3613  "Ping: Pong\r\n"
3614  "Timestamp: %ld.%06lu\r\n"
3615  "\r\n",
3616  (long) now.tv_sec, (unsigned long) now.tv_usec);
3617  return 0;
3618 }
3619 
3620 static int action_getconfig(struct mansession *s, const struct message *m)
3621 {
3622  struct ast_config *cfg;
3623  const char *fn = astman_get_header(m, "Filename");
3624  const char *category = astman_get_header(m, "Category");
3625  const char *filter = astman_get_header(m, "Filter");
3626  const char *category_name;
3627  int catcount = 0;
3628  int lineno = 0;
3629  struct ast_category *cur_category = NULL;
3630  struct ast_variable *v;
3631  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3632 
3633  if (ast_strlen_zero(fn)) {
3634  astman_send_error(s, m, "Filename not specified");
3635  return 0;
3636  }
3637 
3638  cfg = ast_config_load2(fn, "manager", config_flags);
3639  if (cfg == CONFIG_STATUS_FILEMISSING) {
3640  astman_send_error(s, m, "Config file not found");
3641  return 0;
3642  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
3643  astman_send_error(s, m, "Config file has invalid format");
3644  return 0;
3645  }
3646 
3647  astman_start_ack(s, m);
3648  while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
3649  struct ast_str *templates;
3650 
3651  category_name = ast_category_get_name(cur_category);
3652  lineno = 0;
3653  astman_append(s, "Category-%06d: %s\r\n", catcount, category_name);
3654 
3655  if (ast_category_is_template(cur_category)) {
3656  astman_append(s, "IsTemplate-%06d: %d\r\n", catcount, 1);
3657  }
3658 
3659  if ((templates = ast_category_get_templates(cur_category))
3660  && ast_str_strlen(templates) > 0) {
3661  astman_append(s, "Templates-%06d: %s\r\n", catcount, ast_str_buffer(templates));
3662  ast_free(templates);
3663  }
3664 
3665  for (v = ast_category_first(cur_category); v; v = v->next) {
3666  astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
3667  }
3668 
3669  catcount++;
3670  }
3671 
3672  if (!ast_strlen_zero(category) && catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
3673  astman_append(s, "No categories found\r\n");
3674  }
3675 
3676  ast_config_destroy(cfg);
3677  astman_append(s, "\r\n");
3678 
3679  return 0;
3680 }
3681 
3682 static int action_listcategories(struct mansession *s, const struct message *m)
3683 {
3684  struct ast_config *cfg;
3685  const char *fn = astman_get_header(m, "Filename");
3686  const char *match = astman_get_header(m, "Match");
3687  struct ast_category *category = NULL;
3688  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3689  int catcount = 0;
3690 
3691  if (ast_strlen_zero(fn)) {
3692  astman_send_error(s, m, "Filename not specified");
3693  return 0;
3694  }
3695 
3696  if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
3697  astman_send_error(s, m, "Config file not found");
3698  return 0;
3699  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
3700  astman_send_error(s, m, "Config file has invalid format");
3701  return 0;
3702  }
3703 
3704  astman_start_ack(s, m);
3705  while ((category = ast_category_browse_filtered(cfg, NULL, category, match))) {
3706  astman_append(s, "Category-%06d: %s\r\n", catcount, ast_category_get_name(category));
3707  catcount++;
3708  }
3709 
3710  if (catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
3711  astman_append(s, "Error: no categories found\r\n");
3712  }
3713 
3714  ast_config_destroy(cfg);
3715  astman_append(s, "\r\n");
3716 
3717  return 0;
3718 }
3719 
3720 /*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
3721 static void json_escape(char *out, const char *in)
3722 {
3723  for (; *in; in++) {
3724  if (*in == '\\' || *in == '\"') {
3725  *out++ = '\\';
3726  }
3727  *out++ = *in;
3728  }
3729  *out = '\0';
3730 }
3731 
3732 /*!
3733  * \internal
3734  * \brief Append a JSON escaped string to the manager stream.
3735  *
3736  * \param s AMI stream to append a string.
3737  * \param str String to append to the stream after JSON escaping it.
3738  *
3739  * \return Nothing
3740  */
3741 static void astman_append_json(struct mansession *s, const char *str)
3742 {
3743  char *buf;
3744 
3745  buf = ast_alloca(2 * strlen(str) + 1);
3746  json_escape(buf, str);
3747  astman_append(s, "%s", buf);
3748 }
3749 
3750 static int action_getconfigjson(struct mansession *s, const struct message *m)
3751 {
3752  struct ast_config *cfg;
3753  const char *fn = astman_get_header(m, "Filename");
3754  const char *filter = astman_get_header(m, "Filter");
3755  const char *category = astman_get_header(m, "Category");
3756  struct ast_category *cur_category = NULL;
3757  const char *category_name;
3758  struct ast_variable *v;
3759  int comma1 = 0;
3760  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3761 
3762  if (ast_strlen_zero(fn)) {
3763  astman_send_error(s, m, "Filename not specified");
3764  return 0;
3765  }
3766 
3767  if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
3768  astman_send_error(s, m, "Config file not found");
3769  return 0;
3770  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
3771  astman_send_error(s, m, "Config file has invalid format");
3772  return 0;
3773  }
3774 
3775  astman_start_ack(s, m);
3776  astman_append(s, "JSON: {");
3777  while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
3778  int comma2 = 0;
3779  struct ast_str *templates;
3780 
3781  category_name = ast_category_get_name(cur_category);
3782  astman_append(s, "%s\"", comma1 ? "," : "");
3783  astman_append_json(s, category_name);
3784  astman_append(s, "\":{");
3785  comma1 = 1;
3786 
3787  if (ast_category_is_template(cur_category)) {
3788  astman_append(s, "\"istemplate\":1");
3789  comma2 = 1;
3790  }
3791 
3792  if ((templates = ast_category_get_templates(cur_category))
3793  && ast_str_strlen(templates) > 0) {
3794  astman_append(s, "%s", comma2 ? "," : "");
3795  astman_append(s, "\"templates\":\"%s\"", ast_str_buffer(templates));
3796  ast_free(templates);
3797  comma2 = 1;
3798  }
3799 
3800  for (v = ast_category_first(cur_category); v; v = v->next) {
3801  astman_append(s, "%s\"", comma2 ? "," : "");
3802  astman_append_json(s, v->name);
3803  astman_append(s, "\":\"");
3804  astman_append_json(s, v->value);
3805  astman_append(s, "\"");
3806  comma2 = 1;
3807  }
3808 
3809  astman_append(s, "}");
3810  }
3811  astman_append(s, "}\r\n\r\n");
3812 
3813  ast_config_destroy(cfg);
3814 
3815  return 0;
3816 }
3817 
3818 /*! \brief helper function for action_updateconfig */
3819 static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
3820 {
3821  int x;
3822  char hdr[40];
3823  const char *action, *cat, *var, *value, *match, *line, *options;
3824  struct ast_variable *v;
3825  struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
3826  enum error_type result = 0;
3827 
3828  for (x = 0; x < 100000; x++) { /* 100000 = the max number of allowed updates + 1 */
3829  unsigned int object = 0;
3830  char *dupoptions;
3831  int allowdups = 0;
3832  int istemplate = 0;
3833  int ignoreerror = 0;
3834  RAII_VAR(char *, inherit, NULL, ast_free);
3835  RAII_VAR(char *, catfilter, NULL, ast_free);
3836  char *token;
3837  int foundvar = 0;
3838  int foundcat = 0;
3839  struct ast_category *category = NULL;
3840 
3841  snprintf(hdr, sizeof(hdr), "Action-%06d", x);
3842  action = astman_get_header(m, hdr);
3843  if (ast_strlen_zero(action)) /* breaks the for loop if no action header */
3844  break; /* this could cause problems if actions come in misnumbered */
3845 
3846  snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
3847  cat = astman_get_header(m, hdr);
3848  if (ast_strlen_zero(cat)) { /* every action needs a category */
3849  result = UNSPECIFIED_CATEGORY;
3850  break;
3851  }
3852 
3853  snprintf(hdr, sizeof(hdr), "Var-%06d", x);
3854  var = astman_get_header(m, hdr);
3855 
3856  snprintf(hdr, sizeof(hdr), "Value-%06d", x);
3857  value = astman_get_header(m, hdr);
3858 
3859  if (!ast_strlen_zero(value) && *value == '>') {
3860  object = 1;
3861  value++;
3862  }
3863 
3864  snprintf(hdr, sizeof(hdr), "Match-%06d", x);
3865  match = astman_get_header(m, hdr);
3866 
3867  snprintf(hdr, sizeof(hdr), "Line-%06d", x);
3868  line = astman_get_header(m, hdr);
3869 
3870  snprintf(hdr, sizeof(hdr), "Options-%06d", x);
3871  options = astman_get_header(m, hdr);
3872  if (!ast_strlen_zero(options)) {
3873  char copy[strlen(options) + 1];
3874  strcpy(copy, options); /* safe */
3875  dupoptions = copy;
3876  while ((token = ast_strsep(&dupoptions, ',', AST_STRSEP_STRIP))) {
3877  if (!strcasecmp("allowdups", token)) {
3878  allowdups = 1;
3879  continue;
3880  }
3881  if (!strcasecmp("template", token)) {
3882  istemplate = 1;
3883  continue;
3884  }
3885  if (!strcasecmp("ignoreerror", token)) {
3886  ignoreerror = 1;
3887  continue;
3888  }
3889  if (ast_begins_with(token, "inherit")) {
3890  char *c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3891  c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3892  if (c) {
3893  inherit = ast_strdup(c);
3894  }
3895  continue;
3896  }
3897  if (ast_begins_with(token, "catfilter")) {
3898  char *c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3899  c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3900  if (c) {
3901  catfilter = ast_strdup(c);
3902  }
3903  continue;
3904  }
3905  }
3906  }
3907 
3908  if (!strcasecmp(action, "newcat")) {
3909  struct ast_category *template;
3910  char *tmpl_name = NULL;
3911 
3912  if (!allowdups) {
3913  if (ast_category_get(cfg, cat, "TEMPLATES=include")) {
3914  if (ignoreerror) {
3915  continue;
3916  } else {
3917  result = FAILURE_NEWCAT; /* already exist */
3918  break;
3919  }
3920  }
3921  }
3922 
3923  if (istemplate) {
3924  category = ast_category_new_template(cat, dfn, -1);
3925  } else {
3926  category = ast_category_new(cat, dfn, -1);
3927  }
3928 
3929  if (!category) {
3930  result = FAILURE_ALLOCATION;
3931  break;
3932  }
3933 
3934  if (inherit) {
3935  while ((tmpl_name = ast_strsep(&inherit, ',', AST_STRSEP_STRIP))) {
3936  if ((template = ast_category_get(cfg, tmpl_name, "TEMPLATES=restrict"))) {
3937  if (ast_category_inherit(category, template)) {
3938  result = FAILURE_ALLOCATION;
3939  break;
3940  }
3941  } else {
3942  ast_category_destroy(category);
3943  category = NULL;
3944  result = FAILURE_TEMPLATE; /* template not found */
3945  break;
3946  }
3947  }
3948  }
3949 
3950  if (category != NULL) {
3951  if (ast_strlen_zero(match)) {
3952  ast_category_append(cfg, category);
3953  } else {
3954  if (ast_category_insert(cfg, category, match)) {
3955  ast_category_destroy(category);
3956  result = FAILURE_NEWCAT;
3957  break;
3958  }
3959  }
3960  }
3961  } else if (!strcasecmp(action, "renamecat")) {
3962  if (ast_strlen_zero(value)) {
3963  result = UNSPECIFIED_ARGUMENT;
3964  break;
3965  }
3966 
3967  foundcat = 0;
3968  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3969  ast_category_rename(category, value);
3970  foundcat = 1;
3971  }
3972 
3973  if (!foundcat) {
3974  result = UNKNOWN_CATEGORY;
3975  break;
3976  }
3977  } else if (!strcasecmp(action, "delcat")) {
3978  foundcat = 0;
3979  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3980  category = ast_category_delete(cfg, category);
3981  foundcat = 1;
3982  }
3983 
3984  if (!foundcat && !ignoreerror) {
3985  result = UNKNOWN_CATEGORY;
3986  break;
3987  }
3988  } else if (!strcasecmp(action, "emptycat")) {
3989  foundcat = 0;
3990  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3991  ast_category_empty(category);
3992  foundcat = 1;
3993  }
3994 
3995  if (!foundcat) {
3996  result = UNKNOWN_CATEGORY;
3997  break;
3998  }
3999  } else if (!strcasecmp(action, "update")) {
4000  if (ast_strlen_zero(var)) {
4001  result = UNSPECIFIED_ARGUMENT;
4002  break;
4003  }
4004 
4005  foundcat = 0;
4006  foundvar = 0;
4007  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4008  if (!ast_variable_update(category, var, value, match, object)) {
4009  foundvar = 1;
4010  }
4011  foundcat = 1;
4012  }
4013 
4014  if (!foundcat) {
4015  result = UNKNOWN_CATEGORY;
4016  break;
4017  }
4018 
4019  if (!foundvar) {
4020  result = FAILURE_UPDATE;
4021  break;
4022  }
4023  } else if (!strcasecmp(action, "delete")) {
4024  if ((ast_strlen_zero(var) && ast_strlen_zero(line))) {
4025  result = UNSPECIFIED_ARGUMENT;
4026  break;
4027  }
4028 
4029  foundcat = 0;
4030  foundvar = 0;
4031  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4032  if (!ast_variable_delete(category, var, match, line)) {
4033  foundvar = 1;
4034  }
4035  foundcat = 1;
4036  }
4037 
4038  if (!foundcat) {
4039  result = UNKNOWN_CATEGORY;
4040  break;
4041  }
4042 
4043  if (!foundvar && !ignoreerror) {
4044  result = FAILURE_UPDATE;
4045  break;
4046  }
4047  } else if (!strcasecmp(action, "append")) {
4048  if (ast_strlen_zero(var)) {
4049  result = UNSPECIFIED_ARGUMENT;
4050  break;
4051  }
4052 
4053  foundcat = 0;
4054  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4055  if (!(v = ast_variable_new(var, value, dfn))) {
4056  result = FAILURE_ALLOCATION;
4057  break;
4058  }
4059  if (object || (match && !strcasecmp(match, "object"))) {
4060  v->object = 1;
4061  }
4062  ast_variable_append(category, v);
4063  foundcat = 1;
4064  }
4065 
4066  if (!foundcat) {
4067  result = UNKNOWN_CATEGORY;
4068  break;
4069  }
4070  } else if (!strcasecmp(action, "insert")) {
4071  if (ast_strlen_zero(var) || ast_strlen_zero(line)) {
4072  result = UNSPECIFIED_ARGUMENT;
4073  break;
4074  }
4075 
4076  foundcat = 0;
4077  while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4078  if (!(v = ast_variable_new(var, value, dfn))) {
4079  result = FAILURE_ALLOCATION;
4080  break;
4081  }
4082  ast_variable_insert(category, v, line);
4083  foundcat = 1;
4084  }
4085 
4086  if (!foundcat) {
4087  result = UNKNOWN_CATEGORY;
4088  break;
4089  }
4090  }
4091  else {
4092  ast_log(LOG_WARNING, "Action-%06d: %s not handled\n", x, action);
4093  result = UNKNOWN_ACTION;
4094  break;
4095  }
4096  }
4097  ast_free(str1);
4098  ast_free(str2);
4099  return result;
4100 }
4101 
4102 static int action_updateconfig(struct mansession *s, const struct message *m)
4103 {
4104  struct ast_config *cfg;
4105  const char *sfn = astman_get_header(m, "SrcFilename");
4106  const char *dfn = astman_get_header(m, "DstFilename");
4107  int res;
4108  const char *rld = astman_get_header(m, "Reload");
4109  int preserve_effective_context = CONFIG_SAVE_FLAG_PRESERVE_EFFECTIVE_CONTEXT;
4110  const char *preserve_effective_context_string = astman_get_header(m, "PreserveEffectiveContext");
4111  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
4112  enum error_type result;
4113 
4114  if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
4115  astman_send_error(s, m, "Filename not specified");
4116  return 0;
4117  }
4118  if (!(cfg = ast_config_load2(sfn, "manager", config_flags))) {
4119  astman_send_error(s, m, "Config file not found");
4120  return 0;
4121  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
4122  astman_send_error(s, m, "Config file has invalid format");
4123  return 0;
4124  }
4125  result = handle_updates(s, m, cfg, dfn);
4126  if (!result) {
4127  ast_include_rename(cfg, sfn, dfn); /* change the include references from dfn to sfn, so things match up */
4128  if (!ast_strlen_zero(preserve_effective_context_string) && !ast_true(preserve_effective_context_string)) {
4129  preserve_effective_context = CONFIG_SAVE_FLAG_NONE;
4130  }
4131  res = ast_config_text_file_save2(dfn, cfg, "Manager", preserve_effective_context);
4132  ast_config_destroy(cfg);
4133  if (res) {
4134  astman_send_error(s, m, "Save of config failed");
4135  return 0;
4136  }
4137  astman_send_ack(s, m, NULL);
4138  if (!ast_strlen_zero(rld)) {
4139  if (ast_true(rld)) {
4140  rld = NULL;
4141  }
4142  ast_module_reload(rld);
4143  }
4144  } else {
4145  ast_config_destroy(cfg);
4146  switch(result) {
4147  case UNKNOWN_ACTION:
4148  astman_send_error(s, m, "Unknown action command");
4149  break;
4150  case UNKNOWN_CATEGORY:
4151  astman_send_error(s, m, "Given category does not exist");
4152  break;
4153  case UNSPECIFIED_CATEGORY:
4154  astman_send_error(s, m, "Category not specified");
4155  break;
4156  case UNSPECIFIED_ARGUMENT:
4157  astman_send_error(s, m, "Problem with category, value, or line (if required)");
4158  break;
4159  case FAILURE_ALLOCATION:
4160  astman_send_error(s, m, "Memory allocation failure, this should not happen");
4161  break;
4162  case FAILURE_NEWCAT:
4163  astman_send_error(s, m, "Create category did not complete successfully");
4164  break;
4165  case FAILURE_DELCAT:
4166  astman_send_error(s, m, "Delete category did not complete successfully");
4167  break;
4168  case FAILURE_EMPTYCAT:
4169  astman_send_error(s, m, "Empty category did not complete successfully");
4170  break;
4171  case FAILURE_UPDATE:
4172  astman_send_error(s, m, "Update did not complete successfully");
4173  break;
4174  case FAILURE_DELETE:
4175  astman_send_error(s, m, "Delete did not complete successfully");
4176  break;
4177  case FAILURE_APPEND:
4178  astman_send_error(s, m, "Append did not complete successfully");
4179  break;
4180  case FAILURE_TEMPLATE:
4181  astman_send_error(s, m, "Template category not found");
4182  break;
4183  }
4184  }
4185  return 0;
4186 }
4187 
4188 static int action_createconfig(struct mansession *s, const struct message *m)
4189 {
4190  int fd;
4191  const char *fn = astman_get_header(m, "Filename");
4192  struct ast_str *filepath = ast_str_alloca(PATH_MAX);
4193  ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
4194  ast_str_append(&filepath, 0, "%s", fn);
4195 
4196  if ((fd = open(ast_str_buffer(filepath), O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
4197  close(fd);
4198  astman_send_ack(s, m, "New configuration file created successfully");
4199  } else {
4200  astman_send_error(s, m, strerror(errno));
4201  }
4202 
4203  return 0;
4204 }
4205 
4206 static int action_waitevent(struct mansession *s, const struct message *m)
4207 {
4208  const char *timeouts = astman_get_header(m, "Timeout");
4209  int timeout = -1;
4210  int x;
4211  int needexit = 0;
4212  const char *id = astman_get_header(m, "ActionID");
4213  char idText[256];
4214 
4215  if (!ast_strlen_zero(id)) {
4216  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
4217  } else {
4218  idText[0] = '\0';
4219  }
4220 
4221  if (!ast_strlen_zero(timeouts)) {
4222  sscanf(timeouts, "%30i", &timeout);
4223  if (timeout < -1) {
4224  timeout = -1;
4225  }
4226  /* XXX maybe put an upper bound, or prevent the use of 0 ? */
4227  }
4228 
4231  pthread_kill(s->session->waiting_thread, SIGURG);
4232  }
4234 
4235  ao2_lock(s->session);
4236 
4237  if (s->session->managerid) { /* AMI-over-HTTP session */
4238  /*
4239  * Make sure the timeout is within the expire time of the session,
4240  * as the client will likely abort the request if it does not see
4241  * data coming after some amount of time.
4242  */
4243  time_t now = time(NULL);
4244  int max = s->session->sessiontimeout - now - 10;
4245 
4246  if (max < 0) { /* We are already late. Strange but possible. */
4247  max = 0;
4248  }
4249  if (timeout < 0 || timeout > max) {
4250  timeout = max;
4251  }
4252  if (!s->session->send_events) { /* make sure we record events */
4253  s->session->send_events = -1;
4254  }
4255  }
4256  ao2_unlock(s->session);
4257 
4259  s->session->waiting_thread = pthread_self(); /* let new events wake up this thread */
4261  ast_debug(1, "Starting waiting for an event!\n");
4262 
4263  for (x = 0; x < timeout || timeout < 0; x++) {
4264  ao2_lock(s->session);
4265  if (AST_RWLIST_NEXT(s->session->last_ev, eq_next)) {
4266  needexit = 1;
4267  }
4268  if (s->session->needdestroy) {
4269  needexit = 1;
4270  }
4271  ao2_unlock(s->session);
4272  /* We can have multiple HTTP session point to the same mansession entry.
4273  * The way we deal with it is not very nice: newcomers kick out the previous
4274  * HTTP session. XXX this needs to be improved.
4275  */
4277  if (s->session->waiting_thread != pthread_self()) {
4278  needexit = 1;
4279  }
4281  if (needexit) {
4282  break;
4283  }
4284  if (s->session->managerid == 0) { /* AMI session */
4286  break;
4287  }
4288  } else { /* HTTP session */
4289  sleep(1);
4290  }
4291  }
4292  ast_debug(1, "Finished waiting for an event!\n");
4293 
4295  if (s->session->waiting_thread == pthread_self()) {
4296  struct eventqent *eqe = s->session->last_ev;
4297 
4300 
4301  ao2_lock(s->session);
4302  astman_send_response(s, m, "Success", "Waiting for Event completed.");
4303  while ((eqe = advance_event(eqe))) {
4304  if (((s->session->readperm & eqe->category) == eqe->category)
4305  && ((s->session->send_events & eqe->category) == eqe->category)
4306  && match_filter(s, eqe->eventdata)) {
4307  astman_append(s, "%s", eqe->eventdata);
4308  }
4309  s->session->last_ev = eqe;
4310  }
4311  astman_append(s,
4312  "Event: WaitEventComplete\r\n"
4313  "%s"
4314  "\r\n", idText);
4315  ao2_unlock(s->session);
4316  } else {
4318  ast_debug(1, "Abandoning event request!\n");
4319  }
4320 
4321  return 0;
4322 }
4323 
4324 static int action_listcommands(struct mansession *s, const struct message *m)
4325 {
4326  struct manager_action *cur;
4328 
4329  astman_start_ack(s, m);
4331  AST_RWLIST_TRAVERSE(&actions, cur, list) {
4332  if ((s->session->writeperm & cur->authority) || cur->authority == 0) {
4333  astman_append(s, "%s: %s (Priv: %s)\r\n",
4334  cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
4335  }
4336  }
4338  astman_append(s, "\r\n");
4339 
4340  return 0;
4341 }
4342 
4343 static int action_events(struct mansession *s, const struct message *m)
4344 {
4345  const char *mask = astman_get_header(m, "EventMask");
4346  int res, x;
4347  const char *id = astman_get_header(m, "ActionID");
4348  char id_text[256];
4349 
4350  if (!ast_strlen_zero(id)) {
4351  snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
4352  } else {
4353  id_text[0] = '\0';
4354  }
4355 
4356  res = set_eventmask(s, mask);
4357  if (broken_events_action) {
4358  /* if this option is set we should not return a response on
4359  * error, or when all events are set */
4360 
4361  if (res > 0) {
4362  for (x = 0; x < ARRAY_LEN(perms); x++) {
4363  if (!strcasecmp(perms[x].label, "all") && res == perms[x].num) {
4364  return 0;
4365  }
4366  }
4367  astman_append(s, "Response: Success\r\n%s"
4368  "Events: On\r\n\r\n", id_text);
4369  } else if (res == 0)
4370  astman_append(s, "Response: Success\r\n%s"
4371  "Events: Off\r\n\r\n", id_text);
4372  return 0;
4373  }
4374 
4375  if (res > 0)
4376  astman_append(s, "Response: Success\r\n%s"
4377  "Events: On\r\n\r\n", id_text);
4378  else if (res == 0)
4379  astman_append(s, "Response: Success\r\n%s"
4380  "Events: Off\r\n\r\n", id_text);
4381  else
4382  astman_send_error(s, m, "Invalid event mask");
4383 
4384  return 0;
4385 }
4386 
4387 static int action_logoff(struct mansession *s, const struct message *m)
4388 {
4389  astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
4390  return -1;
4391 }
4392 
4393 static int action_login(struct mansession *s, const struct message *m)
4394 {
4395 
4396  /* still authenticated - don't process again */
4397  if (s->session->authenticated) {
4398  astman_send_ack(s, m, "Already authenticated");
4399  return 0;
4400  }
4401 
4402  if (authenticate(s, m)) {
4403  sleep(1);
4404  astman_send_error(s, m, "Authentication failed");
4405  return -1;
4406  }
4407  s->session->authenticated = 1;
4409  if (manager_displayconnects(s->session)) {
4410  ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_sockaddr_stringify_addr(&s->session->addr));
4411  }
4412  astman_send_ack(s, m, "Authentication accepted");
4417  const char *cat_str = authority_to_str(EVENT_FLAG_SYSTEM, &auth);
4418  long uptime = 0;
4419  long lastreloaded = 0;
4420  struct timeval tmp;
4421  struct timeval curtime = ast_tvnow();
4422 
4423  if (ast_startuptime.tv_sec) {
4424  tmp = ast_tvsub(curtime, ast_startuptime);
4425  uptime = tmp.tv_sec;
4426  }
4427 
4428  if (ast_lastreloadtime.tv_sec) {
4429  tmp = ast_tvsub(curtime, ast_lastreloadtime);
4430  lastreloaded = tmp.tv_sec;
4431  }
4432 
4433  astman_append(s, "Event: FullyBooted\r\n"
4434  "Privilege: %s\r\n"
4435  "Uptime: %ld\r\n"
4436  "LastReload: %ld\r\n"
4437  "Status: Fully Booted\r\n\r\n", cat_str, uptime, lastreloaded);
4438  }
4439  return 0;
4440 }
4441 
4442 static int action_challenge(struct mansession *s, const struct message *m)
4443 {
4444  const char *authtype = astman_get_header(m, "AuthType");
4445 
4446  if (!strcasecmp(authtype, "MD5")) {
4447  if (ast_strlen_zero(s->session->challenge)) {
4448  snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
4449  }
4450  mansession_lock(s);
4451  astman_start_ack(s, m);
4452  astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
4453  mansession_unlock(s);
4454  } else {
4455  astman_send_error(s, m, "Must specify AuthType");
4456  }
4457  return 0;
4458 }
4459 
4460 static int action_hangup(struct mansession *s, const struct message *m)
4461 {
4462  struct ast_channel *c = NULL;
4463  int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
4464  const char *id = astman_get_header(m, "ActionID");
4465  const char *name_or_regex = astman_get_header(m, "Channel");
4466  const char *cause = astman_get_header(m, "Cause");
4467  char idText[256];
4468  regex_t regexbuf;
4469  struct ast_channel_iterator *iter = NULL;
4470  struct ast_str *regex_string;
4471  int channels_matched = 0;
4472 
4473  if (ast_strlen_zero(name_or_regex)) {
4474  astman_send_error(s, m, "No channel specified");
4475  return 0;
4476  }
4477 
4478  if (!ast_strlen_zero(id)) {
4479  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
4480  } else {
4481  idText[0] = '\0';
4482  }
4483 
4484  if (!ast_strlen_zero(cause)) {
4485  char *endptr;
4486  causecode = strtol(cause, &endptr, 10);
4487  if (causecode < 0 || causecode > 127 || *endptr != '\0') {
4488  ast_log(LOG_NOTICE, "Invalid 'Cause: %s' in manager action Hangup\n", cause);
4489  /* keep going, better to hangup without cause than to not hang up at all */
4490  causecode = 0; /* do not set channel's hangupcause */
4491  }
4492  }
4493 
4494  /************************************************/
4495  /* Regular explicit match channel byname hangup */
4496 
4497  if (name_or_regex[0] != '/') {
4498  if (!(c = ast_channel_get_by_name(name_or_regex))) {
4499  ast_log(LOG_NOTICE, "Request to hangup non-existent channel: %s\n",
4500  name_or_regex);
4501  astman_send_error(s, m, "No such channel");
4502  return 0;
4503  }
4504 
4505  ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
4506  (s->session->managerid ? "HTTP " : ""),
4507  s->session->username,
4509  ast_channel_name(c));
4510 
4512  c = ast_channel_unref(c);
4513 
4514  astman_send_ack(s, m, "Channel Hungup");
4515 
4516  return 0;
4517  }
4518 
4519  /***********************************************/
4520  /* find and hangup any channels matching regex */
4521 
4522  regex_string = ast_str_create(strlen(name_or_regex));
4523  if (!regex_string) {
4524  astman_send_error(s, m, "Memory Allocation Failure");
4525  return 0;
4526  }
4527 
4528  /* Make "/regex/" into "regex" */
4529  if (ast_regex_string_to_regex_pattern(name_or_regex, &regex_string) != 0) {
4530  astman_send_error(s, m, "Regex format invalid, Channel param should be /regex/");
4531  ast_free(regex_string);
4532  return 0;
4533  }
4534 
4535  /* if regex compilation fails, hangup fails */
4536  if (regcomp(&regexbuf, ast_str_buffer(regex_string), REG_EXTENDED | REG_NOSUB)) {
4537  astman_send_error_va(s, m, "Regex compile failed on: %s", name_or_regex);
4538  ast_free(regex_string);
4539  return 0;
4540  }
4541 
4542  astman_send_listack(s, m, "Channels hung up will follow", "start");
4543 
4545  if (iter) {
4546  for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
4547  if (regexec(&regexbuf, ast_channel_name(c), 0, NULL, 0)) {
4548  continue;
4549  }
4550 
4551  ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
4552  (s->session->managerid ? "HTTP " : ""),
4553  s->session->username,
4555  ast_channel_name(c));
4556 
4558  channels_matched++;
4559 
4560  astman_append(s,
4561  "Event: ChannelHungup\r\n"
4562  "Channel: %s\r\n"
4563  "%s"
4564  "\r\n", ast_channel_name(c), idText);
4565  }
4567  }
4568 
4569  regfree(&regexbuf);
4570  ast_free(regex_string);
4571 
4572  astman_send_list_complete(s, m, "ChannelsHungupListComplete", channels_matched);
4573 
4574  return 0;
4575 }
4576 
4577 static int action_setvar(struct mansession *s, const struct message *m)
4578 {
4579  struct ast_channel *c = NULL;
4580  const char *name = astman_get_header(m, "Channel");
4581  const char *varname = astman_get_header(m, "Variable");
4582  const char *varval = astman_get_header(m, "Value");
4583  int res = 0;
4584 
4585  if (ast_strlen_zero(varname)) {
4586  astman_send_error(s, m, "No variable specified");
4587  return 0;
4588  }
4589 
4590  if (!ast_strlen_zero(name)) {
4591  if (!(c = ast_channel_get_by_name(name))) {
4592  astman_send_error(s, m, "No such channel");
4593  return 0;
4594  }
4595  }
4596 
4597  res = pbx_builtin_setvar_helper(c, varname, S_OR(varval, ""));
4598 
4599  if (c) {
4600  c = ast_channel_unref(c);
4601  }
4602  if (res == 0) {
4603  astman_send_ack(s, m, "Variable Set");
4604  } else {
4605  astman_send_error(s, m, "Variable not set");
4606  }
4607  return 0;
4608 }
4609 
4610 static int action_getvar(struct mansession *s, const struct message *m)
4611 {
4612  struct ast_channel *c = NULL;
4613  const char *name = astman_get_header(m, "Channel");
4614  const char *varname = astman_get_header(m, "Variable");
4615  char *varval;
4616  char workspace[1024];
4617 
4618  if (ast_strlen_zero(varname)) {
4619  astman_send_error(s, m, "No variable specified");
4620  return 0;
4621  }
4622 
4623  /* We don't want users with insufficient permissions using certain functions. */
4625  astman_send_error(s, m, "GetVar Access Forbidden: Variable");
4626  return 0;
4627  }
4628 
4629  if (!ast_strlen_zero(name)) {
4630  if (!(c = ast_channel_get_by_name(name))) {
4631  astman_send_error(s, m, "No such channel");
4632  return 0;
4633  }
4634  }
4635 
4636  workspace[0] = '\0';
4637  if (varname[strlen(varname) - 1] == ')') {
4638  if (!c) {
4640  if (c) {
4641  ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
4642  } else
4643  ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
4644  } else {
4645  ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
4646  }
4647  varval = workspace;
4648  } else {
4649  pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
4650  }
4651 
4652  if (c) {
4653  c = ast_channel_unref(c);
4654  }
4655 
4656  astman_start_ack(s, m);
4657  astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, S_OR(varval, ""));
4658 
4659  return 0;
4660 }
4661 
4662 static void generate_status(struct mansession *s, struct ast_channel *chan, char **vars, int varc, int all_variables, char *id_text, int *count)
4663 {
4664  struct timeval now;
4665  long elapsed_seconds;
4666  struct ast_bridge *bridge;
4667  RAII_VAR(struct ast_str *, variable_str, NULL, ast_free);
4668  struct ast_str *write_transpath = ast_str_alloca(256);
4669  struct ast_str *read_transpath = ast_str_alloca(256);
4670  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
4671  struct ast_party_id effective_id;
4672  int i;
4673  RAII_VAR(struct ast_channel_snapshot *, snapshot,
4675  ao2_cleanup);
4676  RAII_VAR(struct ast_str *, snapshot_str, NULL, ast_free);
4677 
4678  if (!snapshot) {
4679  return;
4680  }
4681 
4682  snapshot_str = ast_manager_build_channel_state_string(snapshot);
4683  if (!snapshot_str) {
4684  return;
4685  }
4686 
4687  if (all_variables) {
4688  variable_str = ast_str_create(2048);
4689  } else {
4690  variable_str = ast_str_create(1024);
4691  }
4692  if (!variable_str) {
4693  return;
4694  }
4695 
4696  now = ast_tvnow();
4697  elapsed_seconds = ast_tvdiff_sec(now, ast_channel_creationtime(chan));
4698 
4699  /* Even if all_variables has been specified, explicitly requested variables
4700  * may be global variables or dialplan functions */
4701  for (i = 0; i < varc; i++) {
4702  char valbuf[512], *ret = NULL;
4703 
4704  if (vars[i][strlen(vars[i]) - 1] == ')') {
4705  if (ast_func_read(chan, vars[i], valbuf, sizeof(valbuf)) < 0) {
4706  valbuf[0] = '\0';
4707  }
4708  ret = valbuf;
4709  } else {
4710  pbx_retrieve_variable(chan, vars[i], &ret, valbuf, sizeof(valbuf), NULL);
4711  }
4712 
4713  ast_str_append(&variable_str, 0, "Variable: %s=%s\r\n", vars[i], ret);
4714  }
4715 
4716  /* Walk all channel variables and add them */
4717  if (all_variables) {
4718  struct ast_var_t *variables;
4719 
4720  AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
4721  ast_str_append(&variable_str, 0, "Variable: %s=%s\r\n",
4722  ast_var_name(variables), ast_var_value(variables));
4723  }
4724  }
4725 
4726  bridge = ast_channel_get_bridge(chan);
4727  effective_id = ast_channel_connected_effective_id(chan);
4728 
4729  astman_append(s,
4730  "Event: Status\r\n"
4731  "Privilege: Call\r\n"
4732  "%s"
4733  "Type: %s\r\n"
4734  "DNID: %s\r\n"
4735  "EffectiveConnectedLineNum: %s\r\n"
4736  "EffectiveConnectedLineName: %s\r\n"
4737  "TimeToHangup: %ld\r\n"
4738  "BridgeID: %s\r\n"
4739  "Application: %s\r\n"
4740  "Data: %s\r\n"
4741  "Nativeformats: %s\r\n"
4742  "Readformat: %s\r\n"
4743  "Readtrans: %s\r\n"
4744  "Writeformat: %s\r\n"
4745  "Writetrans: %s\r\n"
4746  "Callgroup: %llu\r\n"
4747  "Pickupgroup: %llu\r\n"
4748  "Seconds: %ld\r\n"
4749  "%s"
4750  "%s"
4751  "\r\n",
4752  ast_str_buffer(snapshot_str),
4753  ast_channel_tech(chan)->type,
4754  S_OR(ast_channel_dialed(chan)->number.str, ""),
4755  S_COR(effective_id.number.valid, effective_id.number.str, "<unknown>"),
4756  S_COR(effective_id.name.valid, effective_id.name.str, "<unknown>"),
4757  (long)ast_channel_whentohangup(chan)->tv_sec,
4758  bridge ? bridge->uniqueid : "",
4759  ast_channel_appl(chan),
4760  ast_channel_data(chan),
4763  ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath),
4765  ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath),
4766  ast_channel_callgroup(chan),
4768  (long)elapsed_seconds,
4769  ast_str_buffer(variable_str),
4770  id_text);
4771  ++*count;
4772 
4773  ao2_cleanup(bridge);
4774 }
4775 
4776 /*! \brief Manager "status" command to show channels */
4777 static int action_status(struct mansession *s, const struct message *m)
4778 {
4779  const char *name = astman_get_header(m, "Channel");
4780  const char *chan_variables = astman_get_header(m, "Variables");
4781  const char *all_chan_variables = astman_get_header(m, "AllVariables");
4782  int all_variables = 0;
4783  const char *id = astman_get_header(m, "ActionID");
4784  char *variables = ast_strdupa(S_OR(chan_variables, ""));
4785  struct ast_channel *chan;
4786  int channels = 0;
4787  int all = ast_strlen_zero(name); /* set if we want all channels */
4788  char id_text[256];
4789  struct ast_channel_iterator *it_chans = NULL;
4790  AST_DECLARE_APP_ARGS(vars,
4791  AST_APP_ARG(name)[100];
4792  );
4793 
4794  if (!ast_strlen_zero(all_chan_variables)) {
4795  all_variables = ast_true(all_chan_variables);
4796  }
4797 
4799  astman_send_error(s, m, "Status Access Forbidden: Variables");
4800  return 0;
4801  }
4802 
4803  if (all) {
4804  if (!(it_chans = ast_channel_iterator_all_new())) {
4805  astman_send_error(s, m, "Memory Allocation Failure");
4806  return 1;
4807  }
4808  chan = ast_channel_iterator_next(it_chans);
4809  } else {
4810  chan = ast_channel_get_by_name(name);
4811  if (!chan) {
4812  astman_send_error(s, m, "No such channel");
4813  return 0;
4814  }
4815  }
4816 
4817  astman_send_listack(s, m, "Channel status will follow", "start");
4818 
4819  if (!ast_strlen_zero(id)) {
4820  snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
4821  } else {
4822  id_text[0] = '\0';
4823  }
4824 
4825  if (!ast_strlen_zero(chan_variables)) {
4826  AST_STANDARD_APP_ARGS(vars, variables);
4827  }
4828 
4829  /* if we look by name, we break after the first iteration */
4830  for (; chan; all ? chan = ast_channel_iterator_next(it_chans) : 0) {
4831  ast_channel_lock(chan);
4832 
4833  generate_status(s, chan, vars.name, vars.argc, all_variables, id_text, &channels);
4834 
4835  ast_channel_unlock(chan);
4836  chan = ast_channel_unref(chan);
4837  }
4838 
4839  if (it_chans) {
4840  ast_channel_iterator_destroy(it_chans);
4841  }
4842 
4843  astman_send_list_complete_start(s, m, "StatusComplete", channels);
4844  astman_append(s, "Items: %d\r\n", channels);
4846 
4847  return 0;
4848 }
4849 
4850 /*!
4851  * \brief Queue a given read action containing a payload onto a channel
4852  *
4853  * This queues a READ_ACTION control frame that contains a given "payload", or
4854  * data to be triggered and handled on the channel's read side. This ensures
4855  * the "action" is handled by the channel's media reading thread.
4856  *
4857  * \param chan The channel to queue the action on
4858  * \param payload The read action's payload
4859  * \param payload_size The size of the given payload
4860  * \param action The type of read action to queue
4861  *
4862  * \return -1 on error, 0 on success
4863  */
4864 static int queue_read_action_payload(struct ast_channel *chan, const unsigned char *payload,
4865  size_t payload_size, enum ast_frame_read_action action)
4866 {
4867  struct ast_control_read_action_payload *obj;
4868  size_t obj_size;
4869  int res;
4870 
4871  obj_size = payload_size + sizeof(*obj);
4872 
4873  obj = ast_malloc(obj_size);
4874  if (!obj) {
4875  return -1;
4876  }
4877 
4878  obj->action = action;
4879  obj->payload_size = payload_size;
4880  memcpy(obj->payload, payload, payload_size);
4881 
4882  res = ast_queue_control_data(chan, AST_CONTROL_READ_ACTION, obj, obj_size);
4883 
4884  ast_free(obj);
4885  return res;
4886 }
4887 
4888 /*!
4889  * \brief Queue a read action to send a text message
4890  *
4891  * \param chan The channel to queue the action on
4892  * \param body The body of the message
4893  *
4894  * \return -1 on error, 0 on success
4895  */
4896 static int queue_sendtext(struct ast_channel *chan, const char *body)
4897 {
4898  return queue_read_action_payload(chan, (const unsigned char *)body,
4899  strlen(body) + 1, AST_FRAME_READ_ACTION_SEND_TEXT);
4900 }
4901 
4902 /*!
4903  * \brief Queue a read action to send a text data message
4904  *
4905  * \param chan The channel to queue the action on
4906  * \param body The body of the message
4907  * \param content_type The message's content type
4908  *
4909  * \return -1 on error, 0 on success
4910  */
4911 static int queue_sendtext_data(struct ast_channel *chan, const char *body,
4912  const char *content_type)
4913 {
4914  int res;
4915  struct ast_msg_data *obj;
4916 
4918  NULL, NULL, content_type, body);
4919  if (!obj) {
4920  return -1;
4921  }
4922 
4923  res = queue_read_action_payload(chan, (const unsigned char *)obj,
4925 
4926  ast_free(obj);
4927  return res;
4928 }
4929 
4930 static int action_sendtext(struct mansession *s, const struct message *m)
4931 {
4932  struct ast_channel *c;
4933  const char *name = astman_get_header(m, "Channel");
4934  const char *textmsg = astman_get_header(m, "Message");
4935  const char *content_type = astman_get_header(m, "Content-Type");
4936  int res;
4937 
4938  if (ast_strlen_zero(name)) {
4939  astman_send_error(s, m, "No channel specified");
4940  return 0;
4941  }
4942 
4943  if (ast_strlen_zero(textmsg)) {
4944  astman_send_error(s, m, "No Message specified");
4945  return 0;
4946  }
4947 
4948  c = ast_channel_get_by_name(name);
4949  if (!c) {
4950  astman_send_error(s, m, "No such channel");
4951  return 0;
4952  }
4953 
4954  /*
4955  * If the "extra" data is not available, then send using "string" only.
4956  * Doing such maintains backward compatibilities.
4957  */
4958  res = ast_strlen_zero(content_type) ? queue_sendtext(c, textmsg) :
4959  queue_sendtext_data(c, textmsg, content_type);
4960 
4961  ast_channel_unref(c);
4962 
4963  if (res >= 0) {
4964  astman_send_ack(s, m, "Success");
4965  } else {
4966  astman_send_error(s, m, "Failure");
4967  }
4968 
4969  return 0;
4970 }
4971 
4972 /*! \brief action_redirect: The redirect manager command */
4973 static int action_redirect(struct mansession *s, const struct message *m)
4974 {
4975  char buf[256];
4976  const char *name = astman_get_header(m, "Channel");
4977  const char *name2 = astman_get_header(m, "ExtraChannel");
4978  const char *exten = astman_get_header(m, "Exten");
4979  const char *exten2 = astman_get_header(m, "ExtraExten");
4980  const char *context = astman_get_header(m, "Context");
4981  const char *context2 = astman_get_header(m, "ExtraContext");
4982  const char *priority = astman_get_header(m, "Priority");
4983  const char *priority2 = astman_get_header(m, "ExtraPriority");
4984  struct ast_channel *chan;
4985  struct ast_channel *chan2;
4986  int pi = 0;
4987  int pi2 = 0;
4988  int res;
4989  int chan1_wait = 0;
4990  int chan2_wait = 0;
4991 
4992  if (ast_strlen_zero(name)) {
4993  astman_send_error(s, m, "Channel not specified");
4994  return 0;
4995  }
4996 
4997  if (ast_strlen_zero(context)) {
4998  astman_send_error(s, m, "Context not specified");
4999  return 0;
5000  }
5001  if (ast_strlen_zero(exten)) {
5002  astman_send_error(s, m, "Exten not specified");
5003  return 0;
5004  }
5005  if (ast_strlen_zero(priority)) {
5006  astman_send_error(s, m, "Priority not specified");
5007  return 0;
5008  }
5009  if (sscanf(priority, "%30d", &pi) != 1) {
5010  pi = ast_findlabel_extension(NULL, context, exten, priority, NULL);
5011  }
5012  if (pi < 1) {
5013  astman_send_error(s, m, "Priority is invalid");
5014  return 0;
5015  }
5016 
5017  if (!ast_strlen_zero(name2) && !ast_strlen_zero(context2)) {
5018  /* We have an ExtraChannel and an ExtraContext */
5019  if (ast_strlen_zero(exten2)) {
5020  astman_send_error(s, m, "ExtraExten not specified");
5021  return 0;
5022  }
5023  if (ast_strlen_zero(priority2)) {
5024  astman_send_error(s, m, "ExtraPriority not specified");
5025  return 0;
5026  }
5027  if (sscanf(priority2, "%30d", &pi2) != 1) {
5028  pi2 = ast_findlabel_extension(NULL, context2, exten2, priority2, NULL);
5029  }
5030  if (pi2 < 1) {
5031  astman_send_error(s, m, "ExtraPriority is invalid");
5032  return 0;
5033  }
5034  }
5035 
5036  chan = ast_channel_get_by_name(name);
5037  if (!chan) {
5038  snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
5039  astman_send_error(s, m, buf);
5040  return 0;
5041  }
5042  if (ast_check_hangup_locked(chan)) {
5043  astman_send_error(s, m, "Redirect failed, channel not up.");
5044  chan = ast_channel_unref(chan);
5045  return 0;
5046  }
5047 
5048  if (ast_strlen_zero(name2)) {
5049  /* Single channel redirect in progress. */
5050  res = ast_async_goto(chan, context, exten, pi);
5051  if (!res) {
5052  astman_send_ack(s, m, "Redirect successful");
5053  } else {
5054  astman_send_error(s, m, "Redirect failed");
5055  }
5056  chan = ast_channel_unref(chan);
5057  return 0;
5058  }
5059 
5060  chan2 = ast_channel_get_by_name(name2);
5061  if (!chan2) {
5062  snprintf(buf, sizeof(buf), "ExtraChannel does not exist: %s", name2);
5063  astman_send_error(s, m, buf);
5064  chan = ast_channel_unref(chan);
5065  return 0;
5066  }
5067  if (ast_check_hangup_locked(chan2)) {
5068  astman_send_error(s, m, "Redirect failed, extra channel not up.");
5069  chan2 = ast_channel_unref(chan2);
5070  chan = ast_channel_unref(chan);
5071  return 0;
5072  }
5073 
5074  /* Dual channel redirect in progress. */
5075  ast_channel_lock(chan);
5076  if (ast_channel_is_bridged(chan)) {
5078  chan1_wait = 1;
5079  }
5080  ast_channel_unlock(chan);
5081 
5082  ast_channel_lock(chan2);
5083  if (ast_channel_is_bridged(chan2)) {
5085  chan2_wait = 1;
5086  }
5087  ast_channel_unlock(chan2);
5088 
5089  res = ast_async_goto(chan, context, exten, pi);
5090  if (!res) {
5091  if (!ast_strlen_zero(context2)) {
5092  res = ast_async_goto(chan2, context2, exten2, pi2);
5093  } else {
5094  res = ast_async_goto(chan2, context, exten, pi);
5095  }
5096  if (!res) {
5097  astman_send_ack(s, m, "Dual Redirect successful");
5098  } else {
5099  astman_send_error(s, m, "Secondary redirect failed");
5100  }
5101  } else {
5102  astman_send_error(s, m, "Redirect failed");
5103  }
5104 
5105  /* Release the bridge wait. */
5106  if (chan1_wait) {
5108  }
5109  if (chan2_wait) {
5111  }
5112 
5113  chan2 = ast_channel_unref(chan2);
5114  chan = ast_channel_unref(chan);
5115  return 0;
5116 }
5117 
5118 static int action_blind_transfer(struct mansession *s, const struct message *m)
5119 {
5120  const char *name = astman_get_header(m, "Channel");
5121  const char *exten = astman_get_header(m, "Exten");
5122  const char *context = astman_get_header(m, "Context");
5123  struct ast_channel *chan;
5124 
5125  if (ast_strlen_zero(name)) {
5126  astman_send_error(s, m, "No channel specified");
5127  return 0;
5128  }
5129 
5130  if (ast_strlen_zero(exten)) {
5131  astman_send_error(s, m, "No extension specified");
5132  return 0;
5133  }
5134 
5135  chan = ast_channel_get_by_name(name);
5136  if (!chan) {
5137  astman_send_error(s, m, "Channel specified does not exist");
5138  return 0;
5139  }
5140 
5141  if (ast_strlen_zero(context)) {
5142  context = ast_channel_context(chan);
5143  }
5144 
5145  switch (ast_bridge_transfer_blind(1, chan, exten, context, NULL, NULL)) {
5147  astman_send_error(s, m, "Transfer not permitted");
5148  break;
5150  astman_send_error(s, m, "Transfer invalid");
5151  break;
5153  astman_send_error(s, m, "Transfer failed");
5154  break;
5156  astman_send_ack(s, m, "Transfer succeeded");
5157  break;
5158  }
5159 
5160  ast_channel_unref(chan);
5161  return 0;
5162 }
5163 
5164 static int action_atxfer(struct mansession *s, const struct message *m)
5165 {
5166  const char *name = astman_get_header(m, "Channel");
5167  const char *exten = astman_get_header(m, "Exten");
5168  const char *context = astman_get_header(m, "Context");
5169  struct ast_channel *chan = NULL;
5170  char feature_code[AST_FEATURE_MAX_LEN];
5171  const char *digit;
5172 
5173  if (ast_strlen_zero(name)) {
5174  astman_send_error(s, m, "No channel specified");
5175  return 0;
5176  }
5177  if (ast_strlen_zero(exten)) {
5178  astman_send_error(s, m, "No extension specified");
5179  return 0;
5180  }
5181 
5182  if (!(chan = ast_channel_get_by_name(name))) {
5183  astman_send_error(s, m, "Channel specified does not exist");
5184  return 0;
5185  }
5186 
5187  ast_channel_lock(chan);
5188  if (ast_get_builtin_feature(chan, "atxfer", feature_code, sizeof(feature_code)) ||
5189  ast_strlen_zero(feature_code)) {
5190  ast_channel_unlock(chan);
5191  astman_send_error(s, m, "No attended transfer feature code found");
5192  ast_channel_unref(chan);
5193  return 0;
5194  }
5195  ast_channel_unlock(chan);
5196 
5197  if (!ast_strlen_zero(context)) {
5198  pbx_builtin_setvar_helper(chan, "TRANSFER_CONTEXT", context);
5199  }
5200 
5201  for (digit = feature_code; *digit; ++digit) {
5202  struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
5203  ast_queue_frame(chan, &f);
5204  }
5205 
5206  for (digit = exten; *digit; ++digit) {
5207  struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
5208  ast_queue_frame(chan, &f);
5209  }
5210 
5211  chan = ast_channel_unref(chan);
5212 
5213  astman_send_ack(s, m, "Atxfer successfully queued");
5214 
5215  return 0;
5216 }
5217 
5218 static int action_cancel_atxfer(struct mansession *s, const struct message *m)
5219 {
5220  const char *name = astman_get_header(m, "Channel");
5221  struct ast_channel *chan = NULL;
5222  char *feature_code;
5223  const char *digit;
5224 
5225  if (ast_strlen_zero(name)) {
5226  astman_send_error(s, m, "No channel specified");
5227  return 0;
5228  }
5229 
5230  if (!(chan = ast_channel_get_by_name(name))) {
5231  astman_send_error(s, m, "Channel specified does not exist");
5232  return 0;
5233  }
5234 
5235  ast_channel_lock(chan);
5236  feature_code = ast_get_chan_features_atxferabort(chan);
5237  ast_channel_unlock(chan);
5238 
5239  if (!feature_code) {
5240  astman_send_error(s, m, "No disconnect feature code found");
5241  ast_channel_unref(chan);
5242  return 0;
5243  }
5244 
5245  for (digit = feature_code; *digit; ++digit) {
5246  struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
5247  ast_queue_frame(chan, &f);
5248  }
5249  ast_free(feature_code);
5250 
5251  chan = ast_channel_unref(chan);
5252 
5253  astman_send_ack(s, m, "CancelAtxfer successfully queued");
5254 
5255  return 0;
5256 }
5257 
5258 
5259 static int check_blacklist(const char *cmd)
5260 {
5261  char *cmd_copy, *cur_cmd;
5262  char *cmd_words[AST_MAX_CMD_LEN] = { NULL, };
5263  int i;
5264 
5265  cmd_copy = ast_strdupa(cmd);
5266  for (i = 0; i < MAX_BLACKLIST_CMD_LEN && (cur_cmd = strsep(&cmd_copy, " ")); i++) {
5267  cur_cmd = ast_strip(cur_cmd);
5268  if (ast_strlen_zero(cur_cmd)) {
5269  i--;
5270  continue;
5271  }
5272 
5273  cmd_words[i] = cur_cmd;
5274  }
5275 
5276  for (i = 0; i < ARRAY_LEN(command_blacklist); i++) {
5277  int j, match = 1;
5278 
5279  for (j = 0; command_blacklist[i].words[j]; j++) {
5280  if (ast_strlen_zero(cmd_words[j]) || strcasecmp(cmd_words[j], command_blacklist[i].words[j])) {
5281  match = 0;
5282  break;
5283  }
5284  }
5285 
5286  if (match) {
5287  return 1;
5288  }
5289  }
5290 
5291  return 0;
5292 }
5293 
5294 /*! \brief Manager command "command" - execute CLI command */
5295 static int action_command(struct mansession *s, const struct message *m)
5296 {
5297  const char *cmd = astman_get_header(m, "Command");
5298  char *buf = NULL, *final_buf = NULL, *delim, *output;
5299  char template[] = "/tmp/ast-ami-XXXXXX"; /* template for temporary file */
5300  int fd, ret;
5301  off_t len;
5302 
5303  if (ast_strlen_zero(cmd)) {
5304  astman_send_error(s, m, "No command provided");
5305  return 0;
5306  }
5307 
5308  if (check_blacklist(cmd)) {
5309  astman_send_error(s, m, "Command blacklisted");
5310  return 0;
5311  }
5312 
5313  if ((fd = mkstemp(template)) < 0) {
5314  astman_send_error_va(s, m, "Failed to create temporary file: %s", strerror(errno));
5315  return 0;
5316  }
5317 
5318  ret = ast_cli_command(fd, cmd);
5319  astman_send_response_full(s, m, ret == RESULT_SUCCESS ? "Success" : "Error", MSG_MOREDATA, NULL);
5320 
5321  /* Determine number of characters available */
5322  if ((len = lseek(fd, 0, SEEK_END)) < 0) {
5323  astman_append(s, "Message: Failed to determine number of characters: %s\r\n", strerror(errno));
5324  goto action_command_cleanup;
5325  }
5326 
5327  /* This has a potential to overflow the stack. Hence, use the heap. */
5328  buf = ast_malloc(len + 1);
5329  final_buf = ast_malloc(len + 1);
5330 
5331  if (!buf || !final_buf) {
5332  astman_append(s, "Message: Memory allocation failure\r\n");
5333  goto action_command_cleanup;
5334  }
5335 
5336  if (lseek(fd, 0, SEEK_SET) < 0) {
5337  astman_append(s, "Message: Failed to set position on temporary file: %s\r\n", strerror(errno));
5338  goto action_command_cleanup;
5339  }
5340 
5341  if (read(fd, buf, len) < 0) {
5342  astman_append(s, "Message: Failed to read from temporary file: %s\r\n", strerror(errno));
5343  goto action_command_cleanup;
5344  }
5345 
5346  buf[len] = '\0';
5347  term_strip(final_buf, buf, len);
5348  final_buf[len] = '\0';
5349 
5350  /* Trim trailing newline */
5351  if (len && final_buf[len - 1] == '\n') {
5352  final_buf[len - 1] = '\0';
5353  }
5354 
5355  astman_append(s, "Message: Command output follows\r\n");
5356 
5357  delim = final_buf;
5358  while ((output = strsep(&delim, "\n"))) {
5359  astman_append(s, "Output: %s\r\n", output);
5360  }
5361 
5362 action_command_cleanup:
5363  astman_append(s, "\r\n");
5364 
5365  close(fd);
5366  unlink(template);
5367 
5368  ast_free(buf);
5369  ast_free(final_buf);
5370 
5371  return 0;
5372 }
5373 
5374 /*! \brief helper function for originate */
5376  int timeout;
5377  struct ast_format_cap *cap; /*!< Codecs used for a call */
5380  AST_STRING_FIELD(tech);
5381  /*! data can contain a channel name, extension number, username, password, etc. */
5382  AST_STRING_FIELD(data);
5384  AST_STRING_FIELD(appdata);
5389  AST_STRING_FIELD(idtext);
5390  AST_STRING_FIELD(account);
5391  AST_STRING_FIELD(channelid);
5392  AST_STRING_FIELD(otherchannelid);
5393  );
5394  int priority;
5396 };
5397 
5398 /*!
5399  * \internal
5400  *
5401  * \param doomed Struct to destroy.
5402  *
5403  * \return Nothing
5404  */
5406 {
5407  ao2_cleanup(doomed->cap);
5408  ast_variables_destroy(doomed->vars);
5410  ast_free(doomed);
5411 }
5412 
5413 static void *fast_originate(void *data)
5414 {
5415  struct fast_originate_helper *in = data;
5416  int res;
5417  int reason = 0;
5418  struct ast_channel *chan = NULL, *chans[1];
5419  char requested_channel[AST_CHANNEL_NAME];
5420  struct ast_assigned_ids assignedids = {
5421  .uniqueid = in->channelid,
5422  .uniqueid2 = in->otherchannelid
5423  };
5424 
5425  if (!ast_strlen_zero(in->app)) {
5426  res = ast_pbx_outgoing_app(in->tech, in->cap, in->data,
5427  in->timeout, in->app, in->appdata, &reason,
5429  S_OR(in->cid_num, NULL),
5430  S_OR(in->cid_name, NULL),
5431  in->vars, in->account, &chan, &assignedids);
5432  } else {
5433  res = ast_pbx_outgoing_exten(in->tech, in->cap, in->data,
5434  in->timeout, in->context, in->exten, in->priority, &reason,
5436  S_OR(in->cid_num, NULL),
5437  S_OR(in->cid_name, NULL),
5438  in->vars, in->account, &chan, in->early_media, &assignedids);
5439  }
5440 
5441  if (!chan) {
5442  snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
5443  }
5444  /* Tell the manager what happened with the channel */
5445  chans[0] = chan;
5446  if (!ast_strlen_zero(in->app)) {
5447  ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans,
5448  "%s"
5449  "Response: %s\r\n"
5450  "Channel: %s\r\n"
5451  "Application: %s\r\n"
5452  "Data: %s\r\n"
5453  "Reason: %d\r\n"
5454  "Uniqueid: %s\r\n"
5455  "CallerIDNum: %s\r\n"
5456  "CallerIDName: %s\r\n",
5457  in->idtext, res ? "Failure" : "Success",
5458  chan ? ast_channel_name(chan) : requested_channel,
5459  in->app, in->appdata, reason,
5460  chan ? ast_channel_uniqueid(chan) : S_OR(in->channelid, "<unknown>"),
5461  S_OR(in->cid_num, "<unknown>"),
5462  S_OR(in->cid_name, "<unknown>")
5463  );
5464  } else {
5465  ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans,
5466  "%s"
5467  "Response: %s\r\n"
5468  "Channel: %s\r\n"
5469  "Context: %s\r\n"
5470  "Exten: %s\r\n"
5471  "Reason: %d\r\n"
5472  "Uniqueid: %s\r\n"
5473  "CallerIDNum: %s\r\n"
5474  "CallerIDName: %s\r\n",
5475  in->idtext, res ? "Failure" : "Success",
5476  chan ? ast_channel_name(chan) : requested_channel,
5477  in->context, in->exten, reason,
5478  chan ? ast_channel_uniqueid(chan) : S_OR(in->channelid, "<unknown>"),
5479  S_OR(in->cid_num, "<unknown>"),
5480  S_OR(in->cid_name, "<unknown>")
5481  );
5482  }
5483 
5484  /* Locked and ref'd by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
5485  if (chan) {
5486  ast_channel_unlock(chan);
5487  ast_channel_unref(chan);
5488  }
5490  return NULL;
5491 }
5492 
5493 static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
5494 {
5495  const char *unitamount;
5496  const char *unittype;
5497  struct ast_str *str = ast_str_alloca(32);
5498 
5499  memset(entry, 0, sizeof(*entry));
5500 
5501  ast_str_set(&str, 0, "UnitAmount(%u)", entry_num);
5502  unitamount = astman_get_header(m, ast_str_buffer(str));
5503 
5504  ast_str_set(&str, 0, "UnitType(%u)", entry_num);
5505  unittype = astman_get_header(m, ast_str_buffer(str));
5506 
5507  if (!ast_strlen_zero(unitamount) && (sscanf(unitamount, "%30u", &entry->amount) == 1)) {
5508  entry->valid_amount = 1;
5509  }
5510 
5511  if (!ast_strlen_zero(unittype) && sscanf(unittype, "%30u", &entry->type) == 1) {
5512  entry->valid_type = 1;
5513  }
5514 
5515  return 0;
5516 }
5517 
5518 static int action_aocmessage(struct mansession *s, const struct message *m)
5519 {
5520  const char *channel = astman_get_header(m, "Channel");
5521  const char *pchannel = astman_get_header(m, "ChannelPrefix");
5522  const char *msgtype = astman_get_header(m, "MsgType");
5523  const char *chargetype = astman_get_header(m, "ChargeType");
5524  const char *currencyname = astman_get_header(m, "CurrencyName");
5525  const char *currencyamount = astman_get_header(m, "CurrencyAmount");
5526  const char *mult = astman_get_header(m, "CurrencyMultiplier");
5527  const char *totaltype = astman_get_header(m, "TotalType");
5528  const char *aocbillingid = astman_get_header(m, "AOCBillingId");
5529  const char *association_id= astman_get_header(m, "ChargingAssociationId");
5530  const char *association_num = astman_get_header(m, "ChargingAssociationNumber");
5531  const char *association_plan = astman_get_header(m, "ChargingAssociationPlan");
5532 
5533  enum ast_aoc_type _msgtype;
5534  enum ast_aoc_charge_type _chargetype;
5536  enum ast_aoc_total_type _totaltype = AST_AOC_TOTAL;
5537  enum ast_aoc_billing_id _billingid = AST_AOC_BILLING_NA;
5538  unsigned int _currencyamount = 0;
5539  int _association_id = 0;
5540  unsigned int _association_plan = 0;
5541  struct ast_channel *chan = NULL;
5542 
5543  struct ast_aoc_decoded *decoded = NULL;
5544  struct ast_aoc_encoded *encoded = NULL;
5545  size_t encoded_size = 0;
5546 
5547  if (ast_strlen_zero(channel) && ast_strlen_zero(pchannel)) {
5548  astman_send_error(s, m, "Channel and PartialChannel are not specified. Specify at least one of these.");
5549  goto aocmessage_cleanup;
5550  }
5551 
5552  if (!(chan = ast_channel_get_by_name(channel)) && !ast_strlen_zero(pchannel)) {
5553  chan = ast_channel_get_by_name_prefix(pchannel, strlen(pchannel));
5554  }
5555 
5556  if (!chan) {
5557  astman_send_error(s, m, "No such channel");
5558  goto aocmessage_cleanup;
5559  }
5560 
5561  if (ast_strlen_zero(msgtype) || (strcasecmp(msgtype, "d") && strcasecmp(msgtype, "e"))) {
5562  astman_send_error(s, m, "Invalid MsgType");
5563  goto aocmessage_cleanup;
5564  }
5565 
5566  if (ast_strlen_zero(chargetype)) {
5567  astman_send_error(s, m, "ChargeType not specified");
5568  goto aocmessage_cleanup;
5569  }
5570 
5571  _msgtype = strcasecmp(msgtype, "d") ? AST_AOC_E : AST_AOC_D;
5572 
5573  if (!strcasecmp(chargetype, "NA")) {
5574  _chargetype = AST_AOC_CHARGE_NA;
5575  } else if (!strcasecmp(chargetype, "Free")) {
5576  _chargetype = AST_AOC_CHARGE_FREE;
5577  } else if (!strcasecmp(chargetype, "Currency")) {
5578  _chargetype = AST_AOC_CHARGE_CURRENCY;
5579  } else if (!strcasecmp(chargetype, "Unit")) {
5580  _chargetype = AST_AOC_CHARGE_UNIT;
5581  } else {
5582  astman_send_error(s, m, "Invalid ChargeType");
5583  goto aocmessage_cleanup;
5584  }
5585 
5586  if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
5587 
5588  if (ast_strlen_zero(currencyamount) || (sscanf(currencyamount, "%30u", &_currencyamount) != 1)) {
5589  astman_send_error(s, m, "Invalid CurrencyAmount, CurrencyAmount is a required when ChargeType is Currency");
5590  goto aocmessage_cleanup;
5591  }
5592 
5593  if (ast_strlen_zero(mult)) {
5594  astman_send_error(s, m, "ChargeMultiplier unspecified, ChargeMultiplier is required when ChargeType is Currency.");
5595  goto aocmessage_cleanup;
5596  } else if (!strcasecmp(mult, "onethousandth")) {
5598  } else if (!strcasecmp(mult, "onehundredth")) {
5599  _mult = AST_AOC_MULT_ONEHUNDREDTH;
5600  } else if (!strcasecmp(mult, "onetenth")) {
5601  _mult = AST_AOC_MULT_ONETENTH;
5602  } else if (!strcasecmp(mult, "one")) {
5603  _mult = AST_AOC_MULT_ONE;
5604  } else if (!strcasecmp(mult, "ten")) {
5605  _mult = AST_AOC_MULT_TEN;
5606  } else if (!strcasecmp(mult, "hundred")) {
5607  _mult = AST_AOC_MULT_HUNDRED;
5608  } else if (!strcasecmp(mult, "thousand")) {
5609  _mult = AST_AOC_MULT_THOUSAND;
5610  } else {
5611  astman_send_error(s, m, "Invalid ChargeMultiplier");
5612  goto aocmessage_cleanup;
5613  }
5614  }
5615 
5616  /* create decoded object and start setting values */
5617  if (!(decoded = ast_aoc_create(_msgtype, _chargetype, 0))) {
5618  astman_send_error(s, m, "Message Creation Failed");
5619  goto aocmessage_cleanup;
5620  }
5621 
5622  if (_msgtype == AST_AOC_D) {
5623  if (!ast_strlen_zero(totaltype) && !strcasecmp(totaltype, "subtotal")) {
5624  _totaltype = AST_AOC_SUBTOTAL;
5625  }
5626 
5627  if (ast_strlen_zero(aocbillingid)) {
5628  /* ignore this is optional */
5629  } else if (!strcasecmp(aocbillingid, "Normal")) {
5630  _billingid = AST_AOC_BILLING_NORMAL;
5631  } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
5632  _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
5633  } else if (!strcasecmp(aocbillingid, "CreditCard")) {
5634  _billingid = AST_AOC_BILLING_CREDIT_CARD;
5635  } else {
5636  astman_send_error(s, m, "Invalid AOC-D AOCBillingId");
5637  goto aocmessage_cleanup;
5638  }
5639  } else {
5640  if (ast_strlen_zero(aocbillingid)) {
5641  /* ignore this is optional */
5642  } else if (!strcasecmp(aocbillingid, "Normal")) {
5643  _billingid = AST_AOC_BILLING_NORMAL;
5644  } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
5645  _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
5646  } else if (!strcasecmp(aocbillingid, "CreditCard")) {
5647  _billingid = AST_AOC_BILLING_CREDIT_CARD;
5648  } else if (!strcasecmp(aocbillingid, "CallFwdUnconditional")) {
5650  } else if (!strcasecmp(aocbillingid, "CallFwdBusy")) {
5651  _billingid = AST_AOC_BILLING_CALL_FWD_BUSY;
5652  } else if (!strcasecmp(aocbillingid, "CallFwdNoReply")) {
5653  _billingid = AST_AOC_BILLING_CALL_FWD_NO_REPLY;
5654  } else if (!strcasecmp(aocbillingid, "CallDeflection")) {
5655  _billingid = AST_AOC_BILLING_CALL_DEFLECTION;
5656  } else if (!strcasecmp(aocbillingid, "CallTransfer")) {
5657  _billingid = AST_AOC_BILLING_CALL_TRANSFER;
5658  } else {
5659  astman_send_error(s, m, "Invalid AOC-E AOCBillingId");
5660  goto aocmessage_cleanup;
5661  }
5662 
5663  if (!ast_strlen_zero(association_id) && (sscanf(association_id, "%30d", &_association_id) != 1)) {
5664  astman_send_error(s, m, "Invalid ChargingAssociationId");
5665  goto aocmessage_cleanup;
5666  }
5667  if (!ast_strlen_zero(association_plan) && (sscanf(association_plan, "%30u", &_association_plan) != 1)) {
5668  astman_send_error(s, m, "Invalid ChargingAssociationPlan");
5669  goto aocmessage_cleanup;
5670  }
5671 
5672  if (_association_id) {
5673  ast_aoc_set_association_id(decoded, _association_id);
5674  } else if (!ast_strlen_zero(association_num)) {
5675  ast_aoc_set_association_number(decoded, association_num, _association_plan);
5676  }
5677  }
5678 
5679  if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
5680  ast_aoc_set_currency_info(decoded, _currencyamount, _mult, ast_strlen_zero(currencyname) ? NULL : currencyname);
5681  } else if (_chargetype == AST_AOC_CHARGE_UNIT) {
5682  struct ast_aoc_unit_entry entry;
5683  int i;
5684 
5685  /* multiple unit entries are possible, lets get them all */
5686  for (i = 0; i < 32; i++) {
5687  if (aocmessage_get_unit_entry(m, &entry, i)) {
5688  break; /* that's the end then */
5689  }
5690 
5691  ast_aoc_add_unit_entry(decoded, entry.valid_amount, entry.amount, entry.valid_type, entry.type);
5692  }
5693 
5694  /* at least one unit entry is required */
5695  if (!i) {
5696  astman_send_error(s, m, "Invalid UnitAmount(0), At least one valid unit entry is required when ChargeType is set to Unit");
5697  goto aocmessage_cleanup;
5698  }
5699 
5700  }
5701 
5702  ast_aoc_set_billing_id(decoded, _billingid);
5703  ast_aoc_set_total_type(decoded, _totaltype);
5704 
5705 
5706  if ((encoded = ast_aoc_encode(decoded, &encoded_size, NULL)) && !ast_indicate_data(chan, AST_CONTROL_AOC, encoded, encoded_size)) {
5707  astman_send_ack(s, m, "AOC Message successfully queued on channel");
5708  } else {
5709  astman_send_error(s, m, "Error encoding AOC message, could not queue onto channel");
5710  }
5711 
5712 aocmessage_cleanup:
5713 
5714  ast_aoc_destroy_decoded(decoded);
5715  ast_aoc_destroy_encoded(encoded);
5716 
5717  if (chan) {
5718  chan = ast_channel_unref(chan);
5719  }
5720  return 0;
5721 }
5722 
5723 static int action_originate(struct mansession *s, const struct message *m)
5724 {
5725  const char *name = astman_get_header(m, "Channel");
5726  const char *exten = astman_get_header(m, "Exten");
5727  const char *context = astman_get_header(m, "Context");
5728  const char *priority = astman_get_header(m, "Priority");
5729  const char *timeout = astman_get_header(m, "Timeout");
5730  const char *callerid = astman_get_header(m, "CallerID");
5731  const char *account = astman_get_header(m, "Account");
5732  const char *app = astman_get_header(m, "Application");
5733  const char *appdata = astman_get_header(m, "Data");
5734  const char *async = astman_get_header(m, "Async");
5735  const char *id = astman_get_header(m, "ActionID");
5736  const char *codecs = astman_get_header(m, "Codecs");
5737  const char *early_media = astman_get_header(m, "Earlymedia");
5738  struct ast_assigned_ids assignedids = {
5739  .uniqueid = astman_get_header(m, "ChannelId"),
5740  .uniqueid2 = astman_get_header(m, "OtherChannelId"),
5741  };
5742  struct ast_variable *vars = NULL;
5743  char *tech, *data;
5744  char *l = NULL, *n = NULL;
5745  int pi = 0;
5746  int res;
5747  int to = 30000;
5748  int reason = 0;
5749  char tmp[256];
5750  char tmp2[256];
5752  pthread_t th;
5753  int bridge_early = 0;
5754 
5755  if (!cap) {
5756  astman_send_error(s, m, "Internal Error. Memory allocation failure.");
5757  return 0;
5758  }
5760 
5761  if ((assignedids.uniqueid && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid))
5762  || (assignedids.uniqueid2 && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid2))) {
5763  astman_send_error_va(s, m, "Uniqueid length exceeds maximum of %d\n",
5765  res = 0;
5766  goto fast_orig_cleanup;
5767  }
5768 
5769  if (ast_strlen_zero(name)) {
5770  astman_send_error(s, m, "Channel not specified");
5771  res = 0;
5772  goto fast_orig_cleanup;
5773  }
5774  if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
5775  if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
5776  astman_send_error(s, m, "Invalid priority");
5777  res = 0;
5778  goto fast_orig_cleanup;
5779  }
5780  }
5781  if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%30d", &to) != 1)) {
5782  astman_send_error(s, m, "Invalid timeout");
5783  res = 0;
5784  goto fast_orig_cleanup;
5785  }
5786  ast_copy_string(tmp, name, sizeof(tmp));
5787  tech = tmp;
5788  data = strchr(tmp, '/');
5789  if (!data) {
5790  astman_send_error(s, m, "Invalid channel");
5791  res = 0;
5792  goto fast_orig_cleanup;
5793  }
5794  *data++ = '\0';
5795  ast_copy_string(tmp2, callerid, sizeof(tmp2));
5796  ast_callerid_parse(tmp2, &n, &l);
5797  if (n) {
5798  if (ast_strlen_zero(n)) {
5799  n = NULL;
5800  }
5801  }
5802  if (l) {
5804  if (ast_strlen_zero(l)) {
5805  l = NULL;
5806  }
5807  }
5808  if (!ast_strlen_zero(codecs)) {
5811  }
5812 
5813  if (!ast_strlen_zero(app) && s->session) {
5814  int bad_appdata = 0;
5815  /* To run the System application (or anything else that goes to
5816  * shell), you must have the additional System privilege */
5817  if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
5818  && (
5819  strcasestr(app, "system") || /* System(rm -rf /)
5820  TrySystem(rm -rf /) */
5821  strcasestr(app, "exec") || /* Exec(System(rm -rf /))
5822  TryExec(System(rm -rf /)) */
5823  strcasestr(app, "agi") || /* AGI(/bin/rm,-rf /)
5824  EAGI(/bin/rm,-rf /) */
5825  strcasestr(app, "mixmonitor") || /* MixMonitor(blah,,rm -rf) */
5826  strcasestr(app, "externalivr") || /* ExternalIVR(rm -rf) */
5827  strcasestr(app, "originate") || /* Originate(Local/1234,app,System,rm -rf) */
5828  (strstr(appdata, "SHELL") && (bad_appdata = 1)) || /* NoOp(${SHELL(rm -rf /)}) */
5829  (strstr(appdata, "EVAL") && (bad_appdata = 1)) /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
5830  )) {
5831  char error_buf[64];
5832  snprintf(error_buf, sizeof(error_buf), "Originate Access Forbidden: %s", bad_appdata ? "Data" : "Application");
5833  astman_send_error(s, m, error_buf);
5834  res = 0;
5835  goto fast_orig_cleanup;
5836  }
5837  }
5838 
5839  /* Check early if the extension exists. If not, we need to bail out here. */
5840  if (exten && context && pi) {
5841  if (! ast_exists_extension(NULL, context, exten, pi, l)) {
5842  /* The extension does not exist. */
5843  astman_send_error(s, m, "Extension does not exist.");
5844  res = 0;
5845  goto fast_orig_cleanup;
5846  }
5847  }
5848 
5849  /* Allocate requested channel variables */
5850  vars = astman_get_variables(m);
5851  if (s->session && s->session->chanvars) {
5852  struct ast_variable *v, *old;
5853  old = vars;
5854  vars = NULL;
5855 
5856  /* The variables in the AMI originate action are appended at the end of the list, to override any user variables that apply*/
5857 
5858  vars = ast_variables_dup(s->session->chanvars);
5859  if (old) {
5860  for (v = vars; v->next; v = v->next );
5861  if (v->next) {
5862  v->next = old; /* Append originate variables at end of list */
5863  }
5864  }
5865  }
5866 
5867  /* For originate async - we can bridge in early media stage */
5868  bridge_early = ast_true(early_media);
5869 
5870  if (ast_true(async)) {
5871  struct fast_originate_helper *fast;
5872 
5873  fast = ast_calloc(1, sizeof(*fast));
5874  if (!fast || ast_string_field_init(fast, 252)) {
5875  ast_free(fast);
5876  ast_variables_destroy(vars);
5877  res = -1;
5878  } else {
5879  if (!ast_strlen_zero(id)) {
5880  ast_string_field_build(fast, idtext, "ActionID: %s\r\n", id);
5881  }
5882  ast_string_field_set(fast, tech, tech);
5883  ast_string_field_set(fast, data, data);
5884  ast_string_field_set(fast, app, app);
5885  ast_string_field_set(fast, appdata, appdata);
5886  ast_string_field_set(fast, cid_num, l);
5887  ast_string_field_set(fast, cid_name, n);
5888  ast_string_field_set(fast, context, context);
5889  ast_string_field_set(fast, exten, exten);
5890  ast_string_field_set(fast, account, account);
5891  ast_string_field_set(fast, channelid, assignedids.uniqueid);
5892  ast_string_field_set(fast, otherchannelid, assignedids.uniqueid2);
5893  fast->vars = vars;
5894  fast->cap = cap;
5895  cap = NULL; /* transfered originate helper the capabilities structure. It is now responsible for freeing it. */
5896  fast->timeout = to;
5897  fast->early_media = bridge_early;
5898  fast->priority = pi;
5899  if (ast_pthread_create_detached(&th, NULL, fast_originate, fast)) {
5901  res = -1;
5902  } else {
5903  res = 0;
5904  }
5905  }
5906  } else if (!ast_strlen_zero(app)) {
5907  res = ast_pbx_outgoing_app(tech, cap, data, to, app, appdata, &reason,
5908  AST_OUTGOING_WAIT, l, n, vars, account, NULL,
5909  assignedids.uniqueid ? &assignedids : NULL);
5910  ast_variables_destroy(vars);
5911  } else {
5912  if (exten && context && pi) {
5913  res = ast_pbx_outgoing_exten(tech, cap, data, to,
5914  context, exten, pi, &reason, AST_OUTGOING_WAIT,
5915  l, n, vars, account, NULL, bridge_early,
5916  assignedids.uniqueid ? &assignedids : NULL);
5917  ast_variables_destroy(vars);
5918  } else {
5919  astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
5920  ast_variables_destroy(vars);
5921  res = 0;
5922  goto fast_orig_cleanup;
5923  }
5924  }
5925  if (!res) {
5926  astman_send_ack(s, m, "Originate successfully queued");
5927  } else {
5928  astman_send_error(s, m, "Originate failed");
5929  }
5930 
5931 fast_orig_cleanup:
5932  ao2_cleanup(cap);
5933  return 0;
5934 }
5935 
5936 static int action_mailboxstatus(struct mansession *s, const struct message *m)
5937 {
5938  const char *mailbox = astman_get_header(m, "Mailbox");
5939  int ret;
5940 
5941  if (ast_strlen_zero(mailbox)) {
5942  astman_send_error(s, m, "Mailbox not specified");
5943  return 0;
5944  }
5945  ret = ast_app_has_voicemail(mailbox, NULL);
5946  astman_start_ack(s, m);
5947  astman_append(s, "Message: Mailbox Status\r\n"
5948  "Mailbox: %s\r\n"
5949  "Waiting: %d\r\n\r\n", mailbox, ret);
5950  return 0;
5951 }
5952 
5953 static int action_mailboxcount(struct mansession *s, const struct message *m)
5954 {
5955  const char *mailbox = astman_get_header(m, "Mailbox");
5956  int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;;
5957 
5958  if (ast_strlen_zero(mailbox)) {
5959  astman_send_error(s, m, "Mailbox not specified");
5960  return 0;
5961  }
5962  ast_app_inboxcount2(mailbox, &urgentmsgs, &newmsgs, &oldmsgs);
5963  astman_start_ack(s, m);
5964  astman_append(s, "Message: Mailbox Message Count\r\n"
5965  "Mailbox: %s\r\n"
5966  "UrgMessages: %d\r\n"
5967  "NewMessages: %d\r\n"
5968  "OldMessages: %d\r\n"
5969  "\r\n",
5970  mailbox, urgentmsgs, newmsgs, oldmsgs);
5971  return 0;
5972 }
5973 
5974 static int action_extensionstate(struct mansession *s, const struct message *m)
5975 {
5976  const char *exten = astman_get_header(m, "Exten");
5977  const char *context = astman_get_header(m, "Context");
5978  char hint[256];
5979  int status;
5980 
5981  if (ast_strlen_zero(exten)) {
5982  astman_send_error(s, m, "Extension not specified");
5983  return 0;
5984  }
5985  if (ast_strlen_zero(context)) {
5986  context = "default";
5987  }
5988  status = ast_extension_state(NULL, context, exten);
5989  hint[0] = '\0';
5990  ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten);
5991  astman_start_ack(s, m);
5992  astman_append(s, "Message: Extension Status\r\n"
5993  "Exten: %s\r\n"
5994  "Context: %s\r\n"
5995  "Hint: %s\r\n"
5996  "Status: %d\r\n"
5997  "StatusText: %s\r\n"
5998  "\r\n",
5999  exten, context, hint, status,
6000  ast_extension_state2str(status));
6001  return 0;
6002 }
6003 
6004 static int action_presencestate(struct mansession *s, const struct message *m)
6005 {
6006  const char *provider = astman_get_header(m, "Provider");
6008  char *subtype;
6009  char *message;
6010 
6011  if (ast_strlen_zero(provider)) {
6012  astman_send_error(s, m, "No provider specified");
6013  return 0;
6014  }
6015 
6016  state = ast_presence_state(provider, &subtype, &message);
6017  if (state == AST_PRESENCE_INVALID) {
6018  astman_send_error_va(s, m, "Invalid provider %s or provider in invalid state", provider);
6019  return 0;
6020  }
6021 
6022  astman_start_ack(s, m);
6023  astman_append(s, "Message: Presence State\r\n"
6024  "State: %s\r\n", ast_presence_state2str(state));
6025 
6026  if (!ast_strlen_zero(subtype)) {
6027  astman_append(s, "Subtype: %s\r\n", subtype);
6028  }
6029 
6030  if (!ast_strlen_zero(message)) {
6031  /* XXX The Message header here is deprecated as it
6032  * duplicates the action response header 'Message'.
6033  * Remove it in the next major revision of AMI.
6034  */
6035  astman_append(s, "Message: %s\r\n"
6036  "PresenceMessage: %s\r\n",
6037  message, message);
6038  }
6039  astman_append(s, "\r\n");
6040 
6041  return 0;
6042 }
6043 
6044 static int action_timeout(struct mansession *s, const struct message *m)
6045 {
6046  struct ast_channel *c;
6047  const char *name = astman_get_header(m, "Channel");
6048  double timeout = atof(astman_get_header(m, "Timeout"));
6049  struct timeval when = { timeout, 0 };
6050 
6051  if (ast_strlen_zero(name)) {
6052  astman_send_error(s, m, "No channel specified");
6053  return 0;
6054  }
6055 
6056  if (!timeout || timeout < 0) {
6057  astman_send_error(s, m, "No timeout specified");
6058  return 0;
6059  }
6060 
6061  if (!(c = ast_channel_get_by_name(name))) {
6062  astman_send_error(s, m, "No such channel");
6063  return 0;
6064  }
6065 
6066  when.tv_usec = (timeout - when.tv_sec) * 1000000.0;
6067 
6068  ast_channel_lock(c);
6070  ast_channel_unlock(c);
6071  c = ast_channel_unref(c);
6072 
6073  astman_send_ack(s, m, "Timeout Set");
6074 
6075  return 0;
6076 }
6077 
6078 static int whitefilter_cmp_fn(void *obj, void *arg, void *data, int flags)
6079 {
6080  regex_t *regex_filter = obj;
6081  const char *eventdata = arg;
6082  int *result = data;
6083 
6084  if (!regexec(regex_filter, eventdata, 0, NULL, 0)) {
6085  *result = 1;
6086  return (CMP_MATCH | CMP_STOP);
6087  }
6088 
6089  return 0;
6090 }
6091 
6092 static int blackfilter_cmp_fn(void *obj, void *arg, void *data, int flags)
6093 {
6094  regex_t *regex_filter = obj;
6095  const char *eventdata = arg;
6096  int *result = data;
6097 
6098  if (!regexec(regex_filter, eventdata, 0, NULL, 0)) {
6099  *result = 0;
6100  return (CMP_MATCH | CMP_STOP);
6101  }
6102 
6103  *result = 1;
6104  return 0;
6105 }
6106 
6107 /*!
6108  * \brief Manager command to add an event filter to a manager session
6109  * \see For more details look at manager_add_filter
6110  */
6111 static int action_filter(struct mansession *s, const struct message *m)
6112 {
6113  const char *filter = astman_get_header(m, "Filter");
6114  const char *operation = astman_get_header(m, "Operation");
6115  int res;
6116 
6117  if (!strcasecmp(operation, "Add")) {
6119 
6120  if (res != FILTER_SUCCESS) {
6121  if (res == FILTER_ALLOC_FAILED) {
6122  astman_send_error(s, m, "Internal Error. Failed to allocate regex for filter");
6123  return 0;
6124  } else if (res == FILTER_COMPILE_FAIL) {
6125  astman_send_error(s, m, "Filter did not compile. Check the syntax of the filter given.");
6126  return 0;
6127  } else {
6128  astman_send_error(s, m, "Internal Error. Failed adding filter.");
6129  return 0;
6130  }
6131  }
6132 
6133  astman_send_ack(s, m, "Success");
6134  return 0;
6135  }
6136 
6137  astman_send_error(s, m, "Unknown operation");
6138  return 0;
6139 }
6140 
6141 /*!
6142  * \brief Add an event filter to a manager session
6143  *
6144  * \param filter_pattern Filter syntax to add, see below for syntax
6145  *
6146  * \return FILTER_ALLOC_FAILED Memory allocation failure
6147  * \return FILTER_COMPILE_FAIL If the filter did not compile
6148  * \return FILTER_SUCCESS Success
6149  *
6150  * Filter will be used to match against each line of a manager event
6151  * Filter can be any valid regular expression
6152  * Filter can be a valid regular expression prefixed with !, which will add the filter as a black filter
6153  *
6154  * Examples:
6155  * \code
6156  * filter_pattern = "Event: Newchannel"
6157  * filter_pattern = "Event: New.*"
6158  * filter_pattern = "!Channel: DAHDI.*"
6159  * \endcode
6160  *
6161  */
6162 static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters) {
6163  regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
6164  int is_blackfilter;
6165 
6166  if (!new_filter) {
6167  return FILTER_ALLOC_FAILED;
6168  }
6169 
6170  if (filter_pattern[0] == '!') {
6171  is_blackfilter = 1;
6172  filter_pattern++;
6173  } else {
6174  is_blackfilter = 0;
6175  }
6176 
6177  if (regcomp(new_filter, filter_pattern, REG_EXTENDED | REG_NOSUB)) {
6178  ao2_t_ref(new_filter, -1, "failed to make regex");
6179  return FILTER_COMPILE_FAIL;
6180  }
6181 
6182  if (is_blackfilter) {
6183  ao2_t_link(blackfilters, new_filter, "link new filter into black user container");
6184  } else {
6185  ao2_t_link(whitefilters, new_filter, "link new filter into white user container");
6186  }
6187 
6188  ao2_ref(new_filter, -1);
6189 
6190  return FILTER_SUCCESS;
6191 }
6192 
6193 static int match_filter(struct mansession *s, char *eventdata)
6194 {
6195  int result = 0;
6196 
6197  if (manager_debug) {
6198  ast_verbose("<-- Examining AMI event: -->\n%s\n", eventdata);
6199  } else {
6200  ast_debug(3, "Examining AMI event:\n%s\n", eventdata);
6201  }
6203  return 1; /* no filtering means match all */
6205  /* white filters only: implied black all filter processed first, then white filters */
6206  ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
6208  /* black filters only: implied white all filter processed first, then black filters */
6209  ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
6210  } else {
6211  /* white and black filters: implied black all filter processed first, then white filters, and lastly black filters */
6212  ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
6213  if (result) {
6214  result = 0;
6215  ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
6216  }
6217  }
6218 
6219  return result;
6220 }
6221 
6222 /*!
6223  * Send any applicable events to the client listening on this socket.
6224  * Wait only for a finite time on each event, and drop all events whether
6225  * they are successfully sent or not.
6226  */
6227 static int process_events(struct mansession *s)
6228 {
6229  int ret = 0;
6230 
6231  ao2_lock(s->session);
6232  if (s->session->stream != NULL) {
6233  struct eventqent *eqe = s->session->last_ev;
6234 
6235  while ((eqe = advance_event(eqe))) {
6236  if (eqe->category == EVENT_FLAG_SHUTDOWN) {
6237  ast_debug(3, "Received CloseSession event\n");
6238  ret = -1;
6239  }
6240  if (!ret && s->session->authenticated &&
6241  (s->session->readperm & eqe->category) == eqe->category &&
6242  (s->session->send_events & eqe->category) == eqe->category) {
6243  if (match_filter(s, eqe->eventdata)) {
6244  if (send_string(s, eqe->eventdata) < 0)
6245  ret = -1; /* don't send more */
6246  }
6247  }
6248  s->session->last_ev = eqe;
6249  }
6250  }
6251  ao2_unlock(s->session);
6252  return ret;
6253 }
6254 
6255 static int action_userevent(struct mansession *s, const struct message *m)
6256 {
6257  const char *event = astman_get_header(m, "UserEvent");
6258  struct ast_str *body = ast_str_thread_get(&userevent_buf, 16);
6259  int x;
6260 
6261  ast_str_reset(body);
6262 
6263  for (x = 0; x < m->hdrcount; x++) {
6264  if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:")) &&
6265  strncasecmp("Action:", m->headers[x], strlen("Action:"))) {
6266  ast_str_append(&body, 0, "%s\r\n", m->headers[x]);
6267  }
6268  }
6269 
6270  astman_send_ack(s, m, "Event Sent");
6271  manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, ast_str_buffer(body));
6272  return 0;
6273 }
6274 
6275 /*! \brief Show PBX core settings information */
6276 static int action_coresettings(struct mansession *s, const struct message *m)
6277 {
6278  const char *actionid = astman_get_header(m, "ActionID");
6279  char idText[150];
6280 
6281  if (!ast_strlen_zero(actionid)) {
6282  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
6283  } else {
6284  idText[0] = '\0';
6285  }
6286 
6287  astman_append(s, "Response: Success\r\n"
6288  "%s"
6289  "AMIversion: %s\r\n"
6290  "AsteriskVersion: %s\r\n"
6291  "SystemName: %s\r\n"
6292  "CoreMaxCalls: %d\r\n"
6293  "CoreMaxLoadAvg: %f\r\n"
6294  "CoreRunUser: %s\r\n"
6295  "CoreRunGroup: %s\r\n"
6296  "CoreMaxFilehandles: %d\r\n"
6297  "CoreRealTimeEnabled: %s\r\n"
6298  "CoreCDRenabled: %s\r\n"
6299  "CoreHTTPenabled: %s\r\n"
6300  "\r\n",
6301  idText,
6302  AMI_VERSION,
6303  ast_get_version(),
6313  );
6314  return 0;
6315 }
6316 
6317 /*! \brief Show PBX core status information */
6318 static int action_corestatus(struct mansession *s, const struct message *m)
6319 {
6320  const char *actionid = astman_get_header(m, "ActionID");
6321  char idText[150];
6322  char startuptime[150], startupdate[150];
6323  char reloadtime[150], reloaddate[150];
6324  struct ast_tm tm;
6325 
6326  if (!ast_strlen_zero(actionid)) {
6327  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
6328  } else {
6329  idText[0] = '\0';
6330  }
6331 
6333  ast_strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
6334  ast_strftime(startupdate, sizeof(startupdate), "%Y-%m-%d", &tm);
6336  ast_strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
6337  ast_strftime(reloaddate, sizeof(reloaddate), "%Y-%m-%d", &tm);
6338 
6339  astman_append(s, "Response: Success\r\n"
6340  "%s"
6341  "CoreStartupDate: %s\r\n"
6342  "CoreStartupTime: %s\r\n"
6343  "CoreReloadDate: %s\r\n"
6344  "CoreReloadTime: %s\r\n"
6345  "CoreCurrentCalls: %d\r\n"
6346  "\r\n",
6347  idText,
6348  startupdate,
6349  startuptime,
6350  reloaddate,
6351  reloadtime,
6353  );
6354  return 0;
6355 }
6356 
6357 /*! \brief Send a reload event */
6358 static int action_reload(struct mansession *s, const struct message *m)
6359 {
6360  const char *module = astman_get_header(m, "Module");
6361  enum ast_module_reload_result res = ast_module_reload(S_OR(module, NULL));
6362 
6363  switch (res) {
6365  astman_send_error(s, m, "No such module");
6366  break;
6368  astman_send_error(s, m, "Module does not support reload");
6369  break;
6371  astman_send_error(s, m, "An unknown error occurred");
6372  break;
6374  astman_send_error(s, m, "A reload is in progress");
6375  break;
6377  astman_send_error(s, m, "Module not initialized");
6378  break;
6381  /* Treat a queued request as success */
6382  astman_send_ack(s, m, "Module Reloaded");
6383  break;
6384  }
6385  return 0;
6386 }
6387 
6388 /*! \brief Manager command "CoreShowChannels" - List currently defined channels
6389  * and some information about them. */
6390 static int action_coreshowchannels(struct mansession *s, const struct message *m)
6391 {
6392  const char *actionid = astman_get_header(m, "ActionID");
6393  char idText[256];
6394  int numchans = 0;
6395  struct ao2_container *channels;
6396  struct ao2_iterator it_chans;
6397  struct ast_channel_snapshot *cs;
6398 
6399  if (!ast_strlen_zero(actionid)) {
6400  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
6401  } else {
6402  idText[0] = '\0';
6403  }
6404 
6405  channels = ast_channel_cache_by_name();
6406 
6407  astman_send_listack(s, m, "Channels will follow", "start");
6408 
6409  it_chans = ao2_iterator_init(channels, 0);
6410  for (; (cs = ao2_iterator_next(&it_chans)); ao2_ref(cs, -1)) {
6412  char durbuf[16] = "";
6413 
6414  if (!built) {
6415  continue;
6416  }
6417 
6418  if (!ast_tvzero(cs->base->creationtime)) {
6419  int duration, durh, durm, durs;
6420 
6421  duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->base->creationtime) / 1000);
6422  durh = duration / 3600;
6423  durm = (duration % 3600) / 60;
6424  durs = duration % 60;
6425  snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
6426  }
6427 
6428  astman_append(s,
6429  "Event: CoreShowChannel\r\n"
6430  "%s"
6431  "%s"
6432  "Application: %s\r\n"
6433  "ApplicationData: %s\r\n"
6434  "Duration: %s\r\n"
6435  "BridgeId: %s\r\n"
6436  "\r\n",
6437  idText,
6438  ast_str_buffer(built),
6439  cs->dialplan->appl,
6440  cs->dialplan->data,
6441  durbuf,
6442  cs->bridge->id);
6443 
6444  numchans++;
6445 
6446  ast_free(built);
6447  }
6448  ao2_iterator_destroy(&it_chans);
6449 
6450  astman_send_list_complete(s, m, "CoreShowChannelsComplete", numchans);
6451 
6452  ao2_ref(channels, -1);
6453  return 0;
6454 }
6455 
6456 /*! \brief Manager command "LoggerRotate" - reloads and rotates the logger in
6457  * the same manner as the CLI command 'logger rotate'. */
6458 static int action_loggerrotate(struct mansession *s, const struct message *m)
6459 {
6460  if (ast_logger_rotate()) {
6461  astman_send_error(s, m, "Failed to reload the logger and rotate log files");
6462  return 0;
6463  }
6464 
6465  astman_send_ack(s, m, "Reloaded the logger and rotated log files");
6466  return 0;
6467 }
6468 
6469 /*! \brief Manager function to check if module is loaded */
6470 static int manager_modulecheck(struct mansession *s, const struct message *m)
6471 {
6472  int res;
6473  const char *module = astman_get_header(m, "Module");
6474  const char *id = astman_get_header(m, "ActionID");
6475  char idText[256];
6476  char filename[PATH_MAX];
6477  char *cut;
6478 
6479  ast_copy_string(filename, module, sizeof(filename));
6480  if ((cut = strchr(filename, '.'))) {
6481  *cut = '\0';
6482  } else {
6483  cut = filename + strlen(filename);
6484  }
6485  snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".so");
6486  ast_debug(1, "**** ModuleCheck .so file %s\n", filename);
6487  res = ast_module_check(filename);
6488  if (!res) {
6489  astman_send_error(s, m, "Module not loaded");
6490  return 0;
6491  }
6492 
6493  if (!ast_strlen_zero(id)) {
6494  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
6495  } else {
6496  idText[0] = '\0';
6497  }
6498  astman_append(s, "Response: Success\r\n%s", idText);
6499 #if !defined(LOW_MEMORY)
6500  astman_append(s, "Version: %s\r\n\r\n", "");
6501 #endif
6502  return 0;
6503 }
6504 
6505 static int manager_moduleload(struct mansession *s, const struct message *m)
6506 {
6507  int res;
6508  const char *module = astman_get_header(m, "Module");
6509  const char *loadtype = astman_get_header(m, "LoadType");
6510 
6511  if (!loadtype || strlen(loadtype) == 0) {
6512  astman_send_error(s, m, "Incomplete ModuleLoad action.");
6513  }
6514  if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0) {
6515  astman_send_error(s, m, "Need module name");
6516  }
6517 
6518  if (!strcasecmp(loadtype, "load")) {
6519  res = ast_load_resource(module);
6520  if (res) {
6521  astman_send_error(s, m, "Could not load module.");
6522  } else {
6523  astman_send_ack(s, m, "Module loaded.");
6524  }
6525  } else if (!strcasecmp(loadtype, "unload")) {
6526  res = ast_unload_resource(module, AST_FORCE_SOFT);
6527  if (res) {
6528  astman_send_error(s, m, "Could not unload module.");
6529  } else {
6530  astman_send_ack(s, m, "Module unloaded.");
6531  }
6532  } else if (!strcasecmp(loadtype, "reload")) {
6533  /* TODO: Unify the ack/error messages here with action_reload */
6534  if (!ast_strlen_zero(module)) {
6535  enum ast_module_reload_result reload_res = ast_module_reload(module);
6536 
6537  switch (reload_res) {
6539  astman_send_error(s, m, "No such module.");
6540  break;
6542  astman_send_error(s, m, "Module does not support reload action.");
6543  break;
6545  astman_send_error(s, m, "An unknown error occurred");
6546  break;
6548  astman_send_error(s, m, "A reload is in progress");
6549  break;
6551  astman_send_error(s, m, "Module not initialized");
6552  break;
6555  /* Treat a queued request as success */
6556  astman_send_ack(s, m, "Module reloaded.");
6557  break;
6558  }
6559  } else {
6560  ast_module_reload(NULL); /* Reload all modules */
6561  astman_send_ack(s, m, "All modules reloaded");
6562  }
6563  } else
6564  astman_send_error(s, m, "Incomplete ModuleLoad action.");
6565  return 0;
6566 }
6567 
6568 static void log_action(const struct message *m, const char *action)
6569 {
6570  struct ast_str *buf;
6571  int x;
6572 
6573  if (!manager_debug) {
6574  return;
6575  }
6576 
6577  buf = ast_str_create(256);
6578  if (!buf) {
6579  return;
6580  }
6581 
6582  for (x = 0; x < m->hdrcount; ++x) {
6583  if (!strncasecmp(m->headers[x], "Secret", 6)) {
6584  ast_str_append(&buf, 0, "Secret: <redacted from logging>\n");
6585  } else {
6586  ast_str_append(&buf, 0, "%s\n", m->headers[x]);
6587  }
6588  }
6589 
6590  ast_verbose("<--- Examining AMI action: -->\n%s\n", ast_str_buffer(buf));
6591  ast_free(buf);
6592 }
6593 
6594 /*
6595  * Done with the action handlers here, we start with the code in charge
6596  * of accepting connections and serving them.
6597  * accept_thread() forks a new thread for each connection, session_do(),
6598  * which in turn calls get_input() repeatedly until a full message has
6599  * been accumulated, and then invokes process_message() to pass it to
6600  * the appropriate handler.
6601  */
6602 
6603 /*! \brief
6604  * Process an AMI message, performing desired action.
6605  * Return 0 on success, -1 on error that require the session to be destroyed.
6606  */
6607 static int process_message(struct mansession *s, const struct message *m)
6608 {
6609  int ret = 0;
6610  struct manager_action *act_found;
6611  struct ast_manager_user *user = NULL;
6612  const char *username;
6613  const char *action;
6614 
6615  action = __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY);
6616  if (ast_strlen_zero(action)) {
6617  report_req_bad_format(s, "NONE");
6618  mansession_lock(s);
6619  astman_send_error(s, m, "Missing action in request");
6620  mansession_unlock(s);
6621  return 0;
6622  }
6623 
6624  log_action(m, action);
6625 
6626  if (ast_shutting_down()) {
6627  ast_log(LOG_ERROR, "Unable to process manager action '%s'. Asterisk is shutting down.\n", action);
6628  mansession_lock(s);
6629  astman_send_error(s, m, "Asterisk is shutting down");
6630  mansession_unlock(s);
6631  return 0;
6632  }
6633 
6634  if (!s->session->authenticated
6635  && strcasecmp(action, "Login")
6636  && strcasecmp(action, "Logoff")
6637  && strcasecmp(action, "Challenge")) {
6638  if (!s->session->authenticated) {
6639  report_req_not_allowed(s, action);
6640  }
6641  mansession_lock(s);
6642  astman_send_error(s, m, "Permission denied");
6643  mansession_unlock(s);
6644  return 0;
6645  }
6646 
6647  if (!s->session->authenticated
6648  && (!strcasecmp(action, "Login")
6649  || !strcasecmp(action, "Challenge"))) {
6650  username = astman_get_header(m, "Username");
6651 
6652  if (!ast_strlen_zero(username) && check_manager_session_inuse(username)) {
6654  user = get_manager_by_name_locked(username);
6655  if (user && !user->allowmultiplelogin) {
6658  sleep(1);
6659  mansession_lock(s);
6660  astman_send_error(s, m, "Login Already In Use");
6661  mansession_unlock(s);
6662  return -1;
6663  }
6665  }
6666  }
6667 
6668  act_found = action_find(action);
6669  if (act_found) {
6670  /* Found the requested AMI action. */
6671  int acted = 0;
6672 
6673  if ((s->session->writeperm & act_found->authority)
6674  || act_found->authority == 0) {
6675  /* We have the authority to execute the action. */
6676  ret = -1;
6677  ao2_lock(act_found);
6678  if (act_found->registered && act_found->func) {
6679  struct ast_module *mod_ref = ast_module_running_ref(act_found->module);
6680 
6681  ao2_unlock(act_found);
6682  if (mod_ref || !act_found->module) {
6683  ast_debug(1, "Running action '%s'\n", act_found->action);
6684  ret = act_found->func(s, m);
6685  acted = 1;
6686  ast_module_unref(mod_ref);
6687  }
6688  } else {
6689  ao2_unlock(act_found);
6690  }
6691  }
6692  if (!acted) {
6693  /*
6694  * We did not execute the action because access was denied, it
6695  * was no longer registered, or no action was really registered.
6696  * Complain about it and leave.
6697  */
6698  report_req_not_allowed(s, action);
6699  mansession_lock(s);
6700  astman_send_error(s, m, "Permission denied");
6701  mansession_unlock(s);
6702  }
6703  ao2_t_ref(act_found, -1, "done with found action object");
6704  } else {
6705  char buf[512];
6706 
6707  report_req_bad_format(s, action);
6708  snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
6709  mansession_lock(s);
6710  astman_send_error(s, m, buf);
6711  mansession_unlock(s);
6712  }
6713  if (ret) {
6714  return ret;
6715  }
6716  /* Once done with our message, deliver any pending events unless the
6717  requester doesn't want them as part of this response.
6718  */
6719  if (ast_strlen_zero(astman_get_header(m, "SuppressEvents"))) {
6720  return process_events(s);
6721  } else {
6722  return ret;
6723  }
6724 }
6725 
6726 /*!
6727  * Read one full line (including crlf) from the manager socket.
6728  * \note \verbatim
6729  * \r\n is the only valid terminator for the line.
6730  * (Note that, later, '\0' will be considered as the end-of-line marker,
6731  * so everything between the '\0' and the '\r\n' will not be used).
6732  * Also note that we assume output to have at least "maxlen" space.
6733  * \endverbatim
6734  */
6735 static int get_input(struct mansession *s, char *output)
6736 {
6737  int res, x;
6738  int maxlen = sizeof(s->session->inbuf) - 1;
6739  char *src = s->session->inbuf;
6740  int timeout = -1;
6741  time_t now;
6742 
6743  /*
6744  * Look for \r\n within the buffer. If found, copy to the output
6745  * buffer and return, trimming the \r\n (not used afterwards).
6746  */
6747  for (x = 0; x < s->session->inlen; x++) {
6748  int cr; /* set if we have \r */
6749  if (src[x] == '\r' && x+1 < s->session->inlen && src[x + 1] == '\n') {
6750  cr = 2; /* Found. Update length to include \r\n */
6751  } else if (src[x] == '\n') {
6752  cr = 1; /* also accept \n only */
6753  } else {
6754  continue;
6755  }
6756  memmove(output, src, x); /*... but trim \r\n */
6757  output[x] = '\0'; /* terminate the string */
6758  x += cr; /* number of bytes used */
6759  s->session->inlen -= x; /* remaining size */
6760  memmove(src, src + x, s->session->inlen); /* remove used bytes */
6761  return 1;
6762  }
6763  if (s->session->inlen >= maxlen) {
6764  /* no crlf found, and buffer full - sorry, too long for us
6765  * keep the last character in case we are in the middle of a CRLF. */
6766  ast_log(LOG_WARNING, "Discarding message from %s. Line too long: %.25s...\n", ast_sockaddr_stringify_addr(&s->session->addr), src);
6767  src[0] = src[s->session->inlen - 1];
6768  s->session->inlen = 1;
6770  }
6771  res = 0;
6772  while (res == 0) {
6773  /* calculate a timeout if we are not authenticated */
6774  if (!s->session->authenticated) {
6775  if(time(&now) == -1) {
6776  ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
6777  return -1;
6778  }
6779 
6780  timeout = (authtimeout - (now - s->session->authstart)) * 1000;
6781  if (timeout < 0) {
6782  /* we have timed out */
6783  return 0;
6784  }
6785  }
6786 
6788  if (s->session->pending_event) {
6789  s->session->pending_event = 0;
6791  return 0;
6792  }
6793  s->session->waiting_thread = pthread_self();
6795 
6797 
6801  }
6802  if (res < 0) {
6803  /* If we get a signal from some other thread (typically because
6804  * there are new events queued), return 0 to notify the caller.
6805  */
6806  if (errno == EINTR || errno == EAGAIN) {
6807  return 0;
6808  }
6809  ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
6810  return -1;
6811  }
6812 
6813  ao2_lock(s->session);
6814  res = ast_iostream_read(s->session->stream, src + s->session->inlen, maxlen - s->session->inlen);
6815  if (res < 1) {
6816  res = -1; /* error return */
6817  } else {
6818  s->session->inlen += res;
6819  src[s->session->inlen] = '\0';
6820  res = 0;
6821  }
6822  ao2_unlock(s->session);
6823  return res;
6824 }
6825 
6826 /*!
6827  * \internal
6828  * \brief Error handling for sending parse errors. This function handles locking, and clearing the
6829  * parse error flag.
6830  *
6831  * \param s AMI session to process action request.
6832  * \param m Message that's in error.
6833  * \param error Error message to send.
6834  */
6835 static void handle_parse_error(struct mansession *s, struct message *m, char *error)
6836 {
6837  mansession_lock(s);
6838  astman_send_error(s, m, error);
6839  s->parsing = MESSAGE_OKAY;
6840  mansession_unlock(s);
6841 }
6842 
6843 /*!
6844  * \internal
6845  * \brief Read and process an AMI action request.
6846  *
6847  * \param s AMI session to process action request.
6848  *
6849  * \retval 0 Retain AMI connection for next command.
6850  * \retval -1 Drop AMI connection due to logoff or connection error.
6851  */
6852 static int do_message(struct mansession *s)
6853 {
6854  struct message m = { 0 };
6855  char header_buf[sizeof(s->session->inbuf)] = { '\0' };
6856  int res;
6857  int hdr_loss;
6858  time_t now;
6859 
6860  hdr_loss = 0;
6861  for (;;) {
6862  /* Check if any events are pending and do them if needed */
6863  if (process_events(s)) {
6864  res = -1;
6865  break;
6866  }
6867  res = get_input(s, header_buf);
6868  if (res == 0) {
6869  /* No input line received. */
6870  if (!s->session->authenticated) {
6871  if (time(&now) == -1) {
6872  ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
6873  res = -1;
6874  break;
6875  }
6876 
6877  if (now - s->session->authstart > authtimeout) {
6878  if (displayconnects) {
6879  ast_verb(2, "Client from %s, failed to authenticate in %d seconds\n", ast_sockaddr_stringify_addr(&s->session->addr), authtimeout);
6880  }
6881  res = -1;
6882  break;
6883  }
6884  }
6885  continue;
6886  } else if (res > 0) {
6887  /* Input line received. */
6888  if (ast_strlen_zero(header_buf)) {
6889  if (hdr_loss) {
6890  mansession_lock(s);
6891  astman_send_error(s, &m, "Too many lines in message or allocation failure");
6892  mansession_unlock(s);
6893  res = 0;
6894  } else {
6895  switch (s->parsing) {
6896  case MESSAGE_OKAY:
6897  res = process_message(s, &m) ? -1 : 0;
6898  break;
6899  case MESSAGE_LINE_TOO_LONG:
6900  handle_parse_error(s, &m, "Failed to parse message: line too long");
6901  res = 0;
6902  break;
6903  }
6904  }
6905  break;
6906  } else if (m.hdrcount < ARRAY_LEN(m.headers)) {
6907  m.headers[m.hdrcount] = ast_strdup(header_buf);
6908  if (!m.headers[m.hdrcount]) {
6909  /* Allocation failure. */
6910  hdr_loss = 1;
6911  } else {
6912  ++m.hdrcount;
6913  }
6914  } else {
6915  /* Too many lines in message. */
6916  hdr_loss = 1;
6917  }
6918  } else {
6919  /* Input error. */
6920  break;
6921  }
6922  }
6923 
6924  astman_free_headers(&m);
6925 
6926  return res;
6927 }
6928 
6929 /*! \brief The body of the individual manager session.
6930  * Call get_input() to read one line at a time
6931  * (or be woken up on new events), collect the lines in a
6932  * message until found an empty line, and execute the request.
6933  * In any case, deliver events asynchronously through process_events()
6934  * (called from here if no line is available, or at the end of
6935  * process_message(). )
6936  */
6937 static void *session_do(void *data)
6938 {
6939  struct ast_tcptls_session_instance *ser = data;
6940  struct mansession_session *session;
6941  struct mansession s = {
6942  .tcptls_session = data,
6943  };
6944  int res;
6945  int arg = 1;
6946  struct ast_sockaddr ser_remote_address_tmp;
6947 
6950  goto done;
6951  }
6952 
6953  ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
6954  session = build_mansession(&ser_remote_address_tmp);
6955 
6956  if (session == NULL) {
6958  goto done;
6959  }
6960 
6961  /* here we set TCP_NODELAY on the socket to disable Nagle's algorithm.
6962  * This is necessary to prevent delays (caused by buffering) as we
6963  * write to the socket in bits and pieces. */
6964  if (setsockopt(ast_iostream_get_fd(ser->stream), IPPROTO_TCP, TCP_NODELAY, (char *) &arg, sizeof(arg)) < 0) {
6965  ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on manager connection: %s\n", strerror(errno));
6966  }
6968 
6969  ao2_lock(session);
6970  /* Hook to the tail of the event queue */
6971  session->last_ev = grab_last();
6972 
6973  ast_mutex_init(&s.lock);
6974 
6975  /* these fields duplicate those in the 'ser' structure */
6976  session->stream = s.stream = ser->stream;
6977  ast_sockaddr_copy(&session->addr, &ser_remote_address_tmp);
6978  s.session = session;
6979 
6981 
6982  if(time(&session->authstart) == -1) {
6983  ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
6985  ao2_unlock(session);
6986  session_destroy(session);
6987  goto done;
6988  }
6989  ao2_unlock(session);
6990 
6991  /*
6992  * We cannot let the stream exclusively wait for data to arrive.
6993  * We have to wake up the task to send async events.
6994  */
6996 
6998  ast_tvnow(), authtimeout * 1000);
6999 
7000  astman_append(&s, "Asterisk Call Manager/%s\r\n", AMI_VERSION); /* welcome prompt */
7001  for (;;) {
7002  if ((res = do_message(&s)) < 0 || s.write_error) {
7003  break;
7004  }
7005  if (session->authenticated) {
7007  }
7008  }
7009  /* session is over, explain why and terminate */
7010  if (session->authenticated) {
7011  if (manager_displayconnects(session)) {
7012  ast_verb(2, "Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
7013  }
7014  } else {
7016  if (displayconnects) {
7017  ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_sockaddr_stringify_addr(&session->addr));
7018  }
7019  }
7020 
7021  session_destroy(session);
7022 
7023  ast_mutex_destroy(&s.lock);
7024 done:
7025  ao2_ref(ser, -1);
7026  ser = NULL;
7027  return NULL;
7028 }
7029 
7030 /*! \brief remove at most n_max stale session from the list. */
7031 static void purge_sessions(int n_max)
7032 {
7033  struct ao2_container *sessions;
7034  struct mansession_session *session;
7035  time_t now = time(NULL);
7036  struct ao2_iterator i;
7037 
7038  sessions = ao2_global_obj_ref(mgr_sessions);
7039  if (!sessions) {
7040  return;
7041  }
7042  i = ao2_iterator_init(sessions, 0);
7043  ao2_ref(sessions, -1);
7044  while ((session = ao2_iterator_next(&i)) && n_max > 0) {
7045  ao2_lock(session);
7046  if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
7047  if (session->authenticated
7048  && VERBOSITY_ATLEAST(2)
7049  && manager_displayconnects(session)) {
7050  ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
7051  session->username, ast_sockaddr_stringify_addr(&session->addr));
7052  }
7053  ao2_unlock(session);
7054  session_destroy(session);
7055  n_max--;
7056  } else {
7057  ao2_unlock(session);
7058  unref_mansession(session);
7059  }
7060  }
7062 }
7063 
7064 /*! \brief
7065  * events are appended to a queue from where they
7066  * can be dispatched to clients.
7067  */
7068 static int append_event(const char *str, int category)
7069 {
7070  struct eventqent *tmp = ast_malloc(sizeof(*tmp) + strlen(str));
7071  static int seq; /* sequence number */
7072 
7073  if (!tmp) {
7074  return -1;
7075  }
7076 
7077  /* need to init all fields, because ast_malloc() does not */
7078  tmp->usecount = 0;
7079  tmp->category = category;
7080  tmp->seq = ast_atomic_fetchadd_int(&seq, 1);
7081  tmp->tv = ast_tvnow();
7082  AST_RWLIST_NEXT(tmp, eq_next) = NULL;
7083  strcpy(tmp->eventdata, str);
7084 
7086  AST_RWLIST_INSERT_TAIL(&all_events, tmp, eq_next);
7088 
7089  return 0;
7090 }
7091 
7092 static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
7093 {
7094  struct varshead *vars;
7095  struct ast_var_t *var;
7096 
7097  vars = ast_channel_get_manager_vars(chan);
7098  if (!vars) {
7099  return;
7100  }
7101 
7102  AST_LIST_TRAVERSE(vars, var, entries) {
7103  ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", ast_channel_name(chan), var->name, var->value);
7104  }
7105  ao2_ref(vars, -1);
7106 }
7107 
7108 /* XXX see if can be moved inside the function */
7110 #define MANAGER_EVENT_BUF_INITSIZE 256
7111 
7112 static int __attribute__((format(printf, 9, 0))) __manager_event_sessions_va(
7113  struct ao2_container *sessions,
7114  int category,
7115  const char *event,
7116  int chancount,
7117  struct ast_channel **chans,
7118  const char *file,
7119  int line,
7120  const char *func,
7121  const char *fmt,
7122  va_list ap)
7123 {
7125  const char *cat_str;
7126  struct timeval now;
7127  struct ast_str *buf;
7128  int i;
7129 
7131  if (!buf) {
7132  return -1;
7133  }
7134 
7135  cat_str = authority_to_str(category, &auth);
7136  ast_str_set(&buf, 0,
7137  "Event: %s\r\n"
7138  "Privilege: %s\r\n",
7139  event, cat_str);
7140 
7141  if (timestampevents) {
7142  now = ast_tvnow();
7143  ast_str_append(&buf, 0,
7144  "Timestamp: %ld.%06lu\r\n",
7145  (long)now.tv_sec, (unsigned long) now.tv_usec);
7146  }
7147  if (manager_debug) {
7148  static int seq;
7149 
7150  ast_str_append(&buf, 0,
7151  "SequenceNumber: %d\r\n",
7152  ast_atomic_fetchadd_int(&seq, 1));
7153  ast_str_append(&buf, 0,
7154  "File: %s\r\n"
7155  "Line: %d\r\n"
7156  "Func: %s\r\n",
7157  file, line, func);
7158  }
7160  ast_str_append(&buf, 0,
7161  "SystemName: %s\r\n",
7163  }
7164 
7165  ast_str_append_va(&buf, 0, fmt, ap);
7166  for (i = 0; i < chancount; i++) {
7167  append_channel_vars(&buf, chans[i]);
7168  }
7169 
7170  ast_str_append(&buf, 0, "\r\n");
7171 
7172  append_event(ast_str_buffer(buf), category);
7173 
7174  /* Wake up any sleeping sessions */
7175  if (sessions) {
7176  struct ao2_iterator iter;
7177  struct mansession_session *session;
7178 
7179  iter = ao2_iterator_init(sessions, 0);
7180  while ((session = ao2_iterator_next(&iter))) {
7181  ast_mutex_lock(&session->notify_lock);
7182  if (session->waiting_thread != AST_PTHREADT_NULL) {
7183  pthread_kill(session->waiting_thread, SIGURG);
7184  } else {
7185  /* We have an event to process, but the mansession is
7186  * not waiting for it. We still need to indicate that there
7187  * is an event waiting so that get_input processes the pending
7188  * event instead of polling.
7189  */
7190  session->pending_event = 1;
7191  }
7192  ast_mutex_unlock(&session->notify_lock);
7193  unref_mansession(session);
7194  }
7195  ao2_iterator_destroy(&iter);
7196  }
7197 
7198  if (category != EVENT_FLAG_SHUTDOWN && !AST_RWLIST_EMPTY(&manager_hooks)) {
7199  struct manager_custom_hook *hook;
7200 
7202  AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
7203  hook->helper(category, event, ast_str_buffer(buf));
7204  }
7206  }
7207 
7208  return 0;
7209 }
7210 
7211 static int __attribute__((format(printf, 9, 0))) __manager_event_sessions(
7212  struct ao2_container *sessions,
7213  int category,
7214  const char *event,
7215  int chancount,
7216  struct ast_channel **chans,
7217  const char *file,
7218  int line,
7219  const char *func,
7220  const char *fmt,
7221  ...)
7222 {
7223  va_list ap;
7224  int res;
7225 
7226  va_start(ap, fmt);
7227  res = __manager_event_sessions_va(sessions, category, event, chancount, chans,
7228  file, line, func, fmt, ap);
7229  va_end(ap);
7230  return res;
7231 }
7232 
7234  struct ast_channel **chans, const char *file, int line, const char *func,
7235  const char *fmt, ...)
7236 {
7237  struct ao2_container *sessions = ao2_global_obj_ref(mgr_sessions);
7238  va_list ap;
7239  int res;
7240 
7241  if (!any_manager_listeners(sessions)) {
7242  /* Nobody is listening */
7243  ao2_cleanup(sessions);
7244  return 0;
7245  }
7246 
7247  va_start(ap, fmt);
7248  res = __manager_event_sessions_va(sessions, category, event, chancount, chans,
7249  file, line, func, fmt, ap);
7250  va_end(ap);
7251  ao2_cleanup(sessions);
7252  return res;
7253 }
7254 
7255 /*! \brief
7256  * support functions to register/unregister AMI action handlers,
7257  */
7258 int ast_manager_unregister(const char *action)
7259 {
7260  struct manager_action *cur;
7261 
7264  if (!strcasecmp(action, cur->action)) {
7266  break;
7267  }
7268  }
7271 
7272  if (cur) {
7273  /*
7274  * We have removed the action object from the container so we
7275  * are no longer in a hurry.
7276  */
7277  ao2_lock(cur);
7278  cur->registered = 0;
7279  ao2_unlock(cur);
7280 
7281  ao2_t_ref(cur, -1, "action object removed from list");
7282  ast_verb(2, "Manager unregistered action %s\n", action);
7283  }
7284 
7285  return 0;
7286 }
7287 
7288 static int manager_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
7289 {
7290  /* Notify managers of change */
7291  char hint[512];
7292 
7293  hint[0] = '\0';
7294  ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten);
7295 
7296  switch(info->reason) {
7298  manager_event(EVENT_FLAG_CALL, "ExtensionStatus",
7299  "Exten: %s\r\n"
7300  "Context: %s\r\n"
7301  "Hint: %s\r\n"
7302  "Status: %d\r\n"
7303  "StatusText: %s\r\n",
7304  exten,
7305  context,
7306  hint,
7307  info->exten_state,
7309  break;
7311  manager_event(EVENT_FLAG_CALL, "PresenceStatus",
7312  "Exten: %s\r\n"
7313  "Context: %s\r\n"
7314  "Hint: %s\r\n"
7315  "Status: %s\r\n"
7316  "Subtype: %s\r\n"
7317  "Message: %s\r\n",
7318  exten,
7319  context,
7320  hint,
7322  info->presence_subtype,
7323  info->presence_message);
7324  break;
7325  }
7326  return 0;
7327 }
7328 
7330 {
7331  struct manager_action *cur, *prev = NULL;
7332 
7334  AST_RWLIST_TRAVERSE(&actions, cur, list) {
7335  int ret;
7336 
7337  ret = strcasecmp(cur->action, act->action);
7338  if (ret == 0) {
7339  ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
7341  return -1;
7342  }
7343  if (ret > 0) { /* Insert these alphabetically */
7344  break;
7345  }
7346  prev = cur;
7347  }
7348 
7349  ao2_t_ref(act, +1, "action object added to list");
7350  act->registered = 1;
7351  if (prev) {
7352  AST_RWLIST_INSERT_AFTER(&actions, prev, act, list);
7353  } else {
7354  AST_RWLIST_INSERT_HEAD(&actions, act, list);
7355  }
7356 
7357  ast_verb(2, "Manager registered action %s\n", act->action);
7358 
7360 
7361  return 0;
7362 }
7363 
7364 /*!
7365  * \internal
7366  * \brief Destroy the registered AMI action object.
7367  *
7368  * \param obj Object to destroy.
7369  *
7370  * \return Nothing
7371  */
7372 static void action_destroy(void *obj)
7373 {
7374  struct manager_action *doomed = obj;
7375 
7376  if (doomed->synopsis) {
7377  /* The string fields were initialized. */
7379  }
7380  ao2_cleanup(doomed->final_response);
7381  ao2_cleanup(doomed->list_responses);
7382 }
7383 
7384 /*! \brief register a new command with manager, including online help. This is
7385  the preferred way to register a manager command */
7386 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), struct ast_module *module, const char *synopsis, const char *description)
7387 {
7388  struct manager_action *cur;
7389 
7390  cur = ao2_t_alloc(sizeof(*cur), action_destroy, action);
7391  if (!cur) {
7392  return -1;
7393  }
7394  if (ast_string_field_init(cur, 128)) {
7395  ao2_t_ref(cur, -1, "action object creation failed");
7396  return -1;
7397  }
7398 
7399  cur->action = action;
7400  cur->authority = auth;
7401  cur->func = func;
7402  cur->module = module;
7403 #ifdef AST_XML_DOCS
7404  if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
7405  char *tmpxml;
7406 
7407  tmpxml = ast_xmldoc_build_synopsis("manager", action, NULL);
7408  ast_string_field_set(cur, synopsis, tmpxml);
7409  ast_free(tmpxml);
7410 
7411  tmpxml = ast_xmldoc_build_syntax("manager", action, NULL);
7412  ast_string_field_set(cur, syntax, tmpxml);
7413  ast_free(tmpxml);
7414 
7415  tmpxml = ast_xmldoc_build_description("manager", action, NULL);
7416  ast_string_field_set(cur, description, tmpxml);
7417  ast_free(tmpxml);
7418 
7419  tmpxml = ast_xmldoc_build_seealso("manager", action, NULL);
7420  ast_string_field_set(cur, seealso, tmpxml);
7421  ast_free(tmpxml);
7422 
7423  tmpxml = ast_xmldoc_build_arguments("manager", action, NULL);
7424  ast_string_field_set(cur, arguments, tmpxml);
7425  ast_free(tmpxml);
7426 
7427  cur->final_response = ast_xmldoc_build_final_response("manager", action, NULL);
7428  cur->list_responses = ast_xmldoc_build_list_responses("manager", action, NULL);
7429 
7430  cur->docsrc = AST_XML_DOC;
7431  } else
7432 #endif
7433  {
7434  ast_string_field_set(cur, synopsis, synopsis);
7435  ast_string_field_set(cur, description, description);
7436 #ifdef AST_XML_DOCS
7437  cur->docsrc = AST_STATIC_DOC;
7438 #endif
7439  }
7440  if (ast_manager_register_struct(cur)) {
7441  ao2_t_ref(cur, -1, "action object registration failed");
7442  return -1;
7443  }
7444 
7445  ao2_t_ref(cur, -1, "action object registration successful");
7446  return 0;
7447 }
7448 /*! @}
7449  END Doxygen group */
7450 
7451 /*
7452  * The following are support functions for AMI-over-http.
7453  * The common entry point is generic_http_callback(),
7454  * which extracts HTTP header and URI fields and reformats
7455  * them into AMI messages, locates a proper session
7456  * (using the mansession_id Cookie or GET variable),
7457  * and calls process_message() as for regular AMI clients.
7458  * When done, the output (which goes to a temporary file)
7459  * is read back into a buffer and reformatted as desired,
7460  * then fed back to the client over the original socket.
7461  */
7466  FORMAT_XML,
7467 };
7469 static const char * const contenttype[] = {
7470  [FORMAT_RAW] = "plain",
7471  [FORMAT_HTML] = "html",
7472  [FORMAT_XML] = "xml",
7473 };
7474 
7475 /*!
7476  * locate an http session in the list. The search key (ident) is
7477  * the value of the mansession_id cookie (0 is not valid and means
7478  * a session on the AMI socket).
7479  */
7480 static struct mansession_session *find_session(uint32_t ident, int incinuse)
7481 {
7482  struct ao2_container *sessions;
7483  struct mansession_session *session;
7484  struct ao2_iterator i;
7485 
7486  if (ident == 0) {
7487  return NULL;
7488  }
7489 
7490  sessions = ao2_global_obj_ref(mgr_sessions);
7491  if (!sessions) {
7492  return NULL;
7493  }
7494  i = ao2_iterator_init(sessions, 0);
7495  ao2_ref(sessions, -1);
7496  while ((session = ao2_iterator_next(&i))) {
7497  ao2_lock(session);
7498  if (session->managerid == ident && !session->needdestroy) {
7499  ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
7500  break;
7501  }
7502  ao2_unlock(session);
7503  unref_mansession(session);
7504  }
7506 
7507  return session;
7508 }
7509 
7510 /*!
7511  * locate an http session in the list.
7512  * The search keys (nonce) and (username) is value from received
7513  * "Authorization" http header.
7514  * As well as in find_session() function, the value of the nonce can't be zero.
7515  * (0 meansi, that the session used for AMI socket connection).
7516  * Flag (stale) is set, if client used valid, but old, nonce value.
7517  *
7518  */
7519 static struct mansession_session *find_session_by_nonce(const char *username, unsigned long nonce, int *stale)
7520 {
7521  struct mansession_session *session;
7522  struct ao2_container *sessions;
7523  struct ao2_iterator i;
7524 
7525  if (nonce == 0 || username == NULL || stale == NULL) {
7526  return NULL;
7527  }
7528 
7529  sessions = ao2_global_obj_ref(mgr_sessions);
7530  if (!sessions) {
7531  return NULL;
7532  }
7533  i = ao2_iterator_init(sessions, 0);
7534  ao2_ref(sessions, -1);
7535  while ((session = ao2_iterator_next(&i))) {
7536  ao2_lock(session);
7537  if (!strcasecmp(session->username, username) && session->managerid == nonce) {
7538  *stale = 0;
7539  break;
7540  } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
7541  *stale = 1;
7542  break;
7543  }
7544  ao2_unlock(session);
7545  unref_mansession(session);
7546  }
7548 
7549  return session;
7550 }
7552 int astman_is_authed(uint32_t ident)
7553 {
7554  int authed;
7555  struct mansession_session *session;
7556 
7557  if (!(session = find_session(ident, 0)))
7558  return 0;
7559 
7560  authed = (session->authenticated != 0);
7561 
7562  ao2_unlock(session);
7563  unref_mansession(session);
7564 
7565  return authed;
7566 }
7568 int astman_verify_session_readpermissions(uint32_t ident, int perm)
7569 {
7570  int result = 0;
7571  struct mansession_session *session;
7572  struct ao2_container *sessions;
7573  struct ao2_iterator i;
7574 
7575  if (ident == 0) {
7576  return 0;
7577  }
7578 
7579  sessions = ao2_global_obj_ref(mgr_sessions);
7580  if (!sessions) {
7581  return 0;
7582  }
7583  i = ao2_iterator_init(sessions, 0);
7584  ao2_ref(sessions, -1);
7585  while ((session = ao2_iterator_next(&i))) {
7586  ao2_lock(session);
7587  if ((session->managerid == ident) && (session->readperm & perm)) {
7588  result = 1;
7589  ao2_unlock(session);
7590  unref_mansession(session);
7591  break;
7592  }
7593  ao2_unlock(session);
7594  unref_mansession(session);
7595  }
7597 
7598  return result;
7599 }
7601 int astman_verify_session_writepermissions(uint32_t ident, int perm)
7602 {
7603  int result = 0;
7604  struct mansession_session *session;
7605  struct ao2_container *sessions;
7606  struct ao2_iterator i;
7607 
7608  if (ident == 0) {
7609  return 0;
7610  }
7611 
7612  sessions = ao2_global_obj_ref(mgr_sessions);
7613  if (!sessions) {
7614  return 0;
7615  }
7616  i = ao2_iterator_init(sessions, 0);
7617  ao2_ref(sessions, -1);
7618  while ((session = ao2_iterator_next(&i))) {
7619  ao2_lock(session);
7620  if ((session->managerid == ident) && (session->writeperm & perm)) {
7621  result = 1;
7622  ao2_unlock(session);
7623  unref_mansession(session);
7624  break;
7625  }
7626  ao2_unlock(session);
7627  unref_mansession(session);
7628  }
7630 
7631  return result;
7632 }
7633 
7634 /*
7635  * convert to xml with various conversion:
7636  * mode & 1 -> lowercase;
7637  * mode & 2 -> replace non-alphanumeric chars with underscore
7638  */
7639 static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
7640 {
7641  /* store in a local buffer to avoid calling ast_str_append too often */
7642  char buf[256];
7643  char *dst = buf;
7644  int space = sizeof(buf);
7645  /* repeat until done and nothing to flush */
7646  for ( ; *src || dst != buf ; src++) {
7647  if (*src == '\0' || space < 10) { /* flush */
7648  *dst++ = '\0';
7649  ast_str_append(out, 0, "%s", buf);
7650  dst = buf;
7651  space = sizeof(buf);
7652  if (*src == '\0') {
7653  break;
7654  }
7655  }
7656 
7657  if ( (mode & 2) && !isalnum(*src)) {
7658  *dst++ = '_';
7659  space--;
7660  continue;
7661  }
7662  switch (*src) {
7663  case '<':
7664  strcpy(dst, "&lt;");
7665  dst += 4;
7666  space -= 4;
7667  break;
7668  case '>':
7669  strcpy(dst, "&gt;");
7670  dst += 4;
7671  space -= 4;
7672  break;
7673  case '\"':
7674  strcpy(dst, "&quot;");
7675  dst += 6;
7676  space -= 6;
7677  break;
7678  case '\'':
7679  strcpy(dst, "&apos;");
7680  dst += 6;
7681  space -= 6;
7682  break;
7683  case '&':
7684  strcpy(dst, "&amp;");
7685  dst += 5;
7686  space -= 5;
7687  break;
7688 
7689  default:
7690  *dst++ = mode ? tolower(*src) : *src;
7691  space--;
7692  }
7693  }
7694 }
7697  char *varname;
7698  int count;
7699 };
7701 static int variable_count_hash_fn(const void *vvc, const int flags)
7702 {
7703  const struct variable_count *vc = vvc;
7704 
7705  return ast_str_hash(vc->varname);
7706 }
7708 static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
7709 {
7710  /* Due to the simplicity of struct variable_count, it makes no difference
7711  * if you pass in objects or strings, the same operation applies. This is
7712  * due to the fact that the hash occurs on the first element, which means
7713  * the address of both the struct and the string are exactly the same. */
7714  struct variable_count *vc = obj;
7715  char *str = vstr;
7716  return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
7717 }
7718 
7719 /*! \brief Convert the input into XML or HTML.
7720  * The input is supposed to be a sequence of lines of the form
7721  * Name: value
7722  * optionally followed by a blob of unformatted text.
7723  * A blank line is a section separator. Basically, this is a
7724  * mixture of the format of Manager Interface and CLI commands.
7725  * The unformatted text is considered as a single value of a field
7726  * named 'Opaque-data'.
7727  *
7728  * At the moment the output format is the following (but it may
7729  * change depending on future requirements so don't count too
7730  * much on it when writing applications):
7731  *
7732  * General: the unformatted text is used as a value of
7733  * XML output: to be completed
7734  *
7735  * \verbatim
7736  * Each section is within <response type="object" id="xxx">
7737  * where xxx is taken from ajaxdest variable or defaults to unknown
7738  * Each row is reported as an attribute Name="value" of an XML
7739  * entity named from the variable ajaxobjtype, default to "generic"
7740  * \endverbatim
7741  *
7742  * HTML output:
7743  * each Name-value pair is output as a single row of a two-column table.
7744  * Sections (blank lines in the input) are separated by a <HR>
7745  *
7746  */
7747 static void xml_translate(struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
7748 {
7749  struct ast_variable *v;
7750  const char *dest = NULL;
7751  char *var, *val;
7752  const char *objtype = NULL;
7753  int in_data = 0; /* parsing data */
7754  int inobj = 0;
7755  int xml = (format == FORMAT_XML);
7756  struct variable_count *vc = NULL;
7757  struct ao2_container *vco = NULL;
7758 
7759  if (xml) {
7760  /* dest and objtype need only for XML format */
7761  for (v = get_vars; v; v = v->next) {
7762  if (!strcasecmp(v->name, "ajaxdest")) {
7763  dest = v->value;
7764  } else if (!strcasecmp(v->name, "ajaxobjtype")) {
7765  objtype = v->value;
7766  }
7767  }
7768  if (ast_strlen_zero(dest)) {
7769  dest = "unknown";
7770  }
7771  if (ast_strlen_zero(objtype)) {
7772  objtype = "generic";
7773  }
7774  }
7775 
7776  /* we want to stop when we find an empty line */
7777  while (in && *in) {
7778  val = strsep(&in, "\r\n"); /* mark start and end of line */
7779  if (in && *in == '\n') { /* remove trailing \n if any */
7780  in++;
7781  }
7782  ast_trim_blanks(val);
7783  ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
7784  if (ast_strlen_zero(val)) {
7785  /* empty line */
7786  if (in_data) {
7787  /* close data in Opaque mode */
7788  ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
7789  in_data = 0;
7790  }
7791 
7792  if (inobj) {
7793  /* close block */
7794  ast_str_append(out, 0, xml ? " /></response>\n" :
7795  "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
7796  inobj = 0;
7797  ao2_ref(vco, -1);
7798  vco = NULL;
7799  }
7800  continue;
7801  }
7802 
7803  if (!inobj) {
7804  /* start new block */
7805  if (xml) {
7806  ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
7807  }
7810  inobj = 1;
7811  }
7812 
7813  if (in_data) {
7814  /* Process data field in Opaque mode. This is a
7815  * followup, so we re-add line feeds. */
7816  ast_str_append(out, 0, xml ? "\n" : "<br>\n");
7817  xml_copy_escape(out, val, 0); /* data field */
7818  continue;
7819  }
7820 
7821  /* We expect "Name: value" line here */
7822  var = strsep(&val, ":");
7823  if (val) {
7824  /* found the field name */
7825  val = ast_skip_blanks(val);
7826  ast_trim_blanks(var);
7827  } else {
7828  /* field name not found, switch to opaque mode */
7829  val = var;
7830  var = "Opaque-data";
7831  in_data = 1;
7832  }
7833 
7834 
7835  ast_str_append(out, 0, xml ? " " : "<tr><td>");
7836  if ((vc = ao2_find(vco, var, 0))) {
7837  vc->count++;
7838  } else {
7839  /* Create a new entry for this one */
7840  vc = ao2_alloc(sizeof(*vc), NULL);
7841  vc->varname = var;
7842  vc->count = 1;
7843  ao2_link(vco, vc);
7844  }
7845 
7846  xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
7847  if (vc->count > 1) {
7848  ast_str_append(out, 0, "-%d", vc->count);
7849  }
7850  ao2_ref(vc, -1);
7851  ast_str_append(out, 0, xml ? "='" : "</td><td>");
7852  xml_copy_escape(out, val, 0); /* data field */
7853  if (!in_data || !*in) {
7854  ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
7855  }
7856  }
7857 
7858  if (inobj) {
7859  ast_str_append(out, 0, xml ? " /></response>\n" :
7860  "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
7861  ao2_ref(vco, -1);
7862  }
7863 }
7865 static void close_mansession_file(struct mansession *s)
7866 {
7867  if (s->stream) {
7869  s->stream = NULL;
7870  } else {
7871  ast_log(LOG_ERROR, "Attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n");
7872  }
7873 }
7875 static void process_output(struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
7876 {
7877  char *buf;
7878  off_t l;
7879  int fd;
7880 
7881  if (!s->stream)
7882  return;
7883 
7884  /* Ensure buffer is NULL-terminated */
7885  ast_iostream_write(s->stream, "", 1);
7886 
7887  fd = ast_iostream_get_fd(s->stream);
7888 
7889  l = lseek(fd, 0, SEEK_CUR);
7890  if (l > 0) {
7891  if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0))) {
7892  ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n");
7893  } else {
7894  if (format == FORMAT_XML || format == FORMAT_HTML) {
7895  xml_translate(out, buf, params, format);
7896  } else {
7897  ast_str_append(out, 0, "%s", buf);
7898  }
7899  munmap(buf, l);
7900  }
7901  } else if (format == FORMAT_XML || format == FORMAT_HTML) {
7902  xml_translate(out, "", params, format);
7903  }
7904 
7906 }
7908 static int generic_http_callback(struct ast_tcptls_session_instance *ser,
7909  enum ast_http_method method,
7910  enum output_format format,
7911  const struct ast_sockaddr *remote_address, const char *uri,
7912  struct ast_variable *get_params,
7913  struct ast_variable *headers)
7914 {
7915  struct mansession s = { .session = NULL, .tcptls_session = ser };
7916  struct mansession_session *session = NULL;
7917  uint32_t ident;
7918  int fd;
7919  int blastaway = 0;
7920  struct ast_variable *params = get_params;
7921  char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
7922  struct ast_str *http_header = NULL, *out = NULL;
7923  struct message m = { 0 };
7924 
7925  if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
7926  ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
7927  return 0;
7928  }
7929 
7930  ident = ast_http_manid_from_vars(headers);
7931 
7932  if (!(session = find_session(ident, 1))) {
7933 
7934  /**/
7935  /* Create new session.
7936  * While it is not in the list we don't need any locking
7937  */
7938  if (!(session = build_mansession(remote_address))) {
7940  ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
7941  return 0;
7942  }
7943  ao2_lock(session);
7944  session->send_events = 0;
7945  session->inuse = 1;
7946  /*!
7947  * \note There is approximately a 1 in 1.8E19 chance that the following
7948  * calculation will produce 0, which is an invalid ID, but due to the
7949  * properties of the rand() function (and the constantcy of s), that
7950  * won't happen twice in a row.
7951  */
7952  while ((session->managerid = ast_random() ^ (unsigned long) session) == 0) {
7953  }
7954  session->last_ev = grab_last();
7955  AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
7956  }
7957  ao2_unlock(session);
7958 
7959  http_header = ast_str_create(128);
7960  out = ast_str_create(2048);
7961 
7962  ast_mutex_init(&s.lock);
7963 
7964  if (http_header == NULL || out == NULL) {
7966  ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)");
7967  goto generic_callback_out;
7968  }
7969 
7970  s.session = session;
7971  fd = mkstemp(template); /* create a temporary file for command output */
7972  unlink(template);
7973  if (fd <= -1) {
7974  ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)");
7975  goto generic_callback_out;
7976  }
7977  s.stream = ast_iostream_from_fd(&fd);
7978  if (!s.stream) {
7979  ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
7980  ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)");
7981  close(fd);
7982  goto generic_callback_out;
7983  }
7984 
7985  if (method == AST_HTTP_POST) {
7986  params = ast_http_get_post_vars(ser, headers);
7987  if (!params) {
7988  switch (errno) {
7989  case EFBIG:
7990  ast_http_error(ser, 413, "Request Entity Too Large", "Body too large");
7992  goto generic_callback_out;
7993  case ENOMEM:
7995  ast_http_error(ser, 500, "Server Error", "Out of memory");
7997  goto generic_callback_out;
7998  case EIO:
7999  ast_http_error(ser, 400, "Bad Request", "Error parsing request body");
8001  goto generic_callback_out;
8002  }
8003  }
8004  }
8005 
8006  astman_append_headers(&m, params);
8007 
8008  if (process_message(&s, &m)) {
8009  if (session->authenticated) {
8010  if (manager_displayconnects(session)) {
8011  ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
8012  }
8013  } else {
8014  if (displayconnects) {
8015  ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_sockaddr_stringify_addr(&session->addr));
8016  }
8017  }
8018  session->needdestroy = 1;
8019  }
8020 
8021  astman_free_headers(&m);
8022 
8023  ast_str_append(&http_header, 0,
8024  "Content-type: text/%s\r\n"
8025  "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
8026  "Pragma: SuppressEvents\r\n",
8027  contenttype[format],
8028  session->managerid, httptimeout);
8029 
8030  if (format == FORMAT_XML) {
8031  ast_str_append(&out, 0, "<ajax-response>\n");
8032  } else if (format == FORMAT_HTML) {
8033  /*
8034  * When handling AMI-over-HTTP in HTML format, we provide a simple form for
8035  * debugging purposes. This HTML code should not be here, we
8036  * should read from some config file...
8037  */
8038 
8039 #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
8040 #define TEST_STRING \
8041  "<form action=\"manager\" method=\"post\">\n\
8042  Action: <select name=\"action\">\n\
8043  <option value=\"\">-----&gt;</option>\n\
8044  <option value=\"login\">login</option>\n\
8045  <option value=\"command\">Command</option>\n\
8046  <option value=\"waitevent\">waitevent</option>\n\
8047  <option value=\"listcommands\">listcommands</option>\n\
8048  </select>\n\
8049  or <input name=\"action\"><br/>\n\
8050  CLI Command <input name=\"command\"><br>\n\
8051  user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
8052  <input type=\"submit\">\n</form>\n"
8053 
8054  ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
8055  ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
8056  ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
8057  ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
8058  }
8059 
8060  process_output(&s, &out, params, format);
8061 
8062  if (format == FORMAT_XML) {
8063  ast_str_append(&out, 0, "</ajax-response>\n");
8064  } else if (format == FORMAT_HTML) {
8065  ast_str_append(&out, 0, "</table></body>\r\n");
8066  }
8067 
8068  ao2_lock(session);
8069  /* Reset HTTP timeout. If we're not authenticated, keep it extremely short */
8070  session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
8071 
8072  if (session->needdestroy) {
8073  if (session->inuse == 1) {
8074  ast_debug(1, "Need destroy, doing it now!\n");
8075  blastaway = 1;
8076  } else {
8077  ast_debug(1, "Need destroy, but can't do it yet!\n");
8078  ast_mutex_lock(&session->notify_lock);
8079  if (session->waiting_thread != AST_PTHREADT_NULL) {
8080  pthread_kill(session->waiting_thread, SIGURG);
8081  }
8082  ast_mutex_unlock(&session->notify_lock);
8083  session->inuse--;
8084  }
8085  } else {
8086  session->inuse--;
8087  }
8088  ao2_unlock(session);
8089 
8090  ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
8091  http_header = NULL;
8092  out = NULL;
8093 
8094 generic_callback_out:
8095  ast_mutex_destroy(&s.lock);
8096 
8097  /* Clear resource */
8098 
8099  if (method == AST_HTTP_POST && params) {
8100  ast_variables_destroy(params);
8101  }
8102  ast_free(http_header);
8103  ast_free(out);
8104 
8105  if (session) {
8106  if (blastaway) {
8107  session_destroy(session);
8108  } else {
8109  if (session->stream) {
8110  ast_iostream_close(session->stream);
8111  session->stream = NULL;
8112  }
8113  unref_mansession(session);
8114  }
8115  }
8116 
8117  return 0;
8118 }
8120 static int auth_http_callback(struct ast_tcptls_session_instance *ser,
8121  enum ast_http_method method,
8122  enum output_format format,
8123  const struct ast_sockaddr *remote_address, const char *uri,
8124  struct ast_variable *get_params,
8125  struct ast_variable *headers)
8126 {
8127  struct mansession_session *session = NULL;
8128  struct mansession s = { .session = NULL, .tcptls_session = ser };
8129  struct ast_variable *v, *params = get_params;
8130  char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
8131  struct ast_str *http_header = NULL, *out = NULL;
8132  size_t result_size;
8133  struct message m = { 0 };
8134  int fd;
8135 
8136  time_t time_now = time(NULL);
8137  unsigned long nonce = 0, nc;
8138  struct ast_http_digest d = { NULL, };
8139  struct ast_manager_user *user = NULL;
8140  int stale = 0;
8141  char resp_hash[256]="";
8142  /* Cache for user data */
8143  char u_username[80];
8144  int u_readperm;
8145  int u_writeperm;
8146  int u_writetimeout;
8147  int u_displayconnects;
8148 
8149  if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
8150  ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
8151  return 0;
8152  }
8153 
8154  /* Find "Authorization: " header */
8155  for (v = headers; v; v = v->next) {
8156  if (!strcasecmp(v->name, "Authorization")) {
8157  break;
8158  }
8159  }
8160 
8161  if (!v || ast_strlen_zero(v->value)) {
8162  goto out_401; /* Authorization Header not present - send auth request */
8163  }
8164 
8165  /* Digest found - parse */
8166  if (ast_string_field_init(&d, 128)) {
8168  ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
8169  return 0;
8170  }
8171 
8172  if (ast_parse_digest(v->value, &d, 0, 1)) {
8173  /* Error in Digest - send new one */
8174  nonce = 0;
8175  goto out_401;
8176  }
8177  if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
8178  ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
8179  nonce = 0;
8180  goto out_401;
8181  }
8182 
8185  if(!user) {
8187  ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
8188  nonce = 0;
8189  goto out_401;
8190  }
8191 
8192  /* --- We have User for this auth, now check ACL */
8193  if (user->acl && !ast_apply_acl(user->acl, remote_address, "Manager User ACL:")) {
8195  ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
8197  ast_http_error(ser, 403, "Permission denied", "Permission denied");
8198  return 0;
8199  }
8200 
8201  /* --- We have auth, so check it */
8202 
8203  /* compute the expected response to compare with what we received */
8204  {
8205  char *a2;
8206  /* ast_md5_hash outputs 32 characters plus NULL terminator. */
8207  char a2_hash[33];
8208  char resp[256];
8209 
8210  /* XXX Now request method are hardcoded in A2 */
8211  if (ast_asprintf(&a2, "%s:%s", ast_get_http_method(method), d.uri) < 0) {
8214  ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
8215  return 0;
8216  }
8217 
8218  ast_md5_hash(a2_hash, a2);
8219  ast_free(a2);
8220 
8221  if (d.qop) {
8222  /* RFC 2617 */
8223  snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
8224  } else {
8225  /* RFC 2069 */
8226  snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
8227  }
8228  ast_md5_hash(resp_hash, resp);
8229  }
8230 
8231  if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
8232  /* Something was wrong, so give the client to try with a new challenge */
8234  nonce = 0;
8235  goto out_401;
8236  }
8237 
8238  /*
8239  * User are pass Digest authentication.
8240  * Now, cache the user data and unlock user list.
8241  */
8242  ast_copy_string(u_username, user->username, sizeof(u_username));
8243  u_readperm = user->readperm;
8244  u_writeperm = user->writeperm;
8245  u_displayconnects = user->displayconnects;
8246  u_writetimeout = user->writetimeout;
8248 
8249  if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
8250  /*
8251  * Create new session.
8252  * While it is not in the list we don't need any locking
8253  */
8254  if (!(session = build_mansession(remote_address))) {
8256  ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
8257  return 0;
8258  }
8259  ao2_lock(session);
8260 
8261  ast_copy_string(session->username, u_username, sizeof(session->username));
8262  session->managerid = nonce;
8263  session->last_ev = grab_last();
8265 
8266  session->readperm = u_readperm;
8267  session->writeperm = u_writeperm;
8268  session->writetimeout = u_writetimeout;
8269 
8270  if (u_displayconnects) {
8271  ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
8272  }
8273  session->noncetime = session->sessionstart = time_now;
8274  session->authenticated = 1;
8275  } else if (stale) {
8276  /*
8277  * Session found, but nonce is stale.
8278  *
8279  * This could be because an old request (w/old nonce) arrived.
8280  *
8281  * This may be as the result of http proxy usage (separate delay or
8282  * multipath) or in a situation where a page was refreshed too quickly
8283  * (seen in Firefox).
8284  *
8285  * In this situation, we repeat the 401 auth with the current nonce
8286  * value.
8287  */
8288  nonce = session->managerid;
8289  ao2_unlock(session);
8290  stale = 1;
8291  goto out_401;
8292  } else {
8293  sscanf(d.nc, "%30lx", &nc);
8294  if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
8295  /*
8296  * Nonce time expired (> 2 minutes) or something wrong with nonce
8297  * counter.
8298  *
8299  * Create new nonce key and resend Digest auth request. Old nonce
8300  * is saved for stale checking...
8301  */
8302  session->nc = 0; /* Reset nonce counter */
8303  session->oldnonce = session->managerid;
8304  nonce = session->managerid = ast_random();
8305  session->noncetime = time_now;
8306  ao2_unlock(session);
8307  stale = 1;
8308  goto out_401;
8309  } else {
8310  session->nc = nc; /* All OK, save nonce counter */
8311  }
8312  }
8313 
8314 
8315  /* Reset session timeout. */
8316  session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
8317  ao2_unlock(session);
8318 
8319  ast_mutex_init(&s.lock);
8320  s.session = session;
8321  fd = mkstemp(template); /* create a temporary file for command output */
8322  unlink(template);
8323  if (fd <= -1) {
8324  ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)");
8325  goto auth_callback_out;
8326  }
8327  s.stream = ast_iostream_from_fd(&fd);
8328  if (!s.stream) {
8329  ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
8330  ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)");
8331  close(fd);
8332  goto auth_callback_out;
8333  }
8334 
8335  if (method == AST_HTTP_POST) {
8336  params = ast_http_get_post_vars(ser, headers);
8337  if (!params) {
8338  switch (errno) {
8339  case EFBIG:
8340  ast_http_error(ser, 413, "Request Entity Too Large", "Body too large");
8342  goto auth_callback_out;
8343  case ENOMEM:
8345  ast_http_error(ser, 500, "Server Error", "Out of memory");
8347  goto auth_callback_out;
8348  case EIO:
8349  ast_http_error(ser, 400, "Bad Request", "Error parsing request body");
8351  goto auth_callback_out;
8352  }
8353  }
8354  }
8355 
8356  astman_append_headers(&m, params);
8357 
8358  if (process_message(&s, &m)) {
8359  if (u_displayconnects) {
8360  ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
8361  }
8362 
8363  session->needdestroy = 1;
8364  }
8365 
8366  astman_free_headers(&m);
8367 
8368  result_size = lseek(ast_iostream_get_fd(s.stream), 0, SEEK_CUR); /* Calculate approx. size of result */
8369 
8370  http_header = ast_str_create(80);
8371  out = ast_str_create(result_size * 2 + 512);
8372  if (http_header == NULL || out == NULL) {
8374  ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)");
8376  goto auth_callback_out;
8377  }
8378 
8379  ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]);
8380 
8381  if (format == FORMAT_XML) {
8382  ast_str_append(&out, 0, "<ajax-response>\n");
8383  } else if (format == FORMAT_HTML) {
8384  ast_str_append(&out, 0,
8385  "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
8386  "<html><head>\r\n"
8387  "<title>Asterisk&trade; Manager Interface</title>\r\n"
8388  "</head><body style=\"background-color: #ffffff;\">\r\n"
8389  "<form method=\"POST\">\r\n"
8390  "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
8391  "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
8392  "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
8393  "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
8394  }
8395 
8396  process_output(&s, &out, params, format);
8397 
8398  if (format == FORMAT_XML) {
8399  ast_str_append(&out, 0, "</ajax-response>\n");
8400  } else if (format == FORMAT_HTML) {
8401  ast_str_append(&out, 0, "</table></form></body></html>\r\n");
8402  }
8403 
8404  ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
8405  http_header = NULL;
8406  out = NULL;
8407 
8408 auth_callback_out:
8409  ast_mutex_destroy(&s.lock);
8410 
8411  /* Clear resources and unlock manager session */
8412  if (method == AST_HTTP_POST && params) {
8413  ast_variables_destroy(params);
8414  }
8415 
8416  ast_free(http_header);
8417  ast_free(out);
8418 
8419  ao2_lock(session);
8420  if (session->stream) {
8421  ast_iostream_close(session->stream);
8422  session->stream = NULL;
8423  }
8424  ao2_unlock(session);
8425 
8426  if (session->needdestroy) {
8427  ast_debug(1, "Need destroy, doing it now!\n");
8428  session_destroy(session);
8429  }
8431  return 0;
8432 
8433 out_401:
8434  if (!nonce) {
8435  nonce = ast_random();
8436  }
8437 
8438  ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
8440  return 0;
8441 }
8443 static int manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
8444 {
8445  int retval;
8446  struct ast_sockaddr ser_remote_address_tmp;
8447 
8448  ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8449  retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
8450  ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8451  return retval;
8452 }
8454 static int mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
8455 {
8456  int retval;
8457  struct ast_sockaddr ser_remote_address_tmp;
8458 
8459  ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8460  retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
8461  ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8462  return retval;
8463 }
8465 static int rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
8466 {
8467  int retval;
8468  struct ast_sockaddr ser_remote_address_tmp;
8469 
8470  ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8471  retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
8472  ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8473  return retval;
8474 }
8476 static struct ast_http_uri rawmanuri = {
8477  .description = "Raw HTTP Manager Event Interface",
8478  .uri = "rawman",
8479  .callback = rawman_http_callback,
8480  .data = NULL,
8481  .key = __FILE__,
8482 };
8484 static struct ast_http_uri manageruri = {
8485  .description = "HTML Manager Event Interface",
8486  .uri = "manager",
8487  .callback = manager_http_callback,
8488  .data = NULL,
8489  .key = __FILE__,
8490 };
8492 static struct ast_http_uri managerxmluri = {
8493  .description = "XML Manager Event Interface",
8494  .uri = "mxml",
8495  .callback = mxml_http_callback,
8496  .data = NULL,
8497  .key = __FILE__,
8498 };
8499 
8500 
8501 /* Callback with Digest authentication */
8502 static int auth_manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
8503 {
8504  int retval;
8505  struct ast_sockaddr ser_remote_address_tmp;
8506 
8507  ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8508  retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
8509  ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8510  return retval;
8511 }
8513 static int auth_mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
8514 {
8515  int retval;
8516  struct ast_sockaddr ser_remote_address_tmp;
8517 
8518  ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8519  retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
8520  ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8521  return retval;
8522 }
8524 static int auth_rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
8525 {
8526  int retval;
8527  struct ast_sockaddr ser_remote_address_tmp;
8528 
8529  ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8530  retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
8531  ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8532  return retval;
8533 }
8535 static struct ast_http_uri arawmanuri = {
8536  .description = "Raw HTTP Manager Event Interface w/Digest authentication",
8537  .uri = "arawman",
8538  .has_subtree = 0,
8539  .callback = auth_rawman_http_callback,
8540  .data = NULL,
8541  .key = __FILE__,
8542 };
8544 static struct ast_http_uri amanageruri = {
8545  .description = "HTML Manager Event Interface w/Digest authentication",
8546  .uri = "amanager",
8547  .has_subtree = 0,
8548  .callback = auth_manager_http_callback,
8549  .data = NULL,
8550  .key = __FILE__,
8551 };
8553 static struct ast_http_uri amanagerxmluri = {
8554  .description = "XML Manager Event Interface w/Digest authentication",
8555  .uri = "amxml",
8556  .has_subtree = 0,
8557  .callback = auth_mxml_http_callback,
8558  .data = NULL,
8559  .key = __FILE__,
8560 };
8561 
8562 /*! \brief Get number of logged in sessions for a login name */
8563 static int get_manager_sessions_cb(void *obj, void *arg, void *data, int flags)
8564 {
8565  struct mansession_session *session = obj;
8566  const char *login = (char *)arg;
8567  int *no_sessions = data;
8568 
8569  if (strcasecmp(session->username, login) == 0) {
8570  (*no_sessions)++;
8571  }
8572 
8573  return 0;
8574 }
8575 
8576 
8577 /*! \brief ${AMI_CLIENT()} Dialplan function - reads manager client data */
8578 static int function_amiclient(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
8579 {
8580  struct ast_manager_user *user = NULL;
8581 
8583  AST_APP_ARG(name);
8584  AST_APP_ARG(param);
8585  );
8586 
8587 
8588  if (ast_strlen_zero(data) ) {
8589  ast_log(LOG_WARNING, "AMI_CLIENT() requires two arguments: AMI_CLIENT(<name>[,<arg>])\n");
8590  return -1;
8591  }
8592  AST_STANDARD_APP_ARGS(args, data);
8593  args.name = ast_strip(args.name);
8594  args.param = ast_strip(args.param);
8595 
8597  if (!(user = get_manager_by_name_locked(args.name))) {
8599  ast_log(LOG_ERROR, "There's no manager user called : \"%s\"\n", args.name);
8600  return -1;
8601  }
8603 
8604  if (!strcasecmp(args.param, "sessions")) {
8605  int no_sessions = 0;
8606  struct ao2_container *sessions;
8607 
8608  sessions = ao2_global_obj_ref(mgr_sessions);
8609  if (sessions) {
8610  ao2_callback_data(sessions, 0, get_manager_sessions_cb, /*login name*/ data, &no_sessions);
8611  ao2_ref(sessions, -1);
8612  }
8613  snprintf(buf, len, "%d", no_sessions);
8614  } else {
8615  ast_log(LOG_ERROR, "Invalid arguments provided to function AMI_CLIENT: %s\n", args.param);
8616  return -1;
8617 
8618  }
8619 
8620  return 0;
8621 }
8622 
8623 
8624 /*! \brief description of AMI_CLIENT dialplan function */
8626  .name = "AMI_CLIENT",
8627  .read = function_amiclient,
8628  .read_max = 12,
8629 };
8631 static int webregged = 0;
8632 
8633 /*! \brief cleanup code called at each iteration of server_root,
8634  * guaranteed to happen every 5 seconds at most
8635  */
8636 static void purge_old_stuff(void *data)
8637 {
8638  purge_sessions(1);
8639  purge_events();
8640 }
8643 static struct ast_tcptls_session_args ami_desc = {
8644  .accept_fd = -1,
8645  .master = AST_PTHREADT_NULL,
8646  .tls_cfg = NULL,
8647  .poll_timeout = 5000, /* wake up every 5 seconds */
8648  .periodic_fn = purge_old_stuff,
8649  .name = "AMI server",
8650  .accept_fn = ast_tcptls_server_root, /* thread doing the accept() */
8651  .worker_fn = session_do, /* thread handling the session */
8652 };
8654 static struct ast_tcptls_session_args amis_desc = {
8655  .accept_fd = -1,
8656  .master = AST_PTHREADT_NULL,
8657  .tls_cfg = &ami_tls_cfg,
8658  .poll_timeout = -1, /* the other does the periodic cleanup */
8659  .name = "AMI TLS server",
8660  .accept_fn = ast_tcptls_server_root, /* thread doing the accept() */
8661  .worker_fn = session_do, /* thread handling the session */
8662 };
8663 
8664 /*! \brief CLI command manager show settings */
8665 static char *handle_manager_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8666 {
8667  switch (cmd) {
8668  case CLI_INIT:
8669  e->command = "manager show settings";
8670  e->usage =
8671  "Usage: manager show settings\n"
8672  " Provides detailed list of the configuration of the Manager.\n";
8673  return NULL;
8674  case CLI_GENERATE:
8675  return NULL;
8676  }
8677 #define FORMAT " %-25.25s %-15.55s\n"
8678 #define FORMAT2 " %-25.25s %-15d\n"
8679  if (a->argc != 3) {
8680  return CLI_SHOWUSAGE;
8681  }
8682  ast_cli(a->fd, "\nGlobal Settings:\n");
8683  ast_cli(a->fd, "----------------\n");
8684  ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
8685  ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
8686  ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
8687  ast_cli(a->fd, FORMAT2, "HTTP Timeout (seconds):", httptimeout);
8688  ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
8689  ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
8690  ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
8691  ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
8692  ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
8693  ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
8694  ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
8695  ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
8696  ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
8697  ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
8698 #undef FORMAT
8699 #undef FORMAT2
8700 
8701  return CLI_SUCCESS;
8702 }
8703 
8704 #ifdef AST_XML_DOCS
8706 static int ast_xml_doc_item_cmp_fn(const void *a, const void *b)
8707 {
8708  struct ast_xml_doc_item **item_a = (struct ast_xml_doc_item **)a;
8709  struct ast_xml_doc_item **item_b = (struct ast_xml_doc_item **)b;
8710  return strcmp((*item_a)->name, (*item_b)->name);
8711 }
8713 static char *handle_manager_show_events(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8714 {
8715  struct ao2_container *events;
8716  struct ao2_iterator *it_events;
8717  struct ast_xml_doc_item *item;
8718  struct ast_xml_doc_item **items;
8719  struct ast_str *buffer;
8720  int i = 0, totalitems = 0;
8721 
8722  switch (cmd) {
8723  case CLI_INIT:
8724  e->command = "manager show events";
8725  e->usage =
8726  "Usage: manager show events\n"
8727  " Prints a listing of the available Asterisk manager interface events.\n";
8728  return NULL;
8729  case CLI_GENERATE:
8730  return NULL;
8731  }
8732  if (a->argc != 3) {
8733  return CLI_SHOWUSAGE;
8734  }
8735 
8736  buffer = ast_str_create(128);
8737  if (!buffer) {
8738  return CLI_SUCCESS;
8739  }
8740 
8741  events = ao2_global_obj_ref(event_docs);
8742  if (!events) {
8743  ast_cli(a->fd, "No manager event documentation loaded\n");
8744  ast_free(buffer);
8745  return CLI_SUCCESS;
8746  }
8747 
8748  ao2_lock(events);
8749  if (!(it_events = ao2_callback(events, OBJ_MULTIPLE | OBJ_NOLOCK, NULL, NULL))) {
8750  ao2_unlock(events);
8751  ast_log(AST_LOG_ERROR, "Unable to create iterator for events container\n");
8752  ast_free(buffer);
8753  ao2_ref(events, -1);
8754  return CLI_SUCCESS;
8755  }
8756  if (!(items = ast_calloc(sizeof(struct ast_xml_doc_item *), ao2_container_count(events)))) {
8757  ao2_unlock(events);
8758  ast_log(AST_LOG_ERROR, "Unable to create temporary sorting array for events\n");
8759  ao2_iterator_destroy(it_events);
8760  ast_free(buffer);
8761  ao2_ref(events, -1);
8762  return CLI_SUCCESS;
8763  }
8764  ao2_unlock(events);
8765 
8766  while ((item = ao2_iterator_next(it_events))) {
8767  items[totalitems++] = item;
8768  ao2_ref(item, -1);
8769  }
8770 
8771  qsort(items, totalitems, sizeof(struct ast_xml_doc_item *), ast_xml_doc_item_cmp_fn);
8772 
8773  ast_cli(a->fd, "Events:\n");
8774  ast_cli(a->fd, " -------------------- -------------------- -------------------- \n");
8775  for (i = 0; i < totalitems; i++) {
8776  ast_str_append(&buffer, 0, " %-20.20s", items[i]->name);
8777  if ((i + 1) % 3 == 0) {
8778  ast_cli(a->fd, "%s\n", ast_str_buffer(buffer));
8779  ast_str_set(&buffer, 0, "%s", "");
8780  }
8781  }
8782  if ((i + 1) % 3 != 0) {
8783  ast_cli(a->fd, "%s\n", ast_str_buffer(buffer));
8784  }
8785 
8786  ao2_iterator_destroy(it_events);
8787  ast_free(items);
8788  ao2_ref(events, -1);
8789  ast_free(buffer);
8790 
8791  return CLI_SUCCESS;
8792 }
8794 static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance)
8795 {
8796  char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
8797 
8798  term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
8799  term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
8800  term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
8801  term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
8802  term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
8803 
8804  if (!ast_strlen_zero(ast_str_buffer(instance->synopsis))) {
8805  char *synopsis = ast_xmldoc_printable(ast_str_buffer(instance->synopsis), 1);
8806  ast_cli(a->fd, "%s%s\n\n", synopsis_title, synopsis);
8807  ast_free(synopsis);
8808  }
8809  if (!ast_strlen_zero(ast_str_buffer(instance->syntax))) {
8810  char *syntax = ast_xmldoc_printable(ast_str_buffer(instance->syntax), 1);
8811  ast_cli(a->fd, "%s%s\n\n", syntax_title, syntax);
8812  ast_free(syntax);
8813  }
8814  if (!ast_strlen_zero(ast_str_buffer(instance->description))) {
8815  char *description = ast_xmldoc_printable(ast_str_buffer(instance->description), 1);
8816  ast_cli(a->fd, "%s%s\n\n", description_title, description);
8817  ast_free(description);
8818  }
8819  if (!ast_strlen_zero(ast_str_buffer(instance->arguments))) {
8820  char *arguments = ast_xmldoc_printable(ast_str_buffer(instance->arguments), 1);
8821  ast_cli(a->fd, "%s%s\n\n", arguments_title, arguments);
8822  ast_free(arguments);
8823  }
8824  if (!ast_strlen_zero(ast_str_buffer(instance->seealso))) {
8825  char *seealso = ast_xmldoc_printable(ast_str_buffer(instance->seealso), 1);
8826  ast_cli(a->fd, "%s%s\n\n", seealso_title, seealso);
8827  ast_free(seealso);
8828  }
8829 }
8831 static char *handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8832 {
8834  struct ao2_iterator it_events;
8835  struct ast_xml_doc_item *item, *temp;
8836  int length;
8837 
8838  if (cmd == CLI_INIT) {
8839  e->command = "manager show event";
8840  e->usage =
8841  "Usage: manager show event <eventname>\n"
8842  " Provides a detailed description a Manager interface event.\n";
8843  return NULL;
8844  }
8845 
8846  events = ao2_global_obj_ref(event_docs);
8847  if (!events) {
8848  ast_cli(a->fd, "No manager event documentation loaded\n");
8849  return CLI_SUCCESS;
8850  }
8851 
8852  if (cmd == CLI_GENERATE) {
8853  if (a->pos != 3) {
8854  return NULL;
8855  }
8856 
8857  length = strlen(a->word);
8858  it_events = ao2_iterator_init(events, 0);
8859  while ((item = ao2_iterator_next(&it_events))) {
8860  if (!strncasecmp(a->word, item->name, length)) {
8861  if (ast_cli_completion_add(ast_strdup(item->name))) {
8862  ao2_ref(item, -1);
8863  break;
8864  }
8865  }
8866  ao2_ref(item, -1);
8867  }
8868  ao2_iterator_destroy(&it_events);
8869 
8870  return NULL;
8871  }
8872 
8873  if (a->argc != 4) {
8874  return CLI_SHOWUSAGE;
8875  }
8876 
8877  if (!(item = ao2_find(events, a->argv[3], OBJ_KEY))) {
8878  ast_cli(a->fd, "Could not find event '%s'\n", a->argv[3]);
8879  return CLI_SUCCESS;
8880  }
8881 
8882  ast_cli(a->fd, "Event: %s\n", a->argv[3]);
8883  for (temp = item; temp; temp = AST_LIST_NEXT(temp, next)) {
8884  print_event_instance(a, temp);
8885  }
8886 
8887  ao2_ref(item, -1);
8888  return CLI_SUCCESS;
8889 }
8890 
8891 #endif
8893 static struct ast_cli_entry cli_manager[] = {
8894  AST_CLI_DEFINE(handle_showmancmd, "Show a manager interface command"),
8895  AST_CLI_DEFINE(handle_showmancmds, "List manager interface commands"),
8896  AST_CLI_DEFINE(handle_showmanconn, "List connected manager interface users"),
8897  AST_CLI_DEFINE(handle_showmaneventq, "List manager interface queued events"),
8898  AST_CLI_DEFINE(handle_showmanagers, "List configured manager users"),
8899  AST_CLI_DEFINE(handle_showmanager, "Display information on a specific manager user"),
8900  AST_CLI_DEFINE(handle_mandebug, "Show, enable, disable debugging of the manager code"),
8901  AST_CLI_DEFINE(handle_manager_reload, "Reload manager configurations"),
8902  AST_CLI_DEFINE(handle_manager_show_settings, "Show manager global settings"),
8903 #ifdef AST_XML_DOCS
8904  AST_CLI_DEFINE(handle_manager_show_events, "List manager interface events"),
8905  AST_CLI_DEFINE(handle_manager_show_event, "Show a manager interface event"),
8906 #endif
8907 };
8908 
8909 /*!
8910  * \internal
8911  * \brief Load the config channelvars variable.
8912  *
8913  * \param var Config variable to load.
8914  *
8915  * \return Nothing
8916  */
8917 static void load_channelvars(struct ast_variable *var)
8918 {
8919  char *parse = NULL;
8921  AST_APP_ARG(vars)[MAX_VARS];
8922  );
8923 
8926 
8927  /* parse the setting */
8929  AST_STANDARD_APP_ARGS(args, parse);
8930 
8932 }
8933 
8934 /*!
8935  * \internal
8936  * \brief Free a user record. Should already be removed from the list
8937  */
8938 static void manager_free_user(struct ast_manager_user *user)
8939 {
8940  ast_free(user->a1_hash);
8941  ast_free(user->secret);
8942  if (user->whitefilters) {
8943  ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
8944  }
8945  if (user->blackfilters) {
8946  ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
8947  }
8948  user->acl = ast_free_acl_list(user->acl);
8950  ast_free(user);
8951 }
8952 
8953 /*!
8954  * \internal
8955  * \brief Clean up resources on Asterisk shutdown
8956  */
8957 static void manager_shutdown(void)
8958 {
8959  struct ast_manager_user *user;
8960 
8961  /* This event is not actually transmitted, but causes all TCP sessions to be closed */
8962  manager_event(EVENT_FLAG_SHUTDOWN, "CloseSession", "CloseSession: true\r\n");
8963 
8964  ast_manager_unregister("Ping");
8965  ast_manager_unregister("Events");
8966  ast_manager_unregister("Logoff");
8967  ast_manager_unregister("Login");
8968  ast_manager_unregister("Challenge");
8969  ast_manager_unregister("Hangup");
8970  ast_manager_unregister("Status");
8971  ast_manager_unregister("Setvar");
8972  ast_manager_unregister("Getvar");
8973  ast_manager_unregister("GetConfig");
8974  ast_manager_unregister("GetConfigJSON");
8975  ast_manager_unregister("UpdateConfig");
8976  ast_manager_unregister("CreateConfig");
8977  ast_manager_unregister("ListCategories");
8978  ast_manager_unregister("Redirect");
8979  ast_manager_unregister("Atxfer");
8980  ast_manager_unregister("CancelAtxfer");
8981  ast_manager_unregister("Originate");
8982  ast_manager_unregister("Command");
8983  ast_manager_unregister("ExtensionState");
8984  ast_manager_unregister("PresenceState");
8985  ast_manager_unregister("AbsoluteTimeout");
8986  ast_manager_unregister("MailboxStatus");
8987  ast_manager_unregister("MailboxCount");
8988  ast_manager_unregister("ListCommands");
8989  ast_manager_unregister("SendText");
8990  ast_manager_unregister("UserEvent");
8991  ast_manager_unregister("WaitEvent");
8992  ast_manager_unregister("CoreSettings");
8993  ast_manager_unregister("CoreStatus");
8994  ast_manager_unregister("Reload");
8995  ast_manager_unregister("LoggerRotate");
8996  ast_manager_unregister("CoreShowChannels");
8997  ast_manager_unregister("ModuleLoad");
8998  ast_manager_unregister("ModuleCheck");
8999  ast_manager_unregister("AOCMessage");
9000  ast_manager_unregister("Filter");
9001  ast_manager_unregister("BlindTransfer");
9002  ast_custom_function_unregister(&managerclient_function);
9003  ast_cli_unregister_multiple(cli_manager, ARRAY_LEN(cli_manager));
9004 
9005 #ifdef AST_XML_DOCS
9006  ao2_t_global_obj_release(event_docs, "Dispose of event_docs");
9007 #endif
9008 
9009 #ifdef TEST_FRAMEWORK
9010  stasis_forward_cancel(test_suite_forwarder);
9011  test_suite_forwarder = NULL;
9012 #endif
9013 
9014  if (stasis_router) {
9016  stasis_router = NULL;
9017  }
9018  stasis_forward_cancel(rtp_topic_forwarder);
9019  rtp_topic_forwarder = NULL;
9020  stasis_forward_cancel(security_topic_forwarder);
9021  security_topic_forwarder = NULL;
9022  ao2_cleanup(manager_topic);
9023  manager_topic = NULL;
9025 
9026  ast_tcptls_server_stop(&ami_desc);
9027  ast_tcptls_server_stop(&amis_desc);
9028 
9039 
9040  ao2_global_obj_release(mgr_sessions);
9041 
9042  while ((user = AST_LIST_REMOVE_HEAD(&users, list))) {
9043  manager_free_user(user);
9044  }
9046 
9048 }
9049 
9050 
9051 /*! \brief Initialize all \ref stasis topics and routers used by the various
9052  * sub-components of AMI
9053  */
9054 static int manager_subscriptions_init(void)
9055 {
9056  int res = 0;
9057 
9058  rtp_topic_forwarder = stasis_forward_all(ast_rtp_topic(), manager_topic);
9059  if (!rtp_topic_forwarder) {
9060  return -1;
9061  }
9062 
9063  security_topic_forwarder = stasis_forward_all(ast_security_topic(), manager_topic);
9064  if (!security_topic_forwarder) {
9065  return -1;
9066  }
9067 
9068  stasis_router = stasis_message_router_create(manager_topic);
9069  if (!stasis_router) {
9070  return -1;
9071  }
9074 
9077 
9078  res |= stasis_message_router_add(stasis_router,
9080 
9081  if (res != 0) {
9082  return -1;
9083  }
9084  return 0;
9085 }
9087 static int subscribe_all(void)
9088 {
9090  ast_log(AST_LOG_ERROR, "Failed to initialize manager subscriptions\n");
9091  return -1;
9092  }
9093  if (manager_system_init()) {
9094  ast_log(AST_LOG_ERROR, "Failed to initialize manager system handling\n");
9095  return -1;
9096  }
9097  if (manager_channels_init()) {
9098  ast_log(AST_LOG_ERROR, "Failed to initialize manager channel handling\n");
9099  return -1;
9100  }
9101  if (manager_mwi_init()) {
9102  ast_log(AST_LOG_ERROR, "Failed to initialize manager MWI handling\n");
9103  return -1;
9104  }
9105  if (manager_bridging_init()) {
9106  return -1;
9107  }
9108  if (manager_endpoints_init()) {
9109  ast_log(AST_LOG_ERROR, "Failed to initialize manager endpoints handling\n");
9110  return -1;
9111  }
9112 
9113  subscribed = 1;
9114  return 0;
9115 }
9117 static void manager_set_defaults(void)
9118 {
9119  manager_enabled = 0;
9120  displayconnects = 1;
9122  authtimeout = 30;
9123  authlimit = 50;
9124  manager_debug = 0; /* Debug disabled by default */
9125 
9126  /* default values */
9128  sizeof(global_realm));
9130  ast_sockaddr_setnull(&amis_desc.local_address);
9131 
9132  ami_tls_cfg.enabled = 0;
9143 }
9145 static int __init_manager(int reload, int by_external_config)
9146 {
9147  struct ast_config *ucfg = NULL, *cfg = NULL;
9148  const char *val;
9149  char *cat = NULL;
9150  int newhttptimeout = 60;
9151  struct ast_manager_user *user = NULL;
9152  struct ast_variable *var;
9153  struct ast_flags config_flags = { (reload && !by_external_config) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9154  char a1[256];
9155  char a1_hash[256];
9156  struct ast_sockaddr ami_desc_local_address_tmp;
9157  struct ast_sockaddr amis_desc_local_address_tmp;
9158  int tls_was_enabled = 0;
9159  int acl_subscription_flag = 0;
9160 
9161  if (!reload) {
9162  struct ao2_container *sessions;
9163 #ifdef AST_XML_DOCS
9164  struct ao2_container *temp_event_docs;
9165 #endif
9166  int res;
9167 
9169  if (res != 0) {
9170  return -1;
9171  }
9172  manager_topic = stasis_topic_create("manager:core");
9173  if (!manager_topic) {
9174  return -1;
9175  }
9176 
9177  /* Register default actions */
9216 
9217 #ifdef TEST_FRAMEWORK
9218  test_suite_forwarder = stasis_forward_all(ast_test_suite_topic(), manager_topic);
9219 #endif
9220 
9221  ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
9222  __ast_custom_function_register(&managerclient_function, NULL);
9224 
9225  /* Append placeholder event so master_eventq never runs dry */
9226  if (append_event("Event: Placeholder\r\n\r\n", 0)) {
9227  return -1;
9228  }
9229 
9230 #ifdef AST_XML_DOCS
9231  temp_event_docs = ast_xmldoc_build_documentation("managerEvent");
9232  if (temp_event_docs) {
9233  ao2_t_global_obj_replace_unref(event_docs, temp_event_docs, "Toss old event docs");
9234  ao2_t_ref(temp_event_docs, -1, "Remove creation ref - container holds only ref now");
9235  }
9236 #endif
9237 
9238  /* If you have a NULL hash fn, you only need a single bucket */
9240  if (!sessions) {
9241  return -1;
9242  }
9243  ao2_global_obj_replace_unref(mgr_sessions, sessions);
9244  ao2_ref(sessions, -1);
9245 
9246  /* Initialize all settings before first configuration load. */
9248  }
9249 
9250  cfg = ast_config_load2("manager.conf", "manager", config_flags);
9251  if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9252  return 0;
9253  } else if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
9254  ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid.\n");
9255  return 0;
9256  }
9257 
9258  /* If this wasn't performed due to a forced reload (because those can be created by ACL change events, we need to unsubscribe to ACL change events. */
9259  if (!by_external_config) {
9261  }
9262 
9263  if (reload) {
9264  /* Reset all settings before reloading configuration */
9265  tls_was_enabled = ami_tls_cfg.enabled;
9267  }
9268 
9269  ast_sockaddr_parse(&ami_desc_local_address_tmp, "[::]", 0);
9270  ast_sockaddr_set_port(&ami_desc_local_address_tmp, DEFAULT_MANAGER_PORT);
9271 
9272  for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
9273  val = var->value;
9274 
9275  /* read tls config options while preventing unsupported options from being set */
9276  if (strcasecmp(var->name, "tlscafile")
9277  && strcasecmp(var->name, "tlscapath")
9278  && strcasecmp(var->name, "tlscadir")
9279  && strcasecmp(var->name, "tlsverifyclient")
9280  && strcasecmp(var->name, "tlsdontverifyserver")
9281  && strcasecmp(var->name, "tlsclientmethod")
9282  && strcasecmp(var->name, "sslclientmethod")
9283  && !ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
9284  continue;
9285  }
9286 
9287  if (!strcasecmp(var->name, "enabled")) {
9288  manager_enabled = ast_true(val);
9289  } else if (!strcasecmp(var->name, "webenabled")) {
9291  } else if (!strcasecmp(var->name, "port")) {
9292  int bindport;
9293  if (ast_parse_arg(val, PARSE_UINT32|PARSE_IN_RANGE, &bindport, 1024, 65535)) {
9294  ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
9295  }
9296  ast_sockaddr_set_port(&ami_desc_local_address_tmp, bindport);
9297  } else if (!strcasecmp(var->name, "bindaddr")) {
9298  /* remember port if it has already been set */
9299  int setport = ast_sockaddr_port(&ami_desc_local_address_tmp);
9300 
9302  ast_log(LOG_WARNING, "Invalid address '%s' specified, default '%s' will be used\n", val,
9303  ast_sockaddr_stringify_addr(&ami_desc_local_address_tmp));
9304  } else {
9305  ast_sockaddr_parse(&ami_desc_local_address_tmp, val, PARSE_PORT_IGNORE);
9306  }
9307 
9308  if (setport) {
9309  ast_sockaddr_set_port(&ami_desc_local_address_tmp, setport);
9310  }
9311 
9312  } else if (!strcasecmp(var->name, "brokeneventsaction")) {
9314  } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
9316  } else if (!strcasecmp(var->name, "displayconnects")) {
9317  displayconnects = ast_true(val);
9318  } else if (!strcasecmp(var->name, "timestampevents")) {
9319  timestampevents = ast_true(val);
9320  } else if (!strcasecmp(var->name, "debug")) {
9321  manager_debug = ast_true(val);
9322  } else if (!strcasecmp(var->name, "httptimeout")) {
9323  newhttptimeout = atoi(val);
9324  } else if (!strcasecmp(var->name, "authtimeout")) {
9325  int timeout = atoi(var->value);
9326 
9327  if (timeout < 1) {
9328  ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
9329  } else {
9330  authtimeout = timeout;
9331  }
9332  } else if (!strcasecmp(var->name, "authlimit")) {
9333  int limit = atoi(var->value);
9334 
9335  if (limit < 1) {
9336  ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
9337  } else {
9338  authlimit = limit;
9339  }
9340  } else if (!strcasecmp(var->name, "channelvars")) {
9341  load_channelvars(var);
9342  } else {
9343  ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
9344  var->name, val);
9345  }
9346  }
9347 
9348  if (manager_enabled && !subscribed) {
9349  if (subscribe_all() != 0) {
9350  ast_log(LOG_ERROR, "Manager subscription error\n");
9351  return -1;
9352  }
9353  }
9354 
9355  ast_sockaddr_copy(&amis_desc_local_address_tmp, &amis_desc.local_address);
9356 
9357  /* if the amis address has not been set, default is the same as non secure ami */
9358  if (ast_sockaddr_isnull(&amis_desc_local_address_tmp)) {
9359  ast_sockaddr_copy(&amis_desc_local_address_tmp, &ami_desc_local_address_tmp);
9360  }
9361 
9362  /* if the amis address was not set, it will have non-secure ami port set; if
9363  amis address was set, we need to check that a port was set or not, if not
9364  use the default tls port */
9365  if (ast_sockaddr_port(&amis_desc_local_address_tmp) == 0 ||
9366  (ast_sockaddr_port(&ami_desc_local_address_tmp) == ast_sockaddr_port(&amis_desc_local_address_tmp))) {
9367 
9368  ast_sockaddr_set_port(&amis_desc_local_address_tmp, DEFAULT_MANAGER_TLS_PORT);
9369  }
9370 
9371  if (manager_enabled) {
9372  ast_sockaddr_copy(&ami_desc.local_address, &ami_desc_local_address_tmp);
9373  ast_sockaddr_copy(&amis_desc.local_address, &amis_desc_local_address_tmp);
9374  }
9375 
9377 
9378  /* First, get users from users.conf */
9379  ucfg = ast_config_load2("users.conf", "manager", config_flags);
9380  if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
9381  const char *hasmanager;
9382  int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
9383 
9384  while ((cat = ast_category_browse(ucfg, cat))) {
9385  if (!strcasecmp(cat, "general")) {
9386  continue;
9387  }
9388 
9389  hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
9390  if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
9391  const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
9392  const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
9393  const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
9394  const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
9395  const char *user_allowmultiplelogin = ast_variable_retrieve(ucfg, cat, "allowmultiplelogin");
9396  const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
9397 
9398  /* Look for an existing entry,
9399  * if none found - create one and add it to the list
9400  */
9401  if (!(user = get_manager_by_name_locked(cat))) {
9402  if (!(user = ast_calloc(1, sizeof(*user)))) {
9403  break;
9404  }
9405 
9406  /* Copy name over */
9407  ast_copy_string(user->username, cat, sizeof(user->username));
9408  /* Insert into list */
9409  AST_LIST_INSERT_TAIL(&users, user, list);
9410  user->acl = NULL;
9411  user->keep = 1;
9412  user->readperm = -1;
9413  user->writeperm = -1;
9414  /* Default displayconnect from [general] */
9416  /* Default allowmultiplelogin from [general] */
9418  user->writetimeout = 100;
9419  }
9420 
9421  if (!user_secret) {
9422  user_secret = ast_variable_retrieve(ucfg, "general", "secret");
9423  }
9424  if (!user_read) {
9425  user_read = ast_variable_retrieve(ucfg, "general", "read");
9426  }
9427  if (!user_write) {
9428  user_write = ast_variable_retrieve(ucfg, "general", "write");
9429  }
9430  if (!user_displayconnects) {
9431  user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
9432  }
9433  if (!user_allowmultiplelogin) {
9434  user_allowmultiplelogin = ast_variable_retrieve(ucfg, "general", "allowmultiplelogin");
9435  }
9436  if (!user_writetimeout) {
9437  user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
9438  }
9439 
9440  if (!ast_strlen_zero(user_secret)) {
9441  ast_free(user->secret);
9442  user->secret = ast_strdup(user_secret);
9443  }
9444 
9445  if (user_read) {
9446  user->readperm = get_perm(user_read);
9447  }
9448  if (user_write) {
9449  user->writeperm = get_perm(user_write);
9450  }
9451  if (user_displayconnects) {
9452  user->displayconnects = ast_true(user_displayconnects);
9453  }
9454  if (user_allowmultiplelogin) {
9455  user->allowmultiplelogin = ast_true(user_allowmultiplelogin);
9456  }
9457  if (user_writetimeout) {
9458  int value = atoi(user_writetimeout);
9459  if (value < 100) {
9460  ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value);
9461  } else {
9462  user->writetimeout = value;
9463  }
9464  }
9465  }
9466  }
9467  ast_config_destroy(ucfg);
9468  }
9469 
9470  /* cat is NULL here in any case */
9471 
9472  while ((cat = ast_category_browse(cfg, cat))) {
9473  struct ast_acl_list *oldacl;
9474 
9475  if (!strcasecmp(cat, "general")) {
9476  continue;
9477  }
9478 
9479  /* Look for an existing entry, if none found - create one and add it to the list */
9480  if (!(user = get_manager_by_name_locked(cat))) {
9481  if (!(user = ast_calloc(1, sizeof(*user)))) {
9482  break;
9483  }
9484  /* Copy name over */
9485  ast_copy_string(user->username, cat, sizeof(user->username));
9486 
9487  user->acl = NULL;
9488  user->readperm = 0;
9489  user->writeperm = 0;
9490  /* Default displayconnect from [general] */
9492  /* Default allowmultiplelogin from [general] */
9494  user->writetimeout = 100;
9497  if (!user->whitefilters || !user->blackfilters) {
9498  manager_free_user(user);
9499  break;
9500  }
9501 
9502  /* Insert into list */
9503  AST_RWLIST_INSERT_TAIL(&users, user, list);
9504  } else {
9505  ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
9506  ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
9507  }
9508 
9509  /* Make sure we keep this user and don't destroy it during cleanup */
9510  user->keep = 1;
9511  oldacl = user->acl;
9512  user->acl = NULL;
9514 
9515  var = ast_variable_browse(cfg, cat);
9516  for (; var; var = var->next) {
9517  if (!strcasecmp(var->name, "secret")) {
9518  ast_free(user->secret);
9519  user->secret = ast_strdup(var->value);
9520  } else if (!strcasecmp(var->name, "deny") ||
9521  !strcasecmp(var->name, "permit") ||
9522  !strcasecmp(var->name, "acl")) {
9523  int acl_error = 0;
9524 
9525  ast_append_acl(var->name, var->value, &user->acl, &acl_error, &acl_subscription_flag);
9526  if (acl_error) {
9527  ast_log(LOG_ERROR, "Invalid ACL '%s' for manager user '%s' on line %d. Deleting user\n",
9528  var->value, user->username, var->lineno);
9529  user->keep = 0;
9530  }
9531  } else if (!strcasecmp(var->name, "read") ) {
9532  user->readperm = get_perm(var->value);
9533  } else if (!strcasecmp(var->name, "write") ) {
9534  user->writeperm = get_perm(var->value);
9535  } else if (!strcasecmp(var->name, "displayconnects") ) {
9536  user->displayconnects = ast_true(var->value);
9537  } else if (!strcasecmp(var->name, "allowmultiplelogin") ) {
9538  user->allowmultiplelogin = ast_true(var->value);
9539  } else if (!strcasecmp(var->name, "writetimeout")) {
9540  int value = atoi(var->value);
9541  if (value < 100) {
9542  ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
9543  } else {
9544  user->writetimeout = value;
9545  }
9546  } else if (!strcasecmp(var->name, "setvar")) {
9547  struct ast_variable *tmpvar;
9548  char varbuf[256];
9549  char *varval;
9550  char *varname;
9551 
9552  ast_copy_string(varbuf, var->value, sizeof(varbuf));
9553  varname = varbuf;
9554 
9555  if ((varval = strchr(varname,'='))) {
9556  *varval++ = '\0';
9557  if ((tmpvar = ast_variable_new(varname, varval, ""))) {
9558  tmpvar->next = user->chanvars;
9559  user->chanvars = tmpvar;
9560  }
9561  }
9562  } else if (!strcasecmp(var->name, "eventfilter")) {
9563  const char *value = var->value;
9564  manager_add_filter(value, user->whitefilters, user->blackfilters);
9565  } else {
9566  ast_debug(1, "%s is an unknown option.\n", var->name);
9567  }
9568  }
9569 
9570  oldacl = ast_free_acl_list(oldacl);
9571  }
9572  ast_config_destroy(cfg);
9573 
9574  /* Check the flag for named ACL event subscription and if we need to, register a subscription. */
9575  if (acl_subscription_flag && !by_external_config) {
9577  }
9578 
9579  /* Perform cleanup - essentially prune out old users that no longer exist */
9580  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
9581  if (user->keep) { /* valid record. clear flag for the next round */
9582  user->keep = 0;
9583 
9584  /* Calculate A1 for Digest auth */
9585  snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
9586  ast_md5_hash(a1_hash,a1);
9587  ast_free(user->a1_hash);
9588  user->a1_hash = ast_strdup(a1_hash);
9589  continue;
9590  }
9591  /* We do not need to keep this user so take them out of the list */
9593  ast_debug(4, "Pruning user '%s'\n", user->username);
9594  manager_free_user(user);
9595  }
9597 
9599 
9601  if (!webregged) {
9602  ast_http_uri_link(&rawmanuri);
9603  ast_http_uri_link(&manageruri);
9604  ast_http_uri_link(&managerxmluri);
9605 
9606  ast_http_uri_link(&arawmanuri);
9607  ast_http_uri_link(&amanageruri);
9608  ast_http_uri_link(&amanagerxmluri);
9609  webregged = 1;
9610  }
9611  } else {
9612  if (webregged) {
9613  ast_http_uri_unlink(&rawmanuri);
9614  ast_http_uri_unlink(&manageruri);
9615  ast_http_uri_unlink(&managerxmluri);
9616 
9617  ast_http_uri_unlink(&arawmanuri);
9618  ast_http_uri_unlink(&amanageruri);
9619  ast_http_uri_unlink(&amanagerxmluri);
9620  webregged = 0;
9621  }
9622  }
9623 
9624  if (newhttptimeout > 0) {
9625  httptimeout = newhttptimeout;
9626  }
9627 
9628  ast_tcptls_server_start(&ami_desc);
9629  if (tls_was_enabled && !ami_tls_cfg.enabled) {
9630  ast_tcptls_server_stop(&amis_desc);
9631  } else if (ast_ssl_setup(amis_desc.tls_cfg)) {
9632  ast_tcptls_server_start(&amis_desc);
9633  }
9634 
9635  return 0;
9636 }
9638 static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
9639  struct stasis_message *message)
9640 {
9641  if (stasis_message_type(message) != ast_named_acl_change_type()) {
9642  return;
9643  }
9644 
9645  /* For now, this is going to be performed simply and just execute a forced reload. */
9646  ast_log(LOG_NOTICE, "Reloading manager in response to ACL change event.\n");
9647  __init_manager(1, 1);
9648 }
9650 static int unload_module(void)
9651 {
9652  return 0;
9653 }
9655 static int load_module(void)
9656 {
9658 
9660 }
9662 static int reload_module(void)
9663 {
9664  return __init_manager(1, 0);
9665 }
9667 int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
9668 {
9669  AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
9670 
9671  return 0;
9672 }
9674 int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
9675 {
9676  return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
9677 }
9679 struct ast_datastore *astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
9680 {
9681  struct ast_datastore *datastore = NULL;
9682 
9683  if (info == NULL)
9684  return NULL;
9685 
9687  if (datastore->info != info) {
9688  continue;
9689  }
9690 
9691  if (uid == NULL) {
9692  /* matched by type only */
9693  break;
9694  }
9695 
9696  if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
9697  /* Matched by type AND uid */
9698  break;
9699  }
9700  }
9702 
9703  return datastore;
9704 }
9706 int ast_str_append_event_header(struct ast_str **fields_string,
9707  const char *header, const char *value)
9708 {
9709  if (!*fields_string) {
9710  *fields_string = ast_str_create(128);
9711  if (!*fields_string) {
9712  return -1;
9713  }
9714  }
9715 
9716  return (ast_str_append(fields_string, 0, "%s: %s\r\n", header, value) < 0) ? -1 : 0;
9717 }
9719 static void manager_event_blob_dtor(void *obj)
9720 {
9721  struct ast_manager_event_blob *ev = obj;
9722 
9724 }
9725 
9726 struct ast_manager_event_blob *
9727 __attribute__((format(printf, 3, 4)))
9729  int event_flags,
9730  const char *manager_event,
9731  const char *extra_fields_fmt,
9732  ...)
9733 {
9734  struct ast_manager_event_blob *ev;
9735  va_list argp;
9736 
9737  ast_assert(extra_fields_fmt != NULL);
9738  ast_assert(manager_event != NULL);
9739 
9741  if (!ev) {
9742  return NULL;
9743  }
9744 
9745  if (ast_string_field_init(ev, 20)) {
9746  ao2_ref(ev, -1);
9747  return NULL;
9748  }
9749 
9751  ev->event_flags = event_flags;
9752 
9753  va_start(argp, extra_fields_fmt);
9754  ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt, argp);
9755  va_end(argp);
9756 
9757  return ev;
9758 }
9759 
9761  .support_level = AST_MODULE_SUPPORT_CORE,
9762  .load = load_module,
9763  .unload = unload_module,
9764  .reload = reload_module,
9765  .load_pri = AST_MODPRI_CORE,
9766  .requires = "extconfig,acl,http",
9767 );
void ast_iostream_set_exclusive_input(struct ast_iostream *stream, int exclusive_input)
Set the iostream if it can exclusively depend upon the set timeouts.
Definition: iostream.c:148
static char * ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:290
static char user[512]
int ast_category_is_template(const struct ast_category *category)
Check if category is a template.
Definition: main/config.c:1033
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
static int load_module(void)
Definition: manager.c:9654
const char * name
Definition: pbx.h:119
helper function for originate
Definition: manager.c:5375
size_t ast_msg_data_get_length(struct ast_msg_data *msg)
Get length of the structure.
Definition: message.c:1513
const ast_string_field cnonce
Definition: utils.h:672
static int action_challenge(struct mansession *s, const struct message *m)
Definition: manager.c:4442
struct ast_iostream * stream
Definition: manager.c:1627
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category.
Definition: extconf.c:2790
static const char synopsis[]
Definition: app_mysql.c:64
static int get_input(struct mansession *s, char *output)
Definition: manager.c:6735
static int action_loggerrotate(struct mansession *s, const struct message *m)
Manager command "LoggerRotate" - reloads and rotates the logger in the same manner as the CLI command...
Definition: manager.c:6458
struct ast_variable * next
struct timeval tv
Definition: manager.c:1463
struct ao2_container * ast_channel_cache_by_name(void)
Secondary channel cache, indexed by name.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:84
struct ast_variable * ast_variables_reverse(struct ast_variable *var)
Reverse a variable list.
Definition: main/config.c:567
static char * handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:2340
struct ao2_container * blackfilters
Definition: manager.c:1654
static const char type[]
Definition: chan_ooh323.c:109
const ast_string_field data
Struct containing info for an AMI event to send out.
Definition: manager.h:491
static int action_command(struct mansession *s, const struct message *m)
Manager command "command" - execute CLI command.
Definition: manager.c:5295
Information needed to identify an endpoint in a call.
Definition: channel.h:339
enum sip_cc_notify_state state
Definition: chan_sip.c:959
char username[80]
Definition: manager.c:1645
#define AST_RWLIST_NEXT
Definition: linkedlists.h:440
int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
If an extension hint exists, return non-zero.
Definition: pbx.c:4141
char digit
struct ao2_container * whitefilters
Definition: manager.c:1653
#define MAX_VARS
Definition: manager.c:1508
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define EVENT_FLAG_CDR
Definition: manager.h:81
char * pvtfile
Definition: tcptls.h:90
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
static void close_mansession_file(struct mansession *s)
Definition: manager.c:7864
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
static const char * __astman_get_header(const struct message *m, char *var, int mode)
Return a matching header value.
Definition: manager.c:2783
char valid_amount
Definition: aoc.h:179
Main Channel structure associated with a channel.
static int action_originate(struct mansession *s, const struct message *m)
Definition: manager.c:5723
An attempt at basic password authentication failed.
#define AST_CERTFILE
Definition: tcptls.h:62
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
static int check_blacklist(const char *cmd)
Definition: manager.c:5259
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
enum ast_security_event_type event_type
The security event sub-type.
static void astman_append_json(struct mansession *s, const char *str)
Definition: manager.c:3741
static int action_mailboxstatus(struct mansession *s, const struct message *m)
Definition: manager.c:5936
int ast_option_maxfiles
Definition: options.c:81
struct ast_channel_snapshot_base * base
Asterisk locking-related definitions:
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1422
Asterisk main include file. File version handling, generic pbx functions.
int ast_shutting_down(void)
Definition: asterisk.c:1834
const ast_string_field otherchannelid
Definition: manager.c:5393
const ast_string_field uniqueid
Definition: bridge.h:409
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
const char * presence_message
Definition: pbx.h:108
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static void mansession_unlock(struct mansession *s)
Unlock the &#39;mansession&#39; structure.
Definition: manager.c:3257
FYI FWIW, Successful authentication has occurred.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
#define HSMC_FORMAT
Security Event Reporting API.
const ast_string_field tech
Definition: manager.c:5393
void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
Definition: main/config.c:501
static int subscribe_all(void)
Definition: manager.c:9086
const ast_string_field account
Definition: manager.c:5393
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition: loader.c:1819
int astman_verify_session_writepermissions(uint32_t ident, int perm)
Verify a session&#39;s write permissions against a permission mask.
Definition: manager.c:7600
char username[80]
Definition: manager.c:1592
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Definition: linkedlists.h:332
void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text)
Send HTTP error message and close socket.
Definition: http.c:648
const char * expected_response
Response expected to be received.
void ast_manager_unregister_hook(struct manager_custom_hook *hook)
Delete a custom hook to be called when an event is fired.
Definition: manager.c:1942
void ast_tcptls_server_start(struct ast_tcptls_session_args *desc)
This is a generic (re)start routine for a TCP server, which does the socket/bind/listen and starts a ...
Definition: tcptls.c:685
String manipulation functions.
static void astman_start_ack(struct mansession *s, const struct message *m)
Definition: manager.c:3196
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
char * ast_get_chan_features_atxferabort(struct ast_channel *chan)
Get the transfer configuration option atxferabort.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
Definition: ast_expr2.c:325
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:409
int ast_ssl_setup(struct ast_tls_config *cfg)
Set up an SSL server.
Definition: tcptls.c:570
int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
Definition: main/config.c:1399
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:563
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
int ast_aoc_add_unit_entry(struct ast_aoc_decoded *decoded, const unsigned int amount_is_present, const unsigned int amount, const unsigned int type_is_present, const unsigned int type)
Adds a unit entry into the list of units.
Definition: aoc.c:977
static struct ast_threadstorage userevent_buf
Definition: manager.c:3063
#define AST_RWLIST_INSERT_AFTER
Definition: linkedlists.h:701
static int action_reload(struct mansession *s, const struct message *m)
Send a reload event.
Definition: manager.c:6358
Asterisk version information.
static enum ast_transport mansession_get_transport(const struct mansession *s)
Definition: manager.c:3279
static int displayconnects
Definition: manager.c:1470
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
static struct ast_variable * man_do_variable_value(struct ast_variable *head, const char *hdr_val)
Definition: manager.c:2862
#define any_manager_listeners(sessions)
Definition: manager.c:1835
static int action_userevent(struct mansession *s, const struct message *m)
Definition: manager.c:6255
static int webregged
Definition: manager.c:8630
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
const ast_string_field extra_fields
Definition: manager.h:496
struct ast_xml_doc_item * next
Definition: xmldoc.h:80
int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
access for hooks to send action messages to ami
Definition: manager.c:2937
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
Definition: json.c:735
static void report_invalid_user(const struct mansession *s, const char *username)
Definition: manager.c:3285
#define ast_test_flag(p, flag)
Definition: utils.h:63
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
void ast_manager_register_hook(struct manager_custom_hook *hook)
Add a custom hook to be called when an event is fired.
Definition: manager.c:1934
static void manager_default_msg_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: manager.c:1838
struct mansession_session::mansession_datastores datastores
void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval offset)
Set when to hang a channel up.
Definition: channel.c:510
struct stasis_topic * ast_security_topic(void)
A stasis_topic which publishes messages for security related issues.
Support for translation of data formats. translate.c.
int ast_manager_check_enabled(void)
Check if AMI is enabled.
Definition: manager.c:1949
#define GET_HEADER_LAST_MATCH
Definition: manager.c:2767
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
Definition: netsock2.h:171
static void manager_json_to_ast_str(struct ast_json *obj, const char *key, struct ast_str **res, key_exclusion_cb exclusion_cb)
Definition: manager.c:1780
ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buffer, size_t count)
Write data to an iostream.
Definition: iostream.c:374
const char * ast_var_value(const struct ast_var_t *var)
Definition: chanvars.c:80
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm, const unsigned long nonce, const unsigned long opaque, int stale, const char *text)
Send http "401 Unauthorized" response and close socket.
Definition: http.c:622
struct ast_party_name name
Subscriber name.
Definition: channel.h:341
#define OBJ_KEY
Definition: astobj2.h:1155
static void astman_append_headers(struct message *m, const struct ast_variable *params)
Append additional headers into the message structure from params.
Definition: manager.c:2830
An attempt at challenge/response auth failed.
static void json_escape(char *out, const char *in)
Definition: manager.c:3721
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int action_ping(struct mansession *s, const struct message *m)
Definition: manager.c:3602
const char * ast_get_version(void)
Retrieve the Asterisk version string.
Definition: version.c:16
#define HSMCONN_FORMAT1
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
#define MAX_AUTH_PERM_STRING
Definition: manager.c:2043
static struct sessions sessions
pthread_t waiting_thread
Definition: manager.c:1587
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1501
ast_transport
Definition: netsock2.h:59
struct ast_category * ast_category_delete(struct ast_config *cfg, struct ast_category *category)
Delete a category.
Definition: main/config.c:1478
#define ao2_t_global_obj_replace_unref(holder, obj, tag)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:906
#define HSMCONN_FORMAT2
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
int ast_str_append_event_header(struct ast_str **fields_string, const char *header, const char *value)
append an event header to an ast string
Definition: manager.c:9705
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
Iterator for JSON object key/values.
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
int ast_check_hangup_locked(struct ast_channel *chan)
Definition: channel.c:459
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:1562
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3237
struct varshead * ast_channel_get_manager_vars(struct ast_channel *chan)
Gets the variables for a given channel, as specified by ast_channel_set_manager_vars().
Definition: channel.c:8085
ast_module_reload_result
Possible return types for ast_module_reload.
Definition: module.h:109
descriptor for a cli entry.
Definition: cli.h:171
static struct ast_manager_user * get_manager_by_name_locked(const char *name)
Definition: manager.c:2305
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
Definition: time.h:64
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
Definition: http.c:673
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:326
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
int num
Definition: manager.c:2016
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
Definition: taskprocessor.h:63
static struct test_val d
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
int(* func)(struct mansession *s, const struct message *m)
Definition: manager.h:166
#define CONFIG_STATUS_FILEINVALID
#define EVENT_FLAG_COMMAND
Definition: manager.h:75
static int action_login(struct mansession *s, const struct message *m)
Definition: manager.c:4393
static int authenticate(struct mansession *s, const struct message *m)
Definition: manager.c:3505
struct ast_json_iter * ast_json_object_iter(struct ast_json *object)
Get an iterator pointing to the first field in a JSON object.
Definition: json.c:429
#define VERBOSITY_ATLEAST(level)
Definition: logger.h:461
struct ast_tcptls_session_args * parent
Definition: tcptls.h:152
static char * handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:2570
static int timeout
Definition: cdr_mysql.c:86
static int tmp()
Definition: bt_open.c:389
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
char * ast_xmldoc_build_description(const char *type, const char *name, const char *module)
Generate description documentation from XML.
Definition: xmldoc.c:2250
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
int ast_config_text_file_save2(const char *filename, const struct ast_config *cfg, const char *generator, uint32_t flags)
Save a config text file.
Definition: main/config.c:2555
struct eventqent * last_ev
Definition: manager.c:1603
const char * action
Definition: manager.h:151
enum ast_state_cb_update_reason reason
Definition: pbx.h:103
error_type
Definition: manager.c:1419
unsigned int type
Definition: aoc.h:182
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed...
static int get_perm(const char *instr)
Definition: manager.c:2131
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: main/config.c:3154
Structure for variables, used for configurations and for channel variables.
static int ast_manager_register_struct(struct manager_action *act)
Definition: manager.c:7329
#define AST_LOG_WARNING
Definition: logger.h:279
#define var
Definition: ast_expr2f.c:614
struct ast_json * json
Definition: json.h:1025
void MD5Final(unsigned char digest[16], struct MD5Context *context)
Definition: md5.c:120
Structure representing a snapshot of channel state.
static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: manager.c:1869
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
Definition: strings.h:982
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
static struct ast_str * astman_send_list_complete_start_common(struct mansession *s, const struct message *m, const char *event_name, int count)
Definition: manager.c:3206
struct ao2_container * ast_xmldoc_build_documentation(const char *type)
Build the documentation for a particular source type.
Definition: xmldoc.c:2653
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Definition: channel.c:11235
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
void ast_acl_output(int fd, struct ast_acl_list *acl, const char *prefix)
output an ACL to the provided fd
Definition: acl.c:1099
Test Framework API.
void ast_iostream_set_timeout_inactivity(struct ast_iostream *stream, int timeout)
Set the iostream inactivity timeout timer.
Definition: iostream.c:121
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1523
Checking against an IP access control list failed.
static int action_createconfig(struct mansession *s, const struct message *m)
Definition: manager.c:4188
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
Definition: http.c:705
#define EVENT_FLAG_CALL
Definition: manager.h:72
Definition: cli.h:152
static int authtimeout
Definition: manager.c:1479
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:307
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:605
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1079
#define ao2_t_global_obj_release(holder, tag)
Release the ao2 object held in the global holder.
Definition: astobj2.h:863
struct stasis_message_type * ast_named_acl_change_type(void)
a stasis_message_type for changes against a named ACL or the set of all named ACLs ...
static int auth_manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:8501
Structure for a data store type.
Definition: datastore.h:31
Structure used to transport a message through the frame core.
Definition: message.c:1406
static const struct @407 command_blacklist[]
char * term_strip(char *outbuf, const char *inbuf, int maxout)
Remove colorings from a specified string.
Definition: term.c:311
#define ao2_t_link(container, obj, tag)
Add an object to a container.
Definition: astobj2.h:1547
#define EVENT_FLAG_DTMF
Definition: manager.h:79
static void report_req_not_allowed(const struct mansession *s, const char *action)
Definition: manager.c:3385
char * str
Subscriber name (Malloced)
Definition: channel.h:265
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4698
int ast_logger_rotate(void)
Reload logger while rotating log files.
Definition: logger.c:1254
struct ast_iostream * ast_iostream_from_fd(int *fd)
Create an iostream from a file descriptor.
Definition: iostream.c:604
static int manager_moduleload(struct mansession *s, const struct message *m)
Definition: manager.c:6505
Definition: astman.c:222
static void report_session_limit(const struct mansession *s)
Definition: manager.c:3473
static const struct adsi_event events[]
Definition: app_adsiprog.c:85
struct ast_category * prev
Definition: main/config.c:244
struct ast_security_event_common common
Common security event descriptor elements.
static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
send a response with an optional message, and terminate it with an empty line. m is used only to grab...
Definition: manager.c:3123
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static int action_aocmessage(struct mansession *s, const struct message *m)
Definition: manager.c:5518
static struct aco_type item
Definition: test_config.c:1463
#define ao2_global_obj_ref(holder)
Definition: astobj2.h:925
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
const char * response
Response received.
#define EVENT_FLAG_LOG
Definition: manager.h:73
#define EVENT_FLAG_TEST
Definition: manager.h:88
int ast_iostream_get_fd(struct ast_iostream *stream)
Get an iostream&#39;s file descriptor.
Definition: iostream.c:84
static int copy(char *infile, char *outfile)
Utility function to copy a file.
static int process_events(struct mansession *s)
Definition: manager.c:6227
static int action_getconfigjson(struct mansession *s, const struct message *m)
Definition: manager.c:3750
#define EVENT_FLAG_AOC
Definition: manager.h:87
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
arguments for the accepting thread
Definition: tcptls.h:129
static char * handle_manager_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager show settings.
Definition: manager.c:8664
const char * uniqueid
Definition: channel.h:606
Wrapper for an ast_acl linked list.
Definition: acl.h:76
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_assert(a)
Definition: utils.h:695
#define ast_mutex_lock(a)
Definition: lock.h:187
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
double ast_option_maxload
Definition: options.c:77
#define ao2_unlock(a)
Definition: astobj2.h:730
static struct test_val c
ast_mutex_t lock
Definition: manager.c:1632
const char * ast_config_AST_RUN_USER
Definition: options.c:168
Definition: muted.c:95
static const char * authority_to_str(int authority, struct ast_str **res)
Convert authority code to a list of options. Note that the EVENT_FLAG_ALL authority will always be re...
Definition: manager.c:2084
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2315
#define ast_str_alloca(init_len)
Definition: strings.h:800
const ast_string_field username
Definition: utils.h:672
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
uint32_t ast_http_manid_from_vars(struct ast_variable *headers) attribute_pure
Return manager id, if exist, from request headers.
Definition: http.c:217
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2207
struct ast_security_event_common common
Common security event descriptor elements.
#define MAXHOSTNAMELEN
Definition: network.h:69
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
Structure for a data store object.
Definition: datastore.h:68
A request was made that is not allowed.
static int queue_sendtext(struct ast_channel *chan, const char *body)
Queue a read action to send a text message.
Definition: manager.c:4896
ast_aoc_currency_multiplier
Defines the currency multiplier for an aoc message.
Definition: aoc.h:34
const char * str
Definition: app_jack.c:147
struct varshead * ast_channel_varshead(struct ast_channel *chan)
struct ast_sockaddr addr
Definition: manager.c:1583
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
static void session_destructor(void *obj)
Definition: manager.c:2198
struct ast_security_event_common common
Common security event descriptor elements.
static const char *const contenttype[]
Definition: manager.c:7468
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
const char * args
#define MAX_BLACKLIST_CMD_LEN
Descriptor for a manager session, either on the AMI socket or over HTTP.
Definition: manager.c:1523
static struct ast_tcptls_session_args ami_desc
Definition: manager.c:8642
static void report_failed_challenge_response(const struct mansession *s, const char *response, const char *expected_response)
Definition: manager.c:3443
#define MANAGER_EVENT_BUF_INITSIZE
Definition: manager.c:7110
#define NULL
Definition: resample.c:96
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:1490
user descriptor, as read from the config file.
Definition: manager.c:1644
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
static int unauth_sessions
Definition: manager.c:1486
int ast_json_is_null(const struct ast_json *value)
Check if value is JSON null.
Definition: json.c:263
Definitions to aid in the use of thread local storage.
static int action_sendtext(struct mansession *s, const struct message *m)
Definition: manager.c:4930
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:197
struct ast_xml_doc_item * list_responses
Definition: manager.h:160
Out-of-call text message support.
#define EVENT_FLAG_CC
Definition: manager.h:86
char * ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
Generate synopsis documentation from XML.
Definition: xmldoc.c:2227
int value
Definition: syslog.c:37
Generic support for tcp/tls servers in Asterisk.
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
int __ast_manager_event_multichan(int category, const char *event, int chancount, struct ast_channel **chans, const char *file, int line, const char *func, const char *fmt,...)
Definition: manager.c:7233
struct ast_format_cap * cap
Definition: manager.c:5377
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:855
#define AST_FRAME_DTMF
#define AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION
Event descriptor version.
void ast_category_destroy(struct ast_category *cat)
Definition: extconf.c:2847
int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, int early_media, const struct ast_assigned_ids *assignedids)
Synchronously or asynchronously make an outbound call and send it to a particular extension...
Definition: pbx.c:7951
struct ao2_container * blackfilters
Definition: manager.c:1600
int ast_manager_register2(const char *action, int auth, int(*func)(struct mansession *s, const struct message *m), struct ast_module *module, const char *synopsis, const char *description)
register a new command with manager, including online help. This is the preferred way to register a m...
Definition: manager.c:7386
list of users found in the config file
ast_aoc_total_type
Definition: aoc.h:82
static int append_event(const char *str, int category)
events are appended to a queue from where they can be dispatched to clients.
Definition: manager.c:7068
static int action_atxfer(struct mansession *s, const struct message *m)
Definition: manager.c:5164
static int priority
int manager_bridging_init(void)
Initialize support for AMI channel events.
#define EVENT_FLAG_DIALPLAN
Definition: manager.h:82
static int rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:8464
#define AST_FILE_MODE
Definition: asterisk.h:32
static void process_output(struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
Definition: manager.c:7874
void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, int fd, unsigned int static_content)
Generic function for sending HTTP/1.1 response.
Definition: http.c:456
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
Socket address structure.
Definition: netsock2.h:97
char * ast_xmldoc_build_arguments(const char *type, const char *name, const char *module)
Generate the [arguments] tag based on type of node (&#39;application&#39;, &#39;function&#39; or &#39;agi&#39;) and name...
Definition: xmldoc.c:2075
static char cid_num[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:164
static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
Definition: manager.c:5493
static struct ast_str * password
Definition: cdr_mysql.c:77
struct ast_channel_snapshot_dialplan * dialplan
void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt,...)
Send error in manager transaction (with va_args support)
Definition: manager.c:3164
static struct manager_action * action_find(const char *name)
Definition: manager.c:1704
#define ast_verb(level,...)
Definition: logger.h:463
#define EVENT_FLAG_ORIGINATE
Definition: manager.h:83
static struct mansession_session * unref_mansession(struct mansession_session *s)
Unreference manager session object. If no more references, then go ahead and delete it...
Definition: manager.c:2183
#define AST_SEC_EVT(e)
struct ast_trans_pvt * ast_channel_readtrans(const struct ast_channel *chan)
static int manager_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: manager.c:7288
void MD5Init(struct MD5Context *context)
Definition: md5.c:57
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
STASIS_MESSAGE_TYPE_DEFN(ast_manager_get_generic_type)
Define AMI message types.
struct ast_category * ast_category_browse_filtered(struct ast_config *config, const char *category_name, struct ast_category *prev, const char *filter)
Browse categories with filters.
Definition: main/config.c:1335
static void manager_free_user(struct ast_manager_user *user)
Definition: manager.c:8937
struct ast_xml_doc_item * ast_xmldoc_build_final_response(const char *type, const char *name, const char *module)
Generate the [final response] tag based on type of node (&#39;application&#39;, &#39;function&#39; or &#39;agi&#39;) and name...
Definition: xmldoc.c:2528
#define ast_string_field_ptr_build_va(x, ptr, fmt, args)
Set a field to a complex (built) value with prebuilt va_lists.
Definition: stringfields.h:569
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
static int auth_mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:8512
int ast_option_maxcalls
Definition: options.c:79
static char * handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager list eventq.
Definition: manager.c:2706
struct ast_xml_doc_item * ast_xmldoc_build_list_responses(const char *type, const char *name, const char *module)
Generate the [list responses] tag based on type of node (&#39;application&#39;, &#39;function&#39; or &#39;agi&#39;) and name...
Definition: xmldoc.c:2463
const char * uid
Definition: datastore.h:69
struct ast_module * module
Definition: manager.h:167
struct ast_str * ast_category_get_templates(const struct ast_category *category)
Return the template names this category inherits from.
Definition: main/config.c:1038
static int action_filter(struct mansession *s, const struct message *m)
Manager command to add an event filter to a manager session.
Definition: manager.c:6111
static int process_message(struct mansession *s, const struct message *m)
Process an AMI message, performing desired action. Return 0 on success, -1 on error that require the ...
Definition: manager.c:6607
static struct stasis_subscription * acl_change_sub
Definition: manager.c:1487
int ast_category_inherit(struct ast_category *existing, const struct ast_category *base)
Applies base (template) to category.
Definition: main/config.c:1367
int ast_module_check(const char *name)
Check if module with the name given is loaded.
Definition: loader.c:2653
static struct ast_http_uri arawmanuri
Definition: manager.c:8534
Utility functions.
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
Definition: netsock2.h:140
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
static int httptimeout
Definition: manager.c:1473
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
Definition: channel.c:1434
const char * astman_get_header(const struct message *m, char *var)
Return the first matching variable from an array.
Definition: manager.c:2820
static struct mansession_session * find_session(uint32_t ident, int incinuse)
Definition: manager.c:7479
static struct ast_custom_function managerclient_function
description of AMI_CLIENT dialplan function
Definition: manager.c:8624
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define ast_strlen_zero(foo)
Definition: strings.h:52
static const struct permalias perms[]
int ast_realtime_enabled(void)
Check if there&#39;s any realtime engines loaded.
Definition: main/config.c:3377
int ast_webmanager_check_enabled(void)
Check if AMI/HTTP is enabled.
Definition: manager.c:1954
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
enum ast_doc_src docsrc
Definition: manager.h:169
const char * manager_event
Definition: manager.h:493
struct ast_variable * chanvars
Definition: manager.c:1601
void stasis_message_router_set_formatters_default(struct stasis_message_router *router, stasis_subscription_cb callback, void *data, enum stasis_subscription_message_formatters formatters)
Sets the default route of a router with formatters.
#define TEST_STRING
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:1821
int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
Parse an "allow" or "deny" list and modify a format capabilities structure accordingly.
Definition: format_cap.c:320
const char * ast_config_AST_SYSTEM_NAME
Definition: options.c:170
static int mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:8453
int done
Definition: test_amihooks.c:48
struct ast_manager_event_blob * stasis_message_to_ami(struct stasis_message *msg)
Build the AMI representation of the message.
ssize_t ast_iostream_read(struct ast_iostream *stream, void *buffer, size_t count)
Read data from an iostream.
Definition: iostream.c:273
int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan)
set the charging accociation number for an AOC-E message
Definition: aoc.c:1056
static int action_events(struct mansession *s, const struct message *m)
Definition: manager.c:4343
Number structure.
Definition: app_followme.c:154
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. "null" in this sense essentially means uninitialized, or having a 0 length.
Definition: netsock2.h:127
time_t sessiontimeout
Definition: manager.c:1591
static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
Definition: manager.c:7092
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:521
static struct ast_threadstorage manager_event_buf
Definition: manager.c:7109
int ast_cdr_is_enabled(void)
Return TRUE if CDR subsystem is enabled.
Definition: cdr.c:2861
const char * ast_config_AST_RUN_GROUP
Definition: options.c:169
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
An attempt at basic password auth failed.
static void generate_status(struct mansession *s, struct ast_channel *chan, char **vars, int varc, int all_variables, char *id_text, int *count)
Definition: manager.c:4662
static int action_getconfig(struct mansession *s, const struct message *m)
Definition: manager.c:3620
static int generic_http_callback(struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, const struct ast_sockaddr *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:7907
Configuration File Parser.
Support for Private Asterisk HTTP Servers.
enum ast_extension_states exten_state
Definition: pbx.h:104
ast_mutex_t notify_lock
Definition: manager.c:1610
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
static void destroy_fast_originate_helper(struct fast_originate_helper *doomed)
Definition: manager.c:5405
void ast_category_rename(struct ast_category *cat, const char *name)
Definition: main/config.c:1362
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Definition: chan_mgcp.c:204
static int check_manager_session_inuse(const char *name)
Definition: manager.c:2282
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:717
int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Determine number of urgent/new/old messages in a mailbox.
Definition: main/app.c:692
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
const ast_string_field uri
Definition: utils.h:672
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
#define ast_log
Definition: astobj2.c:42
struct ao2_container * whitefilters
Definition: manager.c:1599
const char * request_type
Request type that was made.
struct ast_bridge * ast_channel_get_bridge(const struct ast_channel *chan)
Get the bridge associated with a channel.
Definition: channel.c:10735
static int manager_modulecheck(struct mansession *s, const struct message *m)
Manager function to check if module is loaded.
Definition: manager.c:6470
Generic Advice of Charge encode and decode routines.
static int blackfilter_cmp_fn(void *obj, void *arg, void *data, int flags)
Definition: manager.c:6092
#define AST_LOG_ERROR
Definition: logger.h:290
static void report_inval_password(const struct mansession *s, const char *username)
Definition: manager.c:3335
void * ast_tcptls_server_root(void *)
Definition: tcptls.c:280
enum ast_transfer_result ast_bridge_transfer_blind(int is_external, struct ast_channel *transferer, const char *exten, const char *context, transfer_channel_cb new_channel_cb, void *user_data)
Blind transfer target to the extension and context provided.
Definition: bridge.c:4477
int ast_iostream_close(struct ast_iostream *stream)
Close an iostream.
Definition: iostream.c:528
General Asterisk PBX channel definitions.
Asterisk JSON abstraction layer.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
FILE * in
Definition: utils/frame.c:33
static int action_blind_transfer(struct mansession *s, const struct message *m)
Definition: manager.c:5118
Asterisk file paths, configured in asterisk.conf.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
static void * session_do(void *data)
The body of the individual manager session. Call get_input() to read one line at a time (or be woken ...
Definition: manager.c:6937
struct ast_json * ast_json_object_iter_value(struct ast_json_iter *iter)
Get the value from an iterator.
Definition: json.c:445
const ast_string_field response
Definition: utils.h:672
const ast_string_field appl
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
enum ast_presence_state presence_state
Definition: pbx.h:106
static AO2_GLOBAL_OBJ_STATIC(mgr_sessions)
const int fd
Definition: cli.h:159
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
struct ast_trans_pvt * ast_channel_writetrans(const struct ast_channel *chan)
const ast_string_field description
Definition: manager.h:158
integer order
Definition: analys.c:66
#define AST_PTHREADT_NULL
Definition: lock.h:66
ast_presence_state
Definition: presencestate.h:26
static struct ast_mansession session
struct ast_aoc_encoded * ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
encodes a decoded aoc structure so it can be passed on the wire
Definition: aoc.c:650
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1283
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
Access Control of various sorts.
Request received with bad formatting.
static struct ao2_container * codecs
Registered codecs.
Definition: codec.c:48
#define ASTMAN_APPEND_BUF_INITSIZE
initial allocated size for the astman_append_buf and astman_send_*_va
Definition: manager.c:3066
Request denied because of a session limit.
unsigned int registered
TRUE if the AMI action is registered and the callback can be called.
Definition: manager.h:178
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
helper function for action_updateconfig
Definition: manager.c:3819
static int action_coreshowchannels(struct mansession *s, const struct message *m)
Manager command "CoreShowChannels" - List currently defined channels and some information about them...
Definition: manager.c:6390
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static int action_cancel_atxfer(struct mansession *s, const struct message *m)
Definition: manager.c:5218
const char * ast_extension_state2str(int extension_state)
Return string representation of the state of an extension.
Definition: pbx.c:3126
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
struct ast_variable * ast_category_first(struct ast_category *cat)
given a pointer to a category, return the root variable.
Definition: main/config.c:1157
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
In case you didn&#39;t read that giant block of text above the mansession_session struct, the struct mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1625
const char * presence_subtype
Definition: pbx.h:107
long int ast_random(void)
Definition: main/utils.c:2064
const struct ast_datastore_info * info
Definition: datastore.h:71
#define GET_HEADER_SKIP_EMPTY
Definition: manager.c:2768
#define ao2_lock(a)
Definition: astobj2.h:718
mansession_message_parsing
Definition: manager.c:1615
#define AST_SECURITY_EVENT_FAILED_ACL_VERSION
Event descriptor version.
enum mansession_message_parsing parsing
Definition: manager.c:1629
static char * handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:2497
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:569
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
struct timeval ast_lastreloadtime
Definition: asterisk.c:337
struct ast_variable * chanvars
Definition: manager.c:1657
static int action_logoff(struct mansession *s, const struct message *m)
Definition: manager.c:4387
static int auth_rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:8523
int astman_verify_session_readpermissions(uint32_t ident, int perm)
Verify a session&#39;s read permissions against a permission mask.
Definition: manager.c:7567
char * a1_hash
Definition: manager.c:1656
const ast_string_field cid_num
Definition: manager.c:5393
static struct mansession_session * find_session_by_nonce(const char *username, unsigned long nonce, int *stale)
Definition: manager.c:7518
static void log_action(const struct message *m, const char *action)
Definition: manager.c:6568
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
static struct stasis_forward * test_suite_forwarder
The stasis_subscription for forwarding the Test topic to the AMI topic.
Definition: manager.c:1503
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
static void manager_json_value_str_append(struct ast_json *value, const char *key, struct ast_str **res)
Definition: manager.c:1730
const char * method
Definition: res_pjsip.c:4335
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition: main/utils.c:1656
const ast_string_field exten
Definition: manager.c:5393
static struct ast_http_uri managerxmluri
Definition: manager.c:8491
static struct ast_http_uri manageruri
Definition: manager.c:8483
static void challenge(const char *realm, pjsip_tx_data *tdata, const pjsip_rx_data *rdata, int is_stale)
astobj2 callback for adding digest challenges to responses
A set of macros to manage forward-linked lists.
ast_cli_command
calling arguments for new-style handlers.
Definition: cli.h:151
struct ast_security_event_common common
Common security event descriptor elements.
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
static char * handle_manager_show_events(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:8712
const char * ast_json_object_iter_key(struct ast_json_iter *iter)
Get the key from an iterator.
Definition: json.c:441
struct timeval sessionstart_tv
Definition: manager.c:1590
static int manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:8442
#define EVENT_FLAG_AGI
Definition: manager.h:84
struct ast_security_event_common common
Common security event descriptor elements.
static struct channel_usage channels
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition: stasis.c:618
static int function_amiclient(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
${AMI_CLIENT()} Dialplan function - reads manager client data
Definition: manager.c:8577
#define ast_variable_new(name, value, filename)
static int __manager_event_sessions(struct ao2_container *sessions, int category, const char *event, int chancount, struct ast_channel **chans, const char *file, int line, const char *func, const char *fmt,...)
Definition: manager.c:7211
static struct ast_tls_config ami_tls_cfg
Definition: manager.c:8641
static int unload_module(void)
Definition: manager.c:9649
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
struct ast_variable * vars
Definition: manager.c:5395
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
ast_aoc_charge_type
Definition: aoc.h:69
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
static struct eventqent * advance_event(struct eventqent *e)
Definition: manager.c:2753
#define MSG_MOREDATA
Definition: manager.c:3114
static int authlimit
Definition: manager.c:1480
static int timestampevents
Definition: manager.c:1472
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
static struct ast_tcptls_session_args amis_desc
Definition: manager.c:8653
int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
Remove a datastore from a session.
Definition: manager.c:9673
static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance)
Definition: manager.c:8793
enum ast_acl_sense ast_apply_acl(struct ast_acl_list *acl_list, const struct ast_sockaddr *addr, const char *purpose)
Apply a set of rules to a given IP address.
Definition: acl.c:800
static void manager_shutdown(void)
Definition: manager.c:8956
Core PBX routines and definitions.
static int ast_xml_doc_item_cmp_fn(const void *a, const void *b)
Definition: manager.c:8705
describes a server instance
Definition: tcptls.h:149
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel&#39;s frame queue.
Definition: channel.c:1139
list of actions registered
Definition: manager.c:1665
#define stasis_message_router_create(topic)
void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
Send response in manager transaction.
Definition: manager.c:3154
#define AMI_VERSION
Definition: manager.h:57
void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
Remove all formats matching a specific format type.
Definition: format_cap.c:525
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:544
int ast_acl_list_is_empty(struct ast_acl_list *acl_list)
Determines if an ACL is empty or if it contains entries.
Definition: acl.c:541
#define CONFIG_STATUS_FILEUNCHANGED
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:9727
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:652
static int manager_subscriptions_init(void)
Initialize all Stasis Message Bus API topics and routers used by the various sub-components of AMI...
Definition: manager.c:9053
struct ast_str * description
Definition: xmldoc.h:66
static void acl_change_stasis_unsubscribe(void)
Definition: manager.c:1544
int usecount
Definition: manager.c:1460
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
Definition: term.c:184
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const ast_string_field arguments
Definition: manager.h:158
const char *const * argv
Definition: cli.h:161
struct ast_acl_list * acl
Definition: manager.c:1655
static int __manager_event_sessions_va(struct ao2_container *sessions, int category, const char *event, int chancount, struct ast_channel **chans, const char *file, int line, const char *func, const char *fmt, va_list ap)
Definition: manager.c:7112
static int action_listcommands(struct mansession *s, const struct message *m)
Definition: manager.c:4324
void ast_iostream_set_timeout_disable(struct ast_iostream *stream)
Disable the iostream timeout timer.
Definition: iostream.c:113
int ast_manager_unregister(const char *action)
support functions to register/unregister AMI action handlers,
Definition: manager.c:7258
void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len)
Definition: md5.c:72
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION
Event descriptor version.
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:451
#define GET_HEADER_FIRST_MATCH
Definition: manager.c:2766
static int subscribed
Definition: manager.c:1476
static int __init_manager(int reload, int by_external_config)
Definition: manager.c:9144
Presence state management.
Structure that contains information about a bridge.
Definition: bridge.h:357
struct ast_tcptls_session_instance * tcptls_session
Definition: manager.c:1628
char name[0]
Definition: chanvars.h:31
int ast_aoc_set_billing_id(struct ast_aoc_decoded *decoded, const enum ast_aoc_billing_id id)
set the billing id for a AOC-D or AST_AOC_E message
Definition: aoc.c:1024
ast_aoc_type
Definition: aoc.h:62
void ast_channel_set_manager_vars(size_t varc, char **vars)
Sets the variables to be stored in the manager_vars field of all snapshots.
Definition: channel.c:7989
static struct ast_threadstorage astman_append_buf
Definition: manager.c:3061
static const char * user_authority_to_str(int authority, struct ast_str **res)
Convert authority code to a list of options for a user. This will only display those authority codes ...
Definition: manager.c:2060
static void astman_flush(struct mansession *s, struct ast_str *buf)
Definition: manager.c:3068
static void acl_change_stasis_subscribe(void)
Definition: manager.c:1534
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
static int queue_read_action_payload(struct ast_channel *chan, const unsigned char *payload, size_t payload_size, enum ast_frame_read_action action)
Queue a given read action containing a payload onto a channel.
Definition: manager.c:4864
#define EVENT_FLAG_CONFIG
Definition: manager.h:78
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
static int strings_to_mask(const char *string)
Definition: manager.c:2152
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
static char * handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager list commands.
Definition: manager.c:2613
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
void ast_iostream_set_timeout_sequence(struct ast_iostream *stream, struct timeval start, int timeout)
Set the iostream I/O sequence timeout timer.
Definition: iostream.c:139
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
static int action_mailboxcount(struct mansession *s, const struct message *m)
Definition: manager.c:5953
static int set_eventmask(struct mansession *s, const char *eventmask)
Rather than braindead on,off this now can also accept a specific int mask value or a &#39;...
Definition: manager.c:3266
struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan)
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
static int manager_debug
Definition: manager.c:1478
#define CLI_SHOWUSAGE
Definition: cli.h:45
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:151
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
Retrieve the value of a builtin variable or variable from the channel variable stack.
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:537
static struct stasis_message_router * stasis_router
The stasis_message_router for all Stasis Message Bus API messages.
Definition: manager.c:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
#define ao2_global_obj_release(holder)
Definition: astobj2.h:865
static struct templates templates
struct ast_acl_list * ast_free_acl_list(struct ast_acl_list *acl)
Free a list of ACLs.
Definition: acl.c:233
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
Definition: pbx.c:4184
#define EVENT_FLAG_USER
Definition: manager.h:77
def info(msg)
static void manager_json_array_with_key(struct ast_json *obj, const char *key, size_t index, struct ast_str **res, key_exclusion_cb exclusion_cb)
Definition: manager.c:1755
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
char * value
Definition: chanvars.h:30
int errno
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1743
const ast_string_field appdata
Definition: manager.c:5393
int ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
Inserts new category.
Definition: main/config.c:1083
#define FORMAT
int ast_get_builtin_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
Get the DTMF code for a builtin feature.
struct ast_variable * astman_get_variables(const struct message *m)
Get a linked list of the Variable: headers.
Definition: manager.c:2906
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode)
Unload a module.
Definition: loader.c:1229
variable_orders
Definition: manager.h:282
static void report_failed_acl(const struct mansession *s, const char *username)
Definition: manager.c:3310
struct stasis_topic * ast_test_suite_topic(void)
Definition: test.c:1069
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1714
const char * description
Definition: http.h:102
static void xml_translate(struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
Convert the input into XML or HTML. The input is supposed to be a sequence of lines of the form Name:...
Definition: manager.c:7746
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:260
int allowmultiplelogin
Definition: manager.c:1651
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
const char * words[AST_MAX_CMD_LEN]
Definition: manager.c:1525
An attempt at challenge/response authentication failed.
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:157
void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
Definition: main/config.c:385
#define EVENT_FLAG_AGENT
Definition: manager.h:76
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
struct stasis_message_router * ast_manager_get_message_router(void)
Get the stasis_message_router for AMI.
Definition: manager.c:1725
static int action_waitevent(struct mansession *s, const struct message *m)
Definition: manager.c:4206
struct timeval ast_channel_creationtime(struct ast_channel *chan)
const ast_string_field nc
Definition: utils.h:672
#define LOG_NOTICE
Definition: logger.h:263
static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters)
Add an event filter to a manager session.
Definition: manager.c:6162
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition: format_cap.c:736
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
Definition: strings.h:182
char * cafile
Definition: tcptls.h:92
static int action_timeout(struct mansession *s, const struct message *m)
Definition: manager.c:6044
int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, const struct ast_assigned_ids *assignedids)
Synchronously or asynchronously make an outbound call and execute an application on the channel...
Definition: pbx.c:8015
char * strcasestr(const char *, const char *)
const char * ast_channel_appl(const struct ast_channel *chan)
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10746
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
int astman_is_authed(uint32_t ident)
Determinie if a manager session ident is authenticated.
Definition: manager.c:7551
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
const ast_string_field name
Definition: xmldoc.h:74
int ast_regex_string_to_regex_pattern(const char *regex_string, struct ast_str **regex_pattern)
Given a string regex_string in the form of "/regex/", convert it into the form of "regex"...
Definition: main/utils.c:1931
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
static int action_getvar(struct mansession *s, const struct message *m)
Definition: manager.c:4610
static int match_filter(struct mansession *s, char *eventdata)
Definition: manager.c:6193
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static void event_filter_destructor(void *obj)
Definition: manager.c:2192
#define CLI_FAILURE
Definition: cli.h:46
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
int manager_endpoints_init(void)
Initialize support for AMI endpoint events.
#define AST_CHANNEL_NAME
Definition: channel.h:172
static int reload(void)
Definition: cdr_mysql.c:741
const ast_string_field cid_name
Definition: manager.c:5393
static void report_auth_success(const struct mansession *s)
Definition: manager.c:3360
int ast_aoc_set_total_type(struct ast_aoc_decoded *decoded, const enum ast_aoc_total_type type)
Sets the type of total for a AOC-D message.
Definition: aoc.c:907
#define EVENT_FLAG_SECURITY
Definition: manager.h:89
Module could not be loaded properly.
Definition: module.h:102
#define EVENT_FLAG_HOOKRESPONSE
Definition: manager.h:85
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *result,...)
The argument parsing routine.
Definition: main/config.c:3657
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition: stasis.c:1548
struct ast_iostream * stream
Definition: manager.c:1584
static void astman_free_headers(struct message *m)
Free headers inside message structure, but not the message structure itself.
Definition: manager.c:2844
const char * word
Definition: cli.h:163
static int broken_events_action
Definition: manager.c:1474
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:313
enum ast_json_type ast_json_typeof(const struct ast_json *value)
Get the type of value.
Definition: json.c:78
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:843
unsigned long nc
Definition: manager.c:1609
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1136
int ast_variable_update(struct ast_category *category, const char *variable, const char *value, const char *match, unsigned int object)
Update variable value within a config.
Definition: main/config.c:1444
struct ast_security_event_common common
Common security event descriptor elements.
static struct stasis_forward * security_topic_forwarder
The stasis_subscription for forwarding the Security topic to the AMI topic.
Definition: manager.c:1499
uint32_t managerid
Definition: manager.c:1588
const char * ast_get_http_method(enum ast_http_method method) attribute_pure
Return http method name string.
Definition: http.c:190
static void action_destroy(void *obj)
Definition: manager.c:7372
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
int ast_str_append_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Append to a dynamic string using a va_list.
Definition: strings.h:1000
An API for managing task processing threads that can be shared across modules.
#define manager_event_sessions(sessions, category, event, contents,...)
Definition: manager.c:1832
char * ast_xmldoc_printable(const char *bwinput, int withcolors)
Colorize and put delimiters (instead of tags) to the xmldoc output.
Definition: xmldoc.c:242
char valid_type
Definition: aoc.h:181
char inbuf[1025]
Definition: manager.c:1597
static int action_status(struct mansession *s, const struct message *m)
Manager "status" command to show channels.
Definition: manager.c:4777
static void purge_old_stuff(void *data)
cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most ...
Definition: manager.c:8635
#define DEFAULT_MANAGER_TLS_PORT
Definition: manager.h:59
static int send_string(struct mansession *s, char *string)
Definition: manager.c:3025
int stasis_message_can_be_ami(struct stasis_message *msg)
Determine if the given message can be converted to AMI.
structure to hold users read from users.conf
static int action_coresettings(struct mansession *s, const struct message *m)
Show PBX core settings information.
Definition: manager.c:6276
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:550
Structure used to handle boolean flags.
Definition: utils.h:199
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1720
char * ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
Get the syntax for a specified application or function.
Definition: xmldoc.c:1253
char * ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
Parse the <see-also> node content.
Definition: xmldoc.c:1698
int category
Definition: manager.c:1461
char * certfile
Definition: tcptls.h:89
int ast_app_has_voicemail(const char *mailboxes, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX". If folder is "INBOX", includes the number of messages in the "Urgent" folder.
Definition: main/app.c:655
const ast_string_field data
Definition: manager.c:5393
Definition: md5.h:26
const ast_string_field context
Definition: manager.c:5393
struct ast_iostream * stream
Definition: tcptls.h:160
static char cid_name[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:165
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:414
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
#define DEFAULT_REALM
Definition: manager.c:1483
const char * usage
Definition: cli.h:177
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition: extconf.c:1178
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
#define CONFIG_STATUS_FILEMISSING
Invalid account ID specified (invalid username, for example)
unsigned int write_error
Definition: manager.c:1630
struct ast_aoc_decoded * ast_aoc_create(const enum ast_aoc_type msg_type, const enum ast_aoc_charge_type charge_type, const enum ast_aoc_request requests)
creates a ast_aoc_decode object of a specific message type
Definition: aoc.c:276
void ast_category_append(struct ast_config *config, struct ast_category *cat)
Appends a category to a config.
Definition: extconf.c:2835
const char * ast_channel_data(const struct ast_channel *chan)
Definition: astman.c:88
#define ast_module_running_ref(mod)
Hold a reference to the module if it is running.
Definition: module.h:455
struct ast_category * ast_category_new_template(const char *name, const char *in_file, int lineno)
Create a category making it a template.
Definition: main/config.c:995
struct timeval ast_startuptime
Definition: asterisk.c:336
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:653
#define EVENT_FLAG_REPORTING
Definition: manager.h:80
#define CLI_SUCCESS
Definition: cli.h:44
static int get_manager_sessions_cb(void *obj, void *arg, void *data, int flags)
Get number of logged in sessions for a login name.
Definition: manager.c:8562
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static void parsing(int size, unsigned char *buf, struct unistimsession *pte, struct sockaddr_in *addr_from)
const ast_string_field nonce
Definition: utils.h:672
#define ao2_global_obj_replace_unref(holder, obj)
Definition: astobj2.h:908
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
struct ast_security_event_common common
Common security event descriptor elements.
static struct ast_http_uri amanageruri
Definition: manager.c:8543
struct ast_security_event_common common
Common security event descriptor elements.
#define AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION
Event descriptor version.
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:740
static void load_channelvars(struct ast_variable *var)
Definition: manager.c:8916
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
static struct ast_cli_entry cli_manager[]
Definition: manager.c:8892
#define AST_MAX_PUBLIC_UNIQUEID
Definition: channel.h:148
struct ast_flags ast_options
Definition: options.c:61
int ast_category_empty(struct ast_category *category)
Removes and destroys all variables in a category.
Definition: main/config.c:1510
char * strsep(char **str, const char *delims)
const char * ast_translate_path_to_str(struct ast_trans_pvt *t, struct ast_str **str)
Puts a string representation of the translation path into outbuf.
Definition: translate.c:928
FILE * out
Definition: utils/frame.c:33
struct ast_variable * astman_get_variables_order(const struct message *m, enum variable_orders order)
Get a linked list of the Variable: headers with order specified.
Definition: manager.c:2911
#define DEFAULT_MANAGER_PORT
Definition: manager.h:58
#define ao2_t_callback_data(container, flags, cb_fn, arg, data, tag)
ao2_callback_data() is a generic function that applies cb_fn() to all objects in a container...
Definition: astobj2.h:1741
static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
Definition: manager.c:7707
static int do_message(struct mansession *s)
Definition: manager.c:6852
static int chancount
Definition: channel.c:93
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
static struct mansession_session * build_mansession(const struct ast_sockaddr *addr)
Allocate manager session structure and add it to the list of sessions.
Definition: manager.c:2229
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
unsigned int seq
Definition: manager.c:1462
static struct eventqent * grab_last(void)
Definition: manager.c:1963
#define EVENT_FLAG_SHUTDOWN
Fake event class used to end sessions at shutdown.
Definition: manager.c:1511
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Standard Command Line Interface.
static struct ast_http_uri amanagerxmluri
Definition: manager.c:8552
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
static int manager_enabled
Definition: manager.c:1475
#define MGR_SHOW_TERMINAL_WIDTH
Definition: manager.c:1506
#define ROW_FMT
list of hooks registered
Definition: manager.c:1668
manager_hook_t helper
Definition: manager.h:112
static int action_updateconfig(struct mansession *s, const struct message *m)
Definition: manager.c:4102
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static int function_capable_string_allowed_with_auths(const char *evaluating, int writepermlist)
Checks to see if a string which can be used to evaluate functions should be rejected.
Definition: manager.c:2046
void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag)
Add a rule to an ACL struct.
Definition: acl.c:430
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
Uses hint and devicestate callback to get the state of an extension.
Definition: pbx.c:3170
static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
Definition: manager.c:2112
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
static char * handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager reload.
Definition: manager.c:2734
struct ast_msg_data * ast_msg_data_alloc2(enum ast_msg_data_source_type source_type, const char *to, const char *from, const char *content_type, const char *body)
Allocates an ast_msg_data structure.
Definition: message.c:1469
static struct stasis_forward * rtp_topic_forwarder
The stasis_subscription for forwarding the RTP topic to the AMI topic.
Definition: manager.c:1496
const char * ast_channel_name(const struct ast_channel *chan)
static void mansession_lock(struct mansession *s)
Lock the &#39;mansession&#39; structure.
Definition: manager.c:3251
char * varname
Definition: manager.c:7696
struct ast_datastore * astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a session.
Definition: manager.c:9678
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
const int pos
Definition: cli.h:164
struct ast_channel_snapshot_bridge * bridge
int manager_system_init(void)
Initialize support for AMI system events.
struct stasis_topic * ast_rtp_topic(void)
Stasis Message Bus API topic for RTP and RTCP related messages
Definition: rtp_engine.c:3531
#define EVENT_FLAG_VERBOSE
Definition: manager.h:74
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1360
Asterisk MWI API.
Definition of a URI handler.
Definition: http.h:100
static ENTRY retval
Definition: hsearch.c:50
int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Set the channel to next execute the specified dialplan location.
Definition: pbx.c:7011
ast_aoc_billing_id
Defines the billing id options for an aoc message.
Definition: aoc.h:49
static void * fast_originate(void *data)
Definition: manager.c:5413
static PGresult * result
Definition: cel_pgsql.c:88
char challenge[10]
Definition: manager.c:1593
int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
Add a datastore to a session.
Definition: manager.c:9666
#define AST_FEATURE_MAX_LEN
int ast_queue_control_data(struct ast_channel *chan, enum ast_control_frame_type control, const void *data, size_t datalen)
Queue a control frame with payload.
Definition: channel.c:1238
size_t ast_json_array_size(const struct ast_json *array)
Get the size of a JSON array.
Definition: json.c:356
static int action_hangup(struct mansession *s, const struct message *m)
Definition: manager.c:4460
const ast_string_field app
Definition: manager.c:5393
static void purge_events(void)
Definition: manager.c:1983
struct ast_variable * ast_http_get_post_vars(struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlenco...
Definition: http.c:1353
void ast_iostream_nonblock(struct ast_iostream *stream)
Make an iostream non-blocking.
Definition: iostream.c:103
static int whitefilter_cmp_fn(void *obj, void *arg, void *data, int flags)
Definition: manager.c:6078
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1025
int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value)
Used to parse conf files containing tls/ssl options.
Definition: tcptls.c:875
struct stasis_forward * sub
Definition: res_corosync.c:240
Data structure associated with a single frame of data.
static void manager_json_obj_with_key(struct ast_json *obj, const char *key, const char *parent_key, struct ast_str **res, key_exclusion_cb exclusion_cb)
Definition: manager.c:1765
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
Register a custom function.
#define ast_manager_event_multichan(category, event, nchans, chans, contents,...)
Definition: manager.h:255
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Definition: strings.h:94
const ast_string_field channelid
Definition: manager.c:5393
int(* key_exclusion_cb)(const char *key)
Callback used to determine whether a key should be skipped when converting a JSON object to a manager...
Definition: manager.h:444
const char * headers[AST_MAX_MANHEADERS]
Definition: manager.h:146
static void session_destroy(struct mansession_session *s)
Definition: manager.c:2269
Abstract JSON element (object, array, string, int, ...).
int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic)
Parse digest authorization header.
Definition: main/utils.c:2390
const ast_string_field idtext
Definition: manager.c:5393
Definition: aoc.h:66
static char global_realm[MAXHOSTNAMELEN]
Definition: manager.c:1484
#define AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION
Event descriptor version.
ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan)
struct mansession_session * session
Definition: manager.c:1626
#define AST_RWLIST_REMOVE
Definition: linkedlists.h:884
static struct test_val b
static void handle_parse_error(struct mansession *s, struct message *m, char *error)
Definition: manager.c:6835
Definition: search.h:40
const char * ast_channel_context(const struct ast_channel *chan)
Handy terminal functions for vt* terms.
int error(const char *format,...)
Definition: utils/frame.c:999
static int action_extensionstate(struct mansession *s, const struct message *m)
Definition: manager.c:5974
Forwarding information.
Definition: stasis.c:1531
int ast_aoc_set_association_id(struct ast_aoc_decoded *decoded, const int id)
set the charging association id for an AST_AOC_E message
Definition: aoc.c:1040
Struct that contains the XML documentation for a particular item. Note that this is an ao2 ref counte...
Definition: xmldoc.h:56
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2298
char * capath
Definition: tcptls.h:93
int ast_wait_for_input(int fd, int ms)
Definition: main/utils.c:1519
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
#define AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION
Event descriptor version.
#define PATH_MAX
Definition: asterisk.h:40
void ast_tcptls_server_stop(struct ast_tcptls_session_args *desc)
Shutdown a running server if there is one.
Definition: tcptls.c:849
struct ast_tls_config * tls_cfg
Definition: tcptls.h:134
Invalid formatting of request.
static char * handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:8830
#define ast_mutex_init(pmutex)
Definition: lock.h:184
Generic container type.
static int allowmultiplelogin
Definition: manager.c:1471
#define AST_CLI_YESNO(x)
Return Yes or No depending on the argument.
Definition: cli.h:71
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:861
struct ast_str * arguments
Definition: xmldoc.h:62
const char * uri
Definition: http.h:103
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:280
static struct test_options options
struct ast_sockaddr local_address
Definition: tcptls.h:130
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
ast_group_t ast_channel_callgroup(const struct ast_channel *chan)
static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: manager.c:9637
static int action_corestatus(struct mansession *s, const struct message *m)
Show PBX core status information.
Definition: manager.c:6318
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
ast_http_method
HTTP Request methods known by Asterisk.
Definition: http.h:56
#define AST_RWLIST_FIRST
Definition: linkedlists.h:422
Definition: aoc.h:178
#define ast_mutex_destroy(a)
Definition: lock.h:186
static int webmanager_enabled
Definition: manager.c:1477
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:709
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
Definition: main/config.c:1022
int manager_channels_init(void)
Initialize support for AMI channel events.
const ast_string_field synopsis
Definition: manager.h:158
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1408
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition: pbx.c:3825
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition: stasis.c:1578
int stasis_message_router_set_congestion_limits(struct stasis_message_router *router, long low_water, long high_water)
Set the high and low alert water marks of the stasis message router.
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2726
ast_frame_read_action
Actions to indicate to, and be handled on channel read.
time_t sessionstart
Definition: manager.c:1589
struct ast_str * syntax
Definition: xmldoc.h:58
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()&#39;s, .&#39;s, and -&#39;s...
Definition: callerid.c:947
struct ast_xml_doc_item * final_response
Definition: manager.h:162
struct manager_custom_hook * hook
Definition: manager.c:1631
int ast_security_event_report(const struct ast_security_event_common *sec)
Report a security event.
void ast_md5_hash(char *output, const char *input)
Produces MD5 hash based on input string.
Definition: main/utils.c:248
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:248
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
Pluggable RTP Architecture.
Bridging API.
static const char app[]
Definition: app_mysql.c:62
#define RESULT_SUCCESS
Definition: cli.h:40
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
Asterisk module definitions.
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
output_format
Definition: manager.c:7462
const char * label
Definition: manager.c:2017
static int manager_displayconnects(struct mansession_session *session)
Get displayconnects config option.
Definition: manager.c:2322
unsigned int hdrcount
Definition: manager.h:145
MD5 digest functions.
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:322
static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
Definition: manager.c:7638
#define FORMAT2
#define AST_RWLIST_LAST
Definition: linkedlists.h:430
static void manager_set_defaults(void)
Definition: manager.c:9116
static snd_pcm_format_t format
Definition: chan_alsa.c:102
int ast_active_channels(void)
returns number of active/allocated channels
Definition: channel.c:499
static char * handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:2472
unsigned int amount
Definition: aoc.h:180
const char * uniqueid2
Definition: channel.h:607
void ast_http_request_close_on_completion(struct ast_tcptls_session_instance *ser)
Request the HTTP connection be closed after this HTTP request.
Definition: http.c:836
static int mansession_cmp_fn(void *obj, void *arg, int flags)
Definition: manager.c:2262
struct ast_json * ast_json_array_get(const struct ast_json *array, size_t index)
Get an element from an array.
Definition: json.c:360
static struct prometheus_metrics_provider provider
Definition: bridges.c:178
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static void manager_event_blob_dtor(void *obj)
Definition: manager.c:9718
int manager_mwi_init(void)
Initialize support for AMI MWI events.
Definition: manager_mwi.c:153
void ast_channel_softhangup_withcause_locked(struct ast_channel *chan, int causecode)
Lock the given channel, then request softhangup on the channel with the given causecode.
Definition: channel.c:468
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
Definition: main/config.c:545
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
static int action_redirect(struct mansession *s, const struct message *m)
action_redirect: The redirect manager command
Definition: manager.c:4973
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
unsigned long oldnonce
Definition: manager.c:1608
#define AST_MAX_CMD_LEN
Definition: cli.h:48
char * cipher
Definition: tcptls.h:91
void * data
Definition: http.h:114
static int action_listcategories(struct mansession *s, const struct message *m)
Definition: manager.c:3682
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:616
#define AST_SECURITY_EVENT_SESSION_LIMIT_VERSION
Event descriptor version.
const ast_string_field seealso
Definition: manager.h:158
static struct ast_http_uri rawmanuri
Definition: manager.c:8475
Request denied because it&#39;s not allowed.
const ast_string_field syntax
Definition: manager.h:158
const char * request_type
Request type that was made.
struct ast_str * seealso
Definition: xmldoc.h:60
add_filter_result
Definition: manager.c:1434
const char * ast_category_get_name(const struct ast_category *category)
Return the name of the category.
Definition: main/config.c:1028
Structure for mutex and tracking information.
Definition: lock.h:135
static char * handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager list connected.
Definition: manager.c:2655
static int queue_sendtext_data(struct ast_channel *chan, const char *body, const char *content_type)
Queue a read action to send a text data message.
Definition: manager.c:4911
static void report_req_bad_format(const struct mansession *s, const char *action)
Definition: manager.c:3414
static int auth_http_callback(struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, const struct ast_sockaddr *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:8119
static int variable_count_hash_fn(const void *vvc, const int flags)
Definition: manager.c:7700
static void purge_sessions(int n_max)
remove at most n_max stale session from the list.
Definition: manager.c:7031
const char * ast_presence_state2str(enum ast_presence_state state)
Convert presence state to text string for output.
static int action_presencestate(struct mansession *s, const struct message *m)
Definition: manager.c:6004
jack_status_t status
Definition: app_jack.c:146
void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
Publish an event to AMI.
Definition: manager.c:1903
#define COLOR_MAGENTA
Definition: term.h:57
Definition: aoc.h:65
#define AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION
Event descriptor version.
static int reload_module(void)
Definition: manager.c:9661
Media Format Cache API.
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
struct ast_str * synopsis
Definition: xmldoc.h:64
#define ast_mutex_unlock(a)
Definition: lock.h:188
static char * manager_channelvars
Definition: manager.c:1481
struct ast_json_iter * ast_json_object_iter_next(struct ast_json *object, struct ast_json_iter *iter)
Get the next iterator.
Definition: json.c:437
static int action_setvar(struct mansession *s, const struct message *m)
Definition: manager.c:4577
#define AST_APP_ARG(name)
Define an application argument.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1206
struct ast_sockaddr remote_address
Definition: tcptls.h:151
static void astman_send_list_complete(struct mansession *s, const struct message *m, const char *event_name, int count)
Definition: manager.c:3228
#define EVENT_FLAG_MESSAGE
Definition: manager.h:91
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
Definition: callerid.c:1008
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
int ast_aoc_set_currency_info(struct ast_aoc_decoded *decoded, const unsigned int amount, const enum ast_aoc_currency_multiplier multiplier, const char *name)
Sets the currency values for a AOC-D or AOC-E message.
Definition: aoc.c:919
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3201
static struct test_val a
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343
#define ao2_link(container, obj)
Definition: astobj2.h:1549
int enabled
Definition: tcptls.h:88
#define max(a, b)
Definition: f2c.h:198