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