2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
21 * \brief The Asterisk Management Interface - AMI
23 * \author Mark Spencer <markster@digium.com>
25 * OpenSSL http://www.openssl.org - for AMI/SSL
27 * At the moment this file contains a number of functions, namely:
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
39 /*! \li \ref manager.c uses the configuration file \ref manager.conf and \ref users.conf
40 * \addtogroup configuration_file
43 /*! \page manager.conf manager.conf
44 * \verbinclude manager.conf.sample
47 /*! \page users.conf users.conf
48 * \verbinclude users.conf.sample
52 <support_level>core</support_level>
57 #include "asterisk/paths.h" /* use various ast_config_AST_* */
62 #include <sys/types.h>
65 #include "asterisk/channel.h"
66 #include "asterisk/file.h"
67 #include "asterisk/manager.h"
68 #include "asterisk/module.h"
69 #include "asterisk/config.h"
70 #include "asterisk/callerid.h"
71 #include "asterisk/lock.h"
72 #include "asterisk/cli.h"
73 #include "asterisk/app.h"
74 #include "asterisk/mwi.h"
75 #include "asterisk/pbx.h"
76 #include "asterisk/md5.h"
77 #include "asterisk/acl.h"
78 #include "asterisk/utils.h"
79 #include "asterisk/tcptls.h"
80 #include "asterisk/http.h"
81 #include "asterisk/ast_version.h"
82 #include "asterisk/threadstorage.h"
83 #include "asterisk/linkedlists.h"
84 #include "asterisk/term.h"
85 #include "asterisk/astobj2.h"
86 #include "asterisk/features.h"
87 #include "asterisk/security_events.h"
88 #include "asterisk/aoc.h"
89 #include "asterisk/strings.h"
90 #include "asterisk/stringfields.h"
91 #include "asterisk/presencestate.h"
92 #include "asterisk/stasis_message_router.h"
93 #include "asterisk/stasis_channels.h"
94 #include "asterisk/stasis_bridges.h"
95 #include "asterisk/test.h"
96 #include "asterisk/json.h"
97 #include "asterisk/bridge.h"
98 #include "asterisk/features_config.h"
99 #include "asterisk/rtp_engine.h"
100 #include "asterisk/format_cache.h"
101 #include "asterisk/translate.h"
102 #include "asterisk/taskprocessor.h"
103 #include "asterisk/message.h"
106 <manager name="Ping" language="en_US">
111 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
114 <para>A 'Ping' action will ellicit a 'Pong' response. Used to keep the
115 manager connection open.</para>
118 <manager name="Events" language="en_US">
123 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
124 <parameter name="EventMask" required="true">
127 <para>If all events should be sent.</para>
130 <para>If no events should be sent.</para>
132 <enum name="system,call,log,...">
133 <para>To select which flags events should have to be sent.</para>
139 <para>Enable/Disable sending of events to this manager client.</para>
142 <manager name="Logoff" language="en_US">
147 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
150 <para>Logoff the current manager session.</para>
153 <ref type="manager">Login</ref>
156 <manager name="Login" language="en_US">
161 <parameter name="ActionID">
162 <para>ActionID for this transaction. Will be returned.</para>
164 <parameter name="Username" required="true">
165 <para>Username to login with as specified in manager.conf.</para>
167 <parameter name="Secret">
168 <para>Secret to login with as specified in manager.conf.</para>
172 <para>Login Manager.</para>
175 <ref type="manager">Logoff</ref>
178 <manager name="Challenge" language="en_US">
180 Generate Challenge for MD5 Auth.
183 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
184 <parameter name="AuthType" required="true">
185 <para>Digest algorithm to use in the challenge. Valid values are:</para>
192 <para>Generate a challenge for MD5 authentication.</para>
195 <manager name="Hangup" language="en_US">
200 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
201 <parameter name="Channel" required="true">
202 <para>The exact channel name to be hungup, or to use a regular expression, set this parameter to: /regex/</para>
203 <para>Example exact channel: SIP/provider-0000012a</para>
204 <para>Example regular expression: /^SIP/provider-.*$/</para>
206 <parameter name="Cause">
207 <para>Numeric hangup cause.</para>
211 <para>Hangup a channel.</para>
214 <manager name="Status" language="en_US">
219 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
220 <parameter name="Channel" required="false">
221 <para>The name of the channel to query for status.</para>
223 <parameter name="Variables">
224 <para>Comma <literal>,</literal> separated list of variable to include.</para>
226 <parameter name="AllVariables">
227 <para>If set to "true", the Status event will include all channel variables for
228 the requested channel(s).</para>
236 <para>Will return the status information of each channel along with the
237 value for the specified channel variables.</para>
241 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Status'])" />
243 <xi:include xpointer="xpointer(/docs/managerEvent[@name='StatusComplete'])" />
246 <managerEvent language="en_US" name="Status">
247 <managerEventInstance class="EVENT_FLAG_CALL">
248 <synopsis>Raised in response to a Status command.</synopsis>
250 <parameter name="ActionID" required="false"/>
252 <parameter name="Type">
253 <para>Type of channel</para>
255 <parameter name="DNID">
256 <para>Dialed number identifier</para>
258 <parameter name="EffectiveConnectedLineNum">
260 <parameter name="EffectiveConnectedLineName">
262 <parameter name="TimeToHangup">
263 <para>Absolute lifetime of the channel</para>
265 <parameter name="BridgeID">
266 <para>Identifier of the bridge the channel is in, may be empty if not in one</para>
268 <parameter name="Application">
269 <para>Application currently executing on the channel</para>
271 <parameter name="Data">
272 <para>Data given to the currently executing channel</para>
274 <parameter name="Nativeformats">
275 <para>Media formats the connected party is willing to send or receive</para>
277 <parameter name="Readformat">
278 <para>Media formats that frames from the channel are received in</para>
280 <parameter name="Readtrans">
281 <para>Translation path for media received in native formats</para>
283 <parameter name="Writeformat">
284 <para>Media formats that frames to the channel are accepted in</para>
286 <parameter name="Writetrans">
287 <para>Translation path for media sent to the connected party</para>
289 <parameter name="Callgroup">
290 <para>Configured call group on the channel</para>
292 <parameter name="Pickupgroup">
293 <para>Configured pickup group on the channel</para>
295 <parameter name="Seconds">
296 <para>Number of seconds the channel has been active</para>
300 <ref type="manager">Status</ref>
302 </managerEventInstance>
304 <managerEvent language="en_US" name="StatusComplete">
305 <managerEventInstance class="EVENT_FLAG_CALL">
306 <synopsis>Raised in response to a Status command.</synopsis>
308 <parameter name="Items">
309 <para>Number of Status events returned</para>
313 <ref type="manager">Status</ref>
315 </managerEventInstance>
317 <manager name="Setvar" language="en_US">
319 Sets a channel variable or function value.
322 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
323 <parameter name="Channel">
324 <para>Channel to set variable for.</para>
326 <parameter name="Variable" required="true">
327 <para>Variable name, function or expression.</para>
329 <parameter name="Value" required="true">
330 <para>Variable or function value.</para>
334 <para>This command can be used to set the value of channel variables or dialplan
337 <para>If a channel name is not provided then the variable is considered global.</para>
341 <ref type="manager">Getvar</ref>
344 <manager name="Getvar" language="en_US">
346 Gets a channel variable or function value.
349 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
350 <parameter name="Channel">
351 <para>Channel to read variable from.</para>
353 <parameter name="Variable" required="true">
354 <para>Variable name, function or expression.</para>
358 <para>Get the value of a channel variable or function return.</para>
360 <para>If a channel name is not provided then the variable is considered global.</para>
364 <ref type="manager">Setvar</ref>
367 <manager name="GetConfig" language="en_US">
369 Retrieve configuration.
372 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
373 <parameter name="Filename" required="true">
374 <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
376 <parameter name="Category">
377 <para>Category in configuration file.</para>
379 <parameter name="Filter">
380 <para>A comma separated list of
381 <replaceable>name_regex</replaceable>=<replaceable>value_regex</replaceable>
382 expressions which will cause only categories whose variables match all expressions
383 to be considered. The special variable name <literal>TEMPLATES</literal>
384 can be used to control whether templates are included. Passing
385 <literal>include</literal> as the value will include templates
386 along with normal categories. Passing
387 <literal>restrict</literal> as the value will restrict the operation to
388 ONLY templates. Not specifying a <literal>TEMPLATES</literal> expression
389 results in the default behavior which is to not include templates.</para>
393 <para>This action will dump the contents of a configuration
394 file by category and contents or optionally by specified category only.
395 In the case where a category name is non-unique, a filter may be specified
396 to match only categories with matching variable values.</para>
399 <ref type="manager">GetConfigJSON</ref>
400 <ref type="manager">UpdateConfig</ref>
401 <ref type="manager">CreateConfig</ref>
402 <ref type="manager">ListCategories</ref>
405 <manager name="GetConfigJSON" language="en_US">
407 Retrieve configuration (JSON format).
410 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
411 <parameter name="Filename" required="true">
412 <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
414 <parameter name="Category">
415 <para>Category in configuration file.</para>
417 <parameter name="Filter">
418 <xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
422 <para>This action will dump the contents of a configuration file by category
423 and contents in JSON format or optionally by specified category only.
424 This only makes sense to be used using rawman over the HTTP interface.
425 In the case where a category name is non-unique, a filter may be specified
426 to match only categories with matching variable values.</para>
429 <ref type="manager">GetConfig</ref>
430 <ref type="manager">UpdateConfig</ref>
431 <ref type="manager">CreateConfig</ref>
432 <ref type="manager">ListCategories</ref>
435 <manager name="UpdateConfig" language="en_US">
437 Update basic configuration.
440 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
441 <parameter name="SrcFilename" required="true">
442 <para>Configuration filename to read (e.g. <filename>foo.conf</filename>).</para>
444 <parameter name="DstFilename" required="true">
445 <para>Configuration filename to write (e.g. <filename>foo.conf</filename>)</para>
447 <parameter name="Reload">
448 <para>Whether or not a reload should take place (or name of specific module).</para>
450 <parameter name="PreserveEffectiveContext">
451 <para>Whether the effective category contents should be preserved on template change. Default is true (pre 13.2 behavior).</para>
453 <parameter name="Action-000000">
454 <para>Action to take.</para>
455 <para>0's represent 6 digit number beginning with 000000.</para>
457 <enum name="NewCat" />
458 <enum name="RenameCat" />
459 <enum name="DelCat" />
460 <enum name="EmptyCat" />
461 <enum name="Update" />
462 <enum name="Delete" />
463 <enum name="Append" />
464 <enum name="Insert" />
467 <parameter name="Cat-000000">
468 <para>Category to operate on.</para>
469 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
471 <parameter name="Var-000000">
472 <para>Variable to work on.</para>
473 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
475 <parameter name="Value-000000">
476 <para>Value to work on.</para>
477 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
479 <parameter name="Match-000000">
480 <para>Extra match required to match line.</para>
481 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
483 <parameter name="Line-000000">
484 <para>Line in category to operate on (used with delete and insert actions).</para>
485 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
487 <parameter name="Options-000000">
488 <para>A comma separated list of action-specific options.</para>
490 <enum name="NewCat"><para>One or more of the following... </para>
492 <enum name="allowdups"><para>Allow duplicate category names.</para></enum>
493 <enum name="template"><para>This category is a template.</para></enum>
494 <enum name="inherit="template[,...]""><para>Templates from which to inherit.</para></enum>
499 <para>The following actions share the same options...</para>
501 <enum name="RenameCat"/>
502 <enum name="DelCat"/>
503 <enum name="EmptyCat"/>
504 <enum name="Update"/>
505 <enum name="Delete"/>
506 <enum name="Append"/>
507 <enum name="Insert"><para> </para>
509 <enum name="catfilter="<expression>[,...]""><para> </para>
510 <xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
511 <para><literal>catfilter</literal> is most useful when a file
512 contains multiple categories with the same name and you wish to
513 operate on specific ones instead of all of them.</para>
518 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
522 <para>This action will modify, create, or delete configuration elements
523 in Asterisk configuration files.</para>
526 <ref type="manager">GetConfig</ref>
527 <ref type="manager">GetConfigJSON</ref>
528 <ref type="manager">CreateConfig</ref>
529 <ref type="manager">ListCategories</ref>
532 <manager name="CreateConfig" language="en_US">
534 Creates an empty file in the configuration directory.
537 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
538 <parameter name="Filename" required="true">
539 <para>The configuration filename to create (e.g. <filename>foo.conf</filename>).</para>
543 <para>This action will create an empty file in the configuration
544 directory. This action is intended to be used before an UpdateConfig
548 <ref type="manager">GetConfig</ref>
549 <ref type="manager">GetConfigJSON</ref>
550 <ref type="manager">UpdateConfig</ref>
551 <ref type="manager">ListCategories</ref>
554 <manager name="ListCategories" language="en_US">
556 List categories in configuration file.
559 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
560 <parameter name="Filename" required="true">
561 <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
565 <para>This action will dump the categories in a given file.</para>
568 <ref type="manager">GetConfig</ref>
569 <ref type="manager">GetConfigJSON</ref>
570 <ref type="manager">UpdateConfig</ref>
571 <ref type="manager">CreateConfig</ref>
574 <manager name="Redirect" language="en_US">
576 Redirect (transfer) a call.
579 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
580 <parameter name="Channel" required="true">
581 <para>Channel to redirect.</para>
583 <parameter name="ExtraChannel">
584 <para>Second call leg to transfer (optional).</para>
586 <parameter name="Exten" required="true">
587 <para>Extension to transfer to.</para>
589 <parameter name="ExtraExten">
590 <para>Extension to transfer extrachannel to (optional).</para>
592 <parameter name="Context" required="true">
593 <para>Context to transfer to.</para>
595 <parameter name="ExtraContext">
596 <para>Context to transfer extrachannel to (optional).</para>
598 <parameter name="Priority" required="true">
599 <para>Priority to transfer to.</para>
601 <parameter name="ExtraPriority">
602 <para>Priority to transfer extrachannel to (optional).</para>
606 <para>Redirect (transfer) a call.</para>
609 <ref type="manager">BlindTransfer</ref>
612 <manager name="Atxfer" language="en_US">
617 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
618 <parameter name="Channel" required="true">
619 <para>Transferer's channel.</para>
621 <parameter name="Exten" required="true">
622 <para>Extension to transfer to.</para>
624 <parameter name="Context">
625 <para>Context to transfer to.</para>
629 <para>Attended transfer.</para>
632 <ref type="managerEvent">AttendedTransfer</ref>
635 <manager name="CancelAtxfer" language="en_US">
637 Cancel an attended transfer.
640 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
641 <parameter name="Channel" required="true">
642 <para>The transferer channel.</para>
646 <para>Cancel an attended transfer. Note, this uses the configured cancel attended transfer
647 feature option (atxferabort) to cancel the transfer. If not available this action will fail.
651 <ref type="managerEvent">AttendedTransfer</ref>
654 <manager name="Originate" language="en_US">
659 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
660 <parameter name="Channel" required="true">
661 <para>Channel name to call.</para>
663 <parameter name="Exten">
664 <para>Extension to use (requires <literal>Context</literal> and
665 <literal>Priority</literal>)</para>
667 <parameter name="Context">
668 <para>Context to use (requires <literal>Exten</literal> and
669 <literal>Priority</literal>)</para>
671 <parameter name="Priority">
672 <para>Priority to use (requires <literal>Exten</literal> and
673 <literal>Context</literal>)</para>
675 <parameter name="Application">
676 <para>Application to execute.</para>
678 <parameter name="Data">
679 <para>Data to use (requires <literal>Application</literal>).</para>
681 <parameter name="Timeout" default="30000">
682 <para>How long to wait for call to be answered (in ms.).</para>
684 <parameter name="CallerID">
685 <para>Caller ID to be set on the outgoing channel.</para>
687 <parameter name="Variable">
688 <para>Channel variable to set, multiple Variable: headers are allowed.</para>
690 <parameter name="Account">
691 <para>Account code.</para>
693 <parameter name="EarlyMedia">
694 <para>Set to <literal>true</literal> to force call bridge on early media..</para>
696 <parameter name="Async">
697 <para>Set to <literal>true</literal> for fast origination.</para>
699 <parameter name="Codecs">
700 <para>Comma-separated list of codecs to use for this call.</para>
702 <parameter name="ChannelId">
703 <para>Channel UniqueId to be set on the channel.</para>
705 <parameter name="OtherChannelId">
706 <para>Channel UniqueId to be set on the second local channel.</para>
710 <para>Generates an outgoing call to a
711 <replaceable>Extension</replaceable>/<replaceable>Context</replaceable>/<replaceable>Priority</replaceable>
712 or <replaceable>Application</replaceable>/<replaceable>Data</replaceable></para>
715 <ref type="managerEvent">OriginateResponse</ref>
718 <managerEvent language="en_US" name="OriginateResponse">
719 <managerEventInstance class="EVENT_FLAG_CALL">
720 <synopsis>Raised in response to an Originate command.</synopsis>
722 <parameter name="ActionID" required="false"/>
723 <parameter name="Response">
725 <enum name="Failure"/>
726 <enum name="Success"/>
729 <parameter name="Channel"/>
730 <parameter name="Context"/>
731 <parameter name="Exten"/>
732 <parameter name="Application"/>
733 <parameter name="Data"/>
734 <parameter name="Reason"/>
735 <parameter name="Uniqueid"/>
736 <parameter name="CallerIDNum"/>
737 <parameter name="CallerIDName"/>
740 <ref type="manager">Originate</ref>
742 </managerEventInstance>
744 <manager name="Command" language="en_US">
746 Execute Asterisk CLI Command.
749 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
750 <parameter name="Command" required="true">
751 <para>Asterisk CLI command to run.</para>
755 <para>Run a CLI command.</para>
758 <manager name="ExtensionState" language="en_US">
760 Check Extension Status.
763 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
764 <parameter name="Exten" required="true">
765 <para>Extension to check state on.</para>
767 <parameter name="Context" required="true">
768 <para>Context for extension.</para>
772 <para>Report the extension state for given extension. If the extension has a hint,
773 will use devicestate to check the status of the device connected to the extension.</para>
774 <para>Will return an <literal>Extension Status</literal> message. The response will include
775 the hint for the extension and the status.</para>
778 <ref type="managerEvent">ExtensionStatus</ref>
781 <manager name="PresenceState" language="en_US">
786 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
787 <parameter name="Provider" required="true">
788 <para>Presence Provider to check the state of</para>
792 <para>Report the presence state for the given presence provider.</para>
793 <para>Will return a <literal>Presence State</literal> message. The response will include the
794 presence state and, if set, a presence subtype and custom message.</para>
797 <ref type="managerEvent">PresenceStatus</ref>
800 <manager name="AbsoluteTimeout" language="en_US">
802 Set absolute timeout.
805 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
806 <parameter name="Channel" required="true">
807 <para>Channel name to hangup.</para>
809 <parameter name="Timeout" required="true">
810 <para>Maximum duration of the call (sec).</para>
814 <para>Hangup a channel after a certain time. Acknowledges set time with
815 <literal>Timeout Set</literal> message.</para>
818 <manager name="MailboxStatus" language="en_US">
823 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
824 <parameter name="Mailbox" required="true">
825 <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
829 <para>Checks a voicemail account for status.</para>
830 <para>Returns whether there are messages waiting.</para>
831 <para>Message: Mailbox Status.</para>
832 <para>Mailbox: <replaceable>mailboxid</replaceable>.</para>
833 <para>Waiting: <literal>0</literal> if messages waiting, <literal>1</literal>
834 if no messages waiting.</para>
837 <ref type="manager">MailboxCount</ref>
840 <manager name="MailboxCount" language="en_US">
842 Check Mailbox Message Count.
845 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
846 <parameter name="Mailbox" required="true">
847 <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
851 <para>Checks a voicemail account for new messages.</para>
852 <para>Returns number of urgent, new and old messages.</para>
853 <para>Message: Mailbox Message Count</para>
854 <para>Mailbox: <replaceable>mailboxid</replaceable></para>
855 <para>UrgentMessages: <replaceable>count</replaceable></para>
856 <para>NewMessages: <replaceable>count</replaceable></para>
857 <para>OldMessages: <replaceable>count</replaceable></para>
860 <ref type="manager">MailboxStatus</ref>
863 <manager name="ListCommands" language="en_US">
865 List available manager commands.
868 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
871 <para>Returns the action name and synopsis for every action that
872 is available to the user.</para>
875 <manager name="SendText" language="en_US">
877 Sends a text message to channel. A content type can be optionally specified. If not set
878 it is set to an empty string allowing a custom handler to default it as it sees fit.
881 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
882 <parameter name="Channel" required="true">
883 <para>Channel to send message to.</para>
885 <parameter name="Message" required="true">
886 <para>Message to send.</para>
888 <parameter name="Content-Type" required="false" default="">
889 <para>The type of content in the message</para>
893 <para>Sends A Text Message to a channel while in a call.</para>
896 <ref type="application">SendText</ref>
899 <manager name="UserEvent" language="en_US">
901 Send an arbitrary event.
904 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
905 <parameter name="UserEvent" required="true">
906 <para>Event string to send.</para>
908 <parameter name="Header1">
909 <para>Content1.</para>
911 <parameter name="HeaderN">
912 <para>ContentN.</para>
916 <para>Send an event to manager sessions.</para>
919 <ref type="managerEvent">UserEvent</ref>
920 <ref type="application">UserEvent</ref>
923 <manager name="WaitEvent" language="en_US">
925 Wait for an event to occur.
928 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
929 <parameter name="Timeout" required="true">
930 <para>Maximum time (in seconds) to wait for events, <literal>-1</literal> means forever.</para>
934 <para>This action will ellicit a <literal>Success</literal> response. Whenever
935 a manager event is queued. Once WaitEvent has been called on an HTTP manager
936 session, events will be generated and queued.</para>
939 <manager name="CoreSettings" language="en_US">
941 Show PBX core settings (version etc).
944 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
947 <para>Query for Core PBX settings.</para>
950 <manager name="CoreStatus" language="en_US">
952 Show PBX core status variables.
955 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
958 <para>Query for Core PBX status.</para>
961 <manager name="Reload" language="en_US">
966 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
967 <parameter name="Module">
968 <para>Name of the module to reload.</para>
972 <para>Send a reload event.</para>
975 <ref type="manager">ModuleLoad</ref>
978 <managerEvent language="en_US" name="CoreShowChannel">
979 <managerEventInstance class="EVENT_FLAG_CALL">
980 <synopsis>Raised in response to a CoreShowChannels command.</synopsis>
982 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
984 <parameter name="BridgeId">
985 <para>Identifier of the bridge the channel is in, may be empty if not in one</para>
987 <parameter name="Application">
988 <para>Application currently executing on the channel</para>
990 <parameter name="ApplicationData">
991 <para>Data given to the currently executing application</para>
993 <parameter name="Duration">
994 <para>The amount of time the channel has existed</para>
998 <ref type="manager">CoreShowChannels</ref>
999 <ref type="managerEvent">CoreShowChannelsComplete</ref>
1001 </managerEventInstance>
1003 <managerEvent language="en_US" name="CoreShowChannelsComplete">
1004 <managerEventInstance class="EVENT_FLAG_CALL">
1005 <synopsis>Raised at the end of the CoreShowChannel list produced by the CoreShowChannels command.</synopsis>
1007 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1008 <parameter name="EventList">
1009 <para>Conveys the status of the command reponse list</para>
1011 <parameter name="ListItems">
1012 <para>The total number of list items produced</para>
1016 <ref type="manager">CoreShowChannels</ref>
1017 <ref type="managerEvent">CoreShowChannel</ref>
1019 </managerEventInstance>
1021 <manager name="CoreShowChannels" language="en_US">
1023 List currently active channels.
1026 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1029 <para>List currently defined channels and some information about them.</para>
1033 <xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannel'])" />
1035 <xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannelsComplete'])" />
1038 <manager name="LoggerRotate" language="en_US">
1040 Reload and rotate the Asterisk logger.
1043 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1046 <para>Reload and rotate the logger. Analogous to the CLI command 'logger rotate'.</para>
1049 <manager name="ModuleLoad" language="en_US">
1054 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1055 <parameter name="Module">
1056 <para>Asterisk module name (including .so extension) or subsystem identifier:</para>
1059 <enum name="dnsmgr" />
1060 <enum name="extconfig" />
1061 <enum name="enum" />
1063 <enum name="manager" />
1064 <enum name="http" />
1065 <enum name="logger" />
1066 <enum name="features" />
1068 <enum name="udptl" />
1069 <enum name="indications" />
1074 <parameter name="LoadType" required="true">
1075 <para>The operation to be done on module. Subsystem identifiers may only
1078 <enum name="load" />
1079 <enum name="unload" />
1080 <enum name="reload" />
1082 <para>If no module is specified for a <literal>reload</literal> loadtype,
1083 all modules are reloaded.</para>
1087 <para>Loads, unloads or reloads an Asterisk module in a running system.</para>
1090 <ref type="manager">Reload</ref>
1091 <ref type="manager">ModuleCheck</ref>
1094 <manager name="ModuleCheck" language="en_US">
1096 Check if module is loaded.
1099 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1100 <parameter name="Module" required="true">
1101 <para>Asterisk module name (not including extension).</para>
1105 <para>Checks if Asterisk module is loaded. Will return Success/Failure.
1106 For success returns, the module revision number is included.</para>
1109 <ref type="manager">ModuleLoad</ref>
1112 <manager name="AOCMessage" language="en_US">
1114 Generate an Advice of Charge message on a channel.
1117 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1118 <parameter name="Channel" required="true">
1119 <para>Channel name to generate the AOC message on.</para>
1121 <parameter name="ChannelPrefix">
1122 <para>Partial channel prefix. By using this option one can match the beginning part
1123 of a channel name without having to put the entire name in. For example
1124 if a channel name is SIP/snom-00000001 and this value is set to SIP/snom, then
1125 that channel matches and the message will be sent. Note however that only
1126 the first matched channel has the message sent on it. </para>
1128 <parameter name="MsgType" required="true">
1129 <para>Defines what type of AOC message to create, AOC-D or AOC-E</para>
1135 <parameter name="ChargeType" required="true">
1136 <para>Defines what kind of charge this message represents.</para>
1139 <enum name="FREE" />
1140 <enum name="Currency" />
1141 <enum name="Unit" />
1144 <parameter name="UnitAmount(0)">
1145 <para>This represents the amount of units charged. The ETSI AOC standard specifies that
1146 this value along with the optional UnitType value are entries in a list. To accommodate this
1147 these values take an index value starting at 0 which can be used to generate this list of
1148 unit entries. For Example, If two unit entires were required this could be achieved by setting the
1149 paramter UnitAmount(0)=1234 and UnitAmount(1)=5678. Note that UnitAmount at index 0 is
1150 required when ChargeType=Unit, all other entries in the list are optional.
1153 <parameter name="UnitType(0)">
1154 <para>Defines the type of unit. ETSI AOC standard specifies this as an integer
1155 value between 1 and 16, but this value is left open to accept any positive
1156 integer. Like the UnitAmount parameter, this value represents a list entry
1157 and has an index parameter that starts at 0.
1160 <parameter name="CurrencyName">
1161 <para>Specifies the currency's name. Note that this value is truncated after 10 characters.</para>
1163 <parameter name="CurrencyAmount">
1164 <para>Specifies the charge unit amount as a positive integer. This value is required
1165 when ChargeType==Currency.</para>
1167 <parameter name="CurrencyMultiplier">
1168 <para>Specifies the currency multiplier. This value is required when ChargeType==Currency.</para>
1170 <enum name="OneThousandth" />
1171 <enum name="OneHundredth" />
1172 <enum name="OneTenth" />
1175 <enum name="Hundred" />
1176 <enum name="Thousand" />
1179 <parameter name="TotalType" default="Total">
1180 <para>Defines what kind of AOC-D total is represented.</para>
1182 <enum name="Total" />
1183 <enum name="SubTotal" />
1186 <parameter name="AOCBillingId">
1187 <para>Represents a billing ID associated with an AOC-D or AOC-E message. Note
1188 that only the first 3 items of the enum are valid AOC-D billing IDs</para>
1190 <enum name="Normal" />
1191 <enum name="ReverseCharge" />
1192 <enum name="CreditCard" />
1193 <enum name="CallFwdUnconditional" />
1194 <enum name="CallFwdBusy" />
1195 <enum name="CallFwdNoReply" />
1196 <enum name="CallDeflection" />
1197 <enum name="CallTransfer" />
1200 <parameter name="ChargingAssociationId">
1201 <para>Charging association identifier. This is optional for AOC-E and can be
1202 set to any value between -32768 and 32767</para>
1204 <parameter name="ChargingAssociationNumber">
1205 <para>Represents the charging association party number. This value is optional
1208 <parameter name="ChargingAssociationPlan">
1209 <para>Integer representing the charging plan associated with the ChargingAssociationNumber.
1210 The value is bits 7 through 1 of the Q.931 octet containing the type-of-number and
1211 numbering-plan-identification fields.</para>
1215 <para>Generates an AOC-D or AOC-E message on a channel.</para>
1218 <ref type="managerEvent">AOC-D</ref>
1219 <ref type="managerEvent">AOC-E</ref>
1222 <function name="AMI_CLIENT" language="en_US">
1224 Checks attributes of manager accounts
1227 <parameter name="loginname" required="true">
1228 <para>Login name, specified in manager.conf</para>
1230 <parameter name="field" required="true">
1231 <para>The manager account attribute to return</para>
1233 <enum name="sessions"><para>The number of sessions for this AMI account</para></enum>
1239 Currently, the only supported parameter is "sessions" which will return the current number of
1240 active sessions for this AMI account.
1244 <manager name="Filter" language="en_US">
1246 Dynamically add filters for the current manager session.
1249 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1250 <parameter name="Operation">
1253 <para>Add a filter.</para>
1257 <parameter name="Filter">
1258 <para>Filters can be whitelist or blacklist</para>
1259 <para>Example whitelist filter: "Event: Newchannel"</para>
1260 <para>Example blacklist filter: "!Channel: DAHDI.*"</para>
1261 <para>This filter option is used to whitelist or blacklist events per user to be
1262 reported with regular expressions and are allowed if both the regex matches
1263 and the user has read access as defined in manager.conf. Filters are assumed to be for whitelisting
1264 unless preceeded by an exclamation point, which marks it as being black.
1265 Evaluation of the filters is as follows:</para>
1266 <para>- If no filters are configured all events are reported as normal.</para>
1267 <para>- If there are white filters only: implied black all filter processed first, then white filters.</para>
1268 <para>- If there are black filters only: implied white all filter processed first, then black filters.</para>
1269 <para>- If there are both white and black filters: implied black all filter processed first, then white
1270 filters, and lastly black filters.</para>
1274 <para>The filters added are only used for the current session.
1275 Once the connection is closed the filters are removed.</para>
1276 <para>This comand requires the system permission because
1277 this command can be used to create filters that may bypass
1278 filters defined in manager.conf</para>
1281 <ref type="manager">FilterList</ref>
1284 <manager name="FilterList" language="en_US">
1286 Show current event filters for this session
1289 <para>The filters displayed are for the current session. Only those filters defined in
1290 manager.conf will be present upon starting a new session.</para>
1293 <ref type="manager">Filter</ref>
1296 <manager name="BlindTransfer" language="en_US">
1298 Blind transfer channel(s) to the given destination
1301 <parameter name="Channel" required="true">
1303 <parameter name="Context">
1305 <parameter name="Exten">
1309 <para>Redirect all channels currently bridged to the specified channel to the specified destination.</para>
1312 <ref type="manager">Redirect</ref>
1313 <ref type="managerEvent">BlindTransfer</ref>
1316 <managerEvent name="ExtensionStatus" language="en_US">
1317 <managerEventInstance class="EVENT_FLAG_CALL">
1318 <synopsis>Raised when a hint changes due to a device state change.</synopsis>
1320 <parameter name="Exten">
1321 <para>Name of the extension.</para>
1323 <parameter name="Context">
1324 <para>Context that owns the extension.</para>
1326 <parameter name="Hint">
1327 <para>Hint set for the extension</para>
1329 <parameter name="Status">
1330 <para>Numerical value of the extension status. Extension
1331 status is determined by the combined device state of all items
1332 contained in the hint.</para>
1335 <para>The extension was removed from the dialplan.</para>
1338 <para>The extension's hint was removed from the dialplan.</para>
1341 <para><literal>Idle</literal> - Related device(s) are in an idle
1345 <para><literal>InUse</literal> - Related device(s) are in active
1346 calls but may take more calls.</para>
1349 <para><literal>Busy</literal> - Related device(s) are in active
1350 calls and may not take any more calls.</para>
1353 <para><literal>Unavailable</literal> - Related device(s) are
1354 not reachable.</para>
1357 <para><literal>Ringing</literal> - Related device(s) are
1358 currently ringing.</para>
1361 <para><literal>InUse&Ringing</literal> - Related device(s)
1362 are currently ringing and in active calls.</para>
1365 <para><literal>Hold</literal> - Related device(s) are
1366 currently on hold.</para>
1369 <para><literal>InUse&Hold</literal> - Related device(s)
1370 are currently on hold and in active calls.</para>
1374 <parameter name="StatusText">
1375 <para>Text representation of <literal>Status</literal>.</para>
1377 <enum name="Idle" />
1378 <enum name="InUse" />
1379 <enum name="Busy" />
1380 <enum name="Unavailable" />
1381 <enum name="Ringing" />
1382 <enum name="InUse&Ringing" />
1383 <enum name="Hold" />
1384 <enum name="InUse&Hold" />
1385 <enum name="Unknown">
1386 <para>Status does not match any of the above values.</para>
1392 <ref type="manager">ExtensionState</ref>
1394 </managerEventInstance>
1396 <managerEvent name="PresenceStatus" language="en_US">
1397 <managerEventInstance class="EVENT_FLAG_CALL">
1398 <synopsis>Raised when a hint changes due to a presence state change.</synopsis>
1400 <parameter name="Exten" />
1401 <parameter name="Context" />
1402 <parameter name="Hint" />
1403 <parameter name="Status" />
1404 <parameter name="Subtype" />
1405 <parameter name="Message" />
1408 <ref type="manager">PresenceState</ref>
1410 </managerEventInstance>
1414 /*! \addtogroup Group_AMI AMI functions
1422 UNSPECIFIED_CATEGORY,
1423 UNSPECIFIED_ARGUMENT,
1434 enum add_filter_result {
1436 FILTER_ALLOC_FAILED,
1437 FILTER_COMPILE_FAIL,
1441 * Linked list of events.
1442 * Global events are appended to the list by append_event().
1443 * The usecount is the number of stored pointers to the element,
1444 * excluding the list pointers. So an element that is only in
1445 * the list has a usecount of 0, not 1.
1447 * Clients have a pointer to the last event processed, and for each
1448 * of these clients we track the usecount of the elements.
1449 * If we have a pointer to an entry in the list, it is safe to navigate
1450 * it forward because elements will not be deleted, but only appended.
1451 * The worst that can happen is seeing the pointer still NULL.
1453 * When the usecount of an element drops to 0, and the element is the
1454 * first in the list, we can remove it. Removal is done within the
1455 * main thread, which is woken up for the purpose.
1457 * For simplicity of implementation, we make sure the list is never empty.
1460 int usecount; /*!< # of clients who still need the event */
1462 unsigned int seq; /*!< sequence number */
1463 struct timeval tv; /*!< When event was allocated */
1464 AST_RWLIST_ENTRY(eventqent) eq_next;
1465 char eventdata[1]; /*!< really variable size, allocated by append_event() */
1468 static AST_RWLIST_HEAD_STATIC(all_events, eventqent);
1470 static int displayconnects = 1;
1471 static int allowmultiplelogin = 1;
1472 static int timestampevents;
1473 static int httptimeout = 60;
1474 static int broken_events_action = 0;
1475 static int manager_enabled = 0;
1476 static int subscribed = 0;
1477 static int webmanager_enabled = 0;
1478 static int manager_debug = 0; /*!< enable some debugging code in the manager */
1479 static int authtimeout;
1480 static int authlimit;
1481 static char *manager_channelvars;
1483 #define DEFAULT_REALM "asterisk"
1484 static char global_realm[MAXHOSTNAMELEN]; /*!< Default realm */
1486 static int unauth_sessions = 0;
1487 static struct stasis_subscription *acl_change_sub;
1489 /*! \brief A \ref stasis_topic that all topics AMI cares about will be forwarded to */
1490 static struct stasis_topic *manager_topic;
1492 /*! \brief The \ref stasis_message_router for all \ref stasis messages */
1493 static struct stasis_message_router *stasis_router;
1495 /*! \brief The \ref stasis_subscription for forwarding the RTP topic to the AMI topic */
1496 static struct stasis_forward *rtp_topic_forwarder;
1498 /*! \brief The \ref stasis_subscription for forwarding the Security topic to the AMI topic */
1499 static struct stasis_forward *security_topic_forwarder;
1501 #ifdef TEST_FRAMEWORK
1502 /*! \brief The \ref stasis_subscription for forwarding the Test topic to the AMI topic */
1503 static struct stasis_forward *test_suite_forwarder;
1506 #define MGR_SHOW_TERMINAL_WIDTH 80
1508 #define MAX_VARS 128
1510 /*! \brief Fake event class used to end sessions at shutdown */
1511 #define EVENT_FLAG_SHUTDOWN -1
1514 * Descriptor for a manager session, either on the AMI socket or over HTTP.
1517 * AMI session have managerid == 0; the entry is created upon a connect,
1518 * and destroyed with the socket.
1519 * HTTP sessions have managerid != 0, the value is used as a search key
1520 * to lookup sessions (using the mansession_id cookie, or nonce key from
1521 * Digest Authentication http header).
1523 #define MAX_BLACKLIST_CMD_LEN 2
1524 static const struct {
1525 const char *words[AST_MAX_CMD_LEN];
1526 } command_blacklist[] = {
1527 {{ "module", "load", NULL }},
1528 {{ "module", "unload", NULL }},
1529 {{ "restart", "gracefully", NULL }},
1532 static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
1534 static void acl_change_stasis_subscribe(void)
1536 if (!acl_change_sub) {
1537 acl_change_sub = stasis_subscribe(ast_security_topic(),
1538 acl_change_stasis_cb, NULL);
1539 stasis_subscription_accept_message_type(acl_change_sub, ast_named_acl_change_type());
1540 stasis_subscription_set_filter(acl_change_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
1544 static void acl_change_stasis_unsubscribe(void)
1546 acl_change_sub = stasis_unsubscribe_and_join(acl_change_sub);
1549 /* In order to understand what the heck is going on with the
1550 * mansession_session and mansession structs, we need to have a bit of a history
1553 * In the beginning, there was the mansession. The mansession contained data that was
1554 * intrinsic to a manager session, such as the time that it started, the name of the logged-in
1555 * user, etc. In addition to these parameters were the f and fd parameters. For typical manager
1556 * sessions, these were used to represent the TCP socket over which the AMI session was taking
1557 * place. It makes perfect sense for these fields to be a part of the session-specific data since
1558 * the session actually defines this information.
1560 * Then came the HTTP AMI sessions. With these, the f and fd fields need to be opened and closed
1561 * for every single action that occurs. Thus the f and fd fields aren't really specific to the session
1562 * but rather to the action that is being executed. Because a single session may execute many commands
1563 * at once, some sort of safety needed to be added in order to be sure that we did not end up with fd
1564 * leaks from one action overwriting the f and fd fields used by a previous action before the previous action
1565 * has had a chance to properly close its handles.
1567 * The initial idea to solve this was to use thread synchronization, but this prevented multiple actions
1568 * from being run at the same time in a single session. Some manager actions may block for a long time, thus
1569 * creating a large queue of actions to execute. In addition, this fix did not address the basic architectural
1570 * issue that for HTTP manager sessions, the f and fd variables are not really a part of the session, but are
1571 * part of the action instead.
1573 * The new idea was to create a structure on the stack for each HTTP Manager action. This structure would
1574 * contain the action-specific information, such as which file to write to. In order to maintain expectations
1575 * of action handlers and not have to change the public API of the manager code, we would need to name this
1576 * new stacked structure 'mansession' and contain within it the old mansession struct that we used to use.
1577 * We renamed the old mansession struct 'mansession_session' to hopefully convey that what is in this structure
1578 * is session-specific data. The structure that it is wrapped in, called a 'mansession' really contains action-specific
1581 struct mansession_session {
1582 /*! \todo XXX need to document which fields it is protecting */
1583 struct ast_sockaddr addr; /*!< address we are connecting from */
1584 struct ast_iostream *stream; /*!< AMI stream */
1585 int inuse; /*!< number of HTTP sessions using this entry */
1586 int needdestroy; /*!< Whether an HTTP session should be destroyed */
1587 pthread_t waiting_thread; /*!< Sleeping thread using this descriptor */
1588 uint32_t managerid; /*!< Unique manager identifier, 0 for AMI sessions */
1589 time_t sessionstart; /*!< Session start time */
1590 struct timeval sessionstart_tv; /*!< Session start time */
1591 time_t sessiontimeout; /*!< Session timeout if HTTP */
1592 char username[80]; /*!< Logged in username */
1593 char challenge[10]; /*!< Authentication challenge */
1594 int authenticated; /*!< Authentication status */
1595 int readperm; /*!< Authorization for reading */
1596 int writeperm; /*!< Authorization for writing */
1597 char inbuf[1025]; /*!< Buffer - we use the extra byte to add a '\\0' and simplify parsing */
1598 int inlen; /*!< number of buffered bytes */
1599 struct ao2_container *whitefilters; /*!< Manager event filters - white list */
1600 struct ao2_container *blackfilters; /*!< Manager event filters - black list */
1601 struct ast_variable *chanvars; /*!< Channel variables to set for originate */
1602 int send_events; /*!< XXX what ? */
1603 struct eventqent *last_ev; /*!< last event processed. */
1604 int writetimeout; /*!< Timeout for ast_carefulwrite() */
1606 int pending_event; /*!< Pending events indicator in case when waiting_thread is NULL */
1607 time_t noncetime; /*!< Timer for nonce value expiration */
1608 unsigned long oldnonce; /*!< Stale nonce value */
1609 unsigned long nc; /*!< incremental nonce counter */
1610 ast_mutex_t notify_lock; /*!< Lock for notifying this session of events */
1611 AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore) datastores; /*!< Data stores on the session */
1612 AST_LIST_ENTRY(mansession_session) list;
1615 enum mansession_message_parsing {
1617 MESSAGE_LINE_TOO_LONG
1620 /*! \brief In case you didn't read that giant block of text above the mansession_session struct, the
1621 * \ref struct mansession is named this solely to keep the API the same in Asterisk. This structure really
1622 * represents data that is different from Manager action to Manager action. The mansession_session pointer
1623 * contained within points to session-specific data.
1626 struct mansession_session *session;
1627 struct ast_iostream *stream;
1628 struct ast_tcptls_session_instance *tcptls_session;
1629 enum mansession_message_parsing parsing;
1630 unsigned int write_error:1;
1631 struct manager_custom_hook *hook;
1635 /*! Active manager connection sessions container. */
1636 static AO2_GLOBAL_OBJ_STATIC(mgr_sessions);
1638 /*! \brief user descriptor, as read from the config file.
1640 * \note It is still missing some fields -- e.g. we can have multiple permit and deny
1641 * lines which are not supported here, and readperm/writeperm/writetimeout
1644 struct ast_manager_user {
1646 char *secret; /*!< Secret for logging in */
1647 int readperm; /*!< Authorization for reading */
1648 int writeperm; /*!< Authorization for writing */
1649 int writetimeout; /*!< Per user Timeout for ast_carefulwrite() */
1650 int displayconnects; /*!< XXX unused */
1651 int allowmultiplelogin; /*!< Per user option*/
1652 int keep; /*!< mark entries created on a reload */
1653 struct ao2_container *whitefilters; /*!< Manager event filters - white list */
1654 struct ao2_container *blackfilters; /*!< Manager event filters - black list */
1655 struct ast_acl_list *acl; /*!< ACL setting */
1656 char *a1_hash; /*!< precalculated A1 for Digest auth */
1657 struct ast_variable *chanvars; /*!< Channel variables to set for originate */
1658 AST_RWLIST_ENTRY(ast_manager_user) list;
1661 /*! \brief list of users found in the config file */
1662 static AST_RWLIST_HEAD_STATIC(users, ast_manager_user);
1664 /*! \brief list of actions registered */
1665 static AST_RWLIST_HEAD_STATIC(actions, manager_action);
1667 /*! \brief list of hooks registered */
1668 static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook);
1671 /*! \brief A container of event documentation nodes */
1672 static AO2_GLOBAL_OBJ_STATIC(event_docs);
1675 static int __attribute__((format(printf, 9, 0))) __manager_event_sessions(
1676 struct ao2_container *sessions,
1680 struct ast_channel **chans,
1686 static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters);
1688 static int match_filter(struct mansession *s, char *eventdata);
1691 * @{ \brief Define AMI message types.
1693 STASIS_MESSAGE_TYPE_DEFN(ast_manager_get_generic_type);
1698 * \brief Find a registered action object.
1700 * \param name Name of AMI action to find.
1702 * \return Reffed action found or NULL
1704 static struct manager_action *action_find(const char *name)
1706 struct manager_action *act;
1708 AST_RWLIST_RDLOCK(&actions);
1709 AST_RWLIST_TRAVERSE(&actions, act, list) {
1710 if (!strcasecmp(name, act->action)) {
1711 ao2_t_ref(act, +1, "found action object");
1715 AST_RWLIST_UNLOCK(&actions);
1720 struct stasis_topic *ast_manager_get_topic(void)
1722 return manager_topic;
1725 struct stasis_message_router *ast_manager_get_message_router(void)
1727 return stasis_router;
1730 static void manager_json_value_str_append(struct ast_json *value, const char *key,
1731 struct ast_str **res)
1733 switch (ast_json_typeof(value)) {
1734 case AST_JSON_STRING:
1735 ast_str_append(res, 0, "%s: %s\r\n", key, ast_json_string_get(value));
1737 case AST_JSON_INTEGER:
1738 ast_str_append(res, 0, "%s: %jd\r\n", key, ast_json_integer_get(value));
1741 ast_str_append(res, 0, "%s: True\r\n", key);
1743 case AST_JSON_FALSE:
1744 ast_str_append(res, 0, "%s: False\r\n", key);
1747 ast_str_append(res, 0, "%s: \r\n", key);
1752 static void manager_json_to_ast_str(struct ast_json *obj, const char *key,
1753 struct ast_str **res, key_exclusion_cb exclusion_cb);
1755 static void manager_json_array_with_key(struct ast_json *obj, const char* key,
1756 size_t index, struct ast_str **res,
1757 key_exclusion_cb exclusion_cb)
1759 struct ast_str *key_str = ast_str_alloca(64);
1760 ast_str_set(&key_str, 0, "%s(%zu)", key, index);
1761 manager_json_to_ast_str(obj, ast_str_buffer(key_str),
1765 static void manager_json_obj_with_key(struct ast_json *obj, const char* key,
1766 const char *parent_key, struct ast_str **res,
1767 key_exclusion_cb exclusion_cb)
1770 struct ast_str *key_str = ast_str_alloca(64);
1771 ast_str_set(&key_str, 0, "%s/%s", parent_key, key);
1772 manager_json_to_ast_str(obj, ast_str_buffer(key_str),
1777 manager_json_to_ast_str(obj, key, res, exclusion_cb);
1780 void manager_json_to_ast_str(struct ast_json *obj, const char *key,
1781 struct ast_str **res, key_exclusion_cb exclusion_cb)
1783 struct ast_json_iter *i;
1785 /* If obj or res is not given, just return */
1790 if (!*res && !(*res = ast_str_create(1024))) {
1794 if (exclusion_cb && key && exclusion_cb(key)) {
1798 if (ast_json_typeof(obj) != AST_JSON_OBJECT &&
1799 ast_json_typeof(obj) != AST_JSON_ARRAY) {
1800 manager_json_value_str_append(obj, key, res);
1804 if (ast_json_typeof(obj) == AST_JSON_ARRAY) {
1806 for (j = 0; j < ast_json_array_size(obj); ++j) {
1807 manager_json_array_with_key(ast_json_array_get(obj, j),
1808 key, j, res, exclusion_cb);
1813 for (i = ast_json_object_iter(obj); i;
1814 i = ast_json_object_iter_next(obj, i)) {
1815 manager_json_obj_with_key(ast_json_object_iter_value(i),
1816 ast_json_object_iter_key(i),
1817 key, res, exclusion_cb);
1821 struct ast_str *ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
1823 struct ast_str *res = ast_str_create(1024);
1825 if (!ast_json_is_null(blob)) {
1826 manager_json_to_ast_str(blob, NULL, &res, exclusion_cb);
1832 #define manager_event_sessions(sessions, category, event, contents , ...) \
1833 __manager_event_sessions(sessions, category, event, 0, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, contents , ## __VA_ARGS__)
1835 #define any_manager_listeners(sessions) \
1836 ((sessions && ao2_container_count(sessions)) || !AST_RWLIST_EMPTY(&manager_hooks))
1838 static void manager_default_msg_cb(void *data, struct stasis_subscription *sub,
1839 struct stasis_message *message)
1841 struct ao2_container *sessions;
1842 struct ast_manager_event_blob *ev;
1844 if (!stasis_message_can_be_ami(message)) {
1845 /* Not an AMI message; disregard */
1849 sessions = ao2_global_obj_ref(mgr_sessions);
1850 if (!any_manager_listeners(sessions)) {
1851 /* Nobody is listening */
1852 ao2_cleanup(sessions);
1856 ev = stasis_message_to_ami(message);
1858 /* Conversion failure */
1859 ao2_cleanup(sessions);
1863 manager_event_sessions(sessions, ev->event_flags, ev->manager_event,
1864 "%s", ev->extra_fields);
1866 ao2_cleanup(sessions);
1869 static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub,
1870 struct stasis_message *message)
1872 struct ast_json_payload *payload;
1875 struct ast_json *event;
1876 struct ast_str *event_buffer;
1877 struct ao2_container *sessions;
1879 sessions = ao2_global_obj_ref(mgr_sessions);
1880 if (!any_manager_listeners(sessions)) {
1881 /* Nobody is listening */
1882 ao2_cleanup(sessions);
1886 payload = stasis_message_data(message);
1887 class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type"));
1888 type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
1889 event = ast_json_object_get(payload->json, "event");
1891 event_buffer = ast_manager_str_from_json_object(event, NULL);
1892 if (!event_buffer) {
1893 ast_log(AST_LOG_WARNING, "Error while creating payload for event %s\n", type);
1894 ao2_cleanup(sessions);
1897 manager_event_sessions(sessions, class_type, type,
1898 "%s", ast_str_buffer(event_buffer));
1899 ast_free(event_buffer);
1900 ao2_cleanup(sessions);
1903 void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
1905 RAII_VAR(struct ast_json *, event_info, NULL, ast_json_unref);
1906 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
1907 RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
1909 if (!obj || !ast_manager_get_generic_type()) {
1914 event_info = ast_json_pack("{s: s, s: i, s: o}",
1916 "class_type", class_type,
1922 payload = ast_json_payload_create(event_info);
1926 message = stasis_message_create(ast_manager_get_generic_type(), payload);
1930 stasis_publish(ast_manager_get_topic(), message);
1933 /*! \brief Add a custom hook to be called when an event is fired */
1934 void ast_manager_register_hook(struct manager_custom_hook *hook)
1936 AST_RWLIST_WRLOCK(&manager_hooks);
1937 AST_RWLIST_INSERT_TAIL(&manager_hooks, hook, list);
1938 AST_RWLIST_UNLOCK(&manager_hooks);
1941 /*! \brief Delete a custom hook to be called when an event is fired */
1942 void ast_manager_unregister_hook(struct manager_custom_hook *hook)
1944 AST_RWLIST_WRLOCK(&manager_hooks);
1945 AST_RWLIST_REMOVE(&manager_hooks, hook, list);
1946 AST_RWLIST_UNLOCK(&manager_hooks);
1949 int ast_manager_check_enabled(void)
1951 return manager_enabled;
1954 int ast_webmanager_check_enabled(void)
1956 return (webmanager_enabled && manager_enabled);
1960 * Grab a reference to the last event, update usecount as needed.
1961 * Can handle a NULL pointer.
1963 static struct eventqent *grab_last(void)
1965 struct eventqent *ret;
1967 AST_RWLIST_WRLOCK(&all_events);
1968 ret = AST_RWLIST_LAST(&all_events);
1969 /* the list is never empty now, but may become so when
1970 * we optimize it in the future, so be prepared.
1973 ast_atomic_fetchadd_int(&ret->usecount, 1);
1975 AST_RWLIST_UNLOCK(&all_events);
1980 * Purge unused events. Remove elements from the head
1981 * as long as their usecount is 0 and there is a next element.
1983 static void purge_events(void)
1985 struct eventqent *ev;
1986 struct timeval now = ast_tvnow();
1988 AST_RWLIST_WRLOCK(&all_events);
1989 while ( (ev = AST_RWLIST_FIRST(&all_events)) &&
1990 ev->usecount == 0 && AST_RWLIST_NEXT(ev, eq_next)) {
1991 AST_RWLIST_REMOVE_HEAD(&all_events, eq_next);
1995 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&all_events, ev, eq_next) {
1996 /* Never release the last event */
1997 if (!AST_RWLIST_NEXT(ev, eq_next)) {
2001 /* 2.5 times whatever the HTTP timeout is (maximum 2.5 hours) is the maximum time that we will definitely cache an event */
2002 if (ev->usecount == 0 && ast_tvdiff_sec(now, ev->tv) > (httptimeout > 3600 ? 3600 : httptimeout) * 2.5) {
2003 AST_RWLIST_REMOVE_CURRENT(eq_next);
2007 AST_RWLIST_TRAVERSE_SAFE_END;
2008 AST_RWLIST_UNLOCK(&all_events);
2012 * helper functions to convert back and forth between
2013 * string and numeric representation of set of flags
2015 static const struct permalias {
2019 { EVENT_FLAG_SYSTEM, "system" },
2020 { EVENT_FLAG_CALL, "call" },
2021 { EVENT_FLAG_LOG, "log" },
2022 { EVENT_FLAG_VERBOSE, "verbose" },
2023 { EVENT_FLAG_COMMAND, "command" },
2024 { EVENT_FLAG_AGENT, "agent" },
2025 { EVENT_FLAG_USER, "user" },
2026 { EVENT_FLAG_CONFIG, "config" },
2027 { EVENT_FLAG_DTMF, "dtmf" },
2028 { EVENT_FLAG_REPORTING, "reporting" },
2029 { EVENT_FLAG_CDR, "cdr" },
2030 { EVENT_FLAG_DIALPLAN, "dialplan" },
2031 { EVENT_FLAG_ORIGINATE, "originate" },
2032 { EVENT_FLAG_AGI, "agi" },
2033 { EVENT_FLAG_CC, "cc" },
2034 { EVENT_FLAG_AOC, "aoc" },
2035 { EVENT_FLAG_TEST, "test" },
2036 { EVENT_FLAG_SECURITY, "security" },
2037 { EVENT_FLAG_MESSAGE, "message" },
2042 /*! Maximum string length of the AMI authority permission string buildable from perms[]. */
2043 #define MAX_AUTH_PERM_STRING 150
2045 /*! \brief Checks to see if a string which can be used to evaluate functions should be rejected */
2046 static int function_capable_string_allowed_with_auths(const char *evaluating, int writepermlist)
2048 if (!(writepermlist & EVENT_FLAG_SYSTEM)
2050 strstr(evaluating, "SHELL") || /* NoOp(${SHELL(rm -rf /)}) */
2051 strstr(evaluating, "EVAL") /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
2058 /*! \brief Convert authority code to a list of options for a user. This will only
2059 * display those authority codes that have an explicit match on authority */
2060 static const char *user_authority_to_str(int authority, struct ast_str **res)
2065 ast_str_reset(*res);
2066 for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
2067 if ((authority & perms[i].num) == perms[i].num) {
2068 ast_str_append(res, 0, "%s%s", sep, perms[i].label);
2073 if (ast_str_strlen(*res) == 0) {
2074 /* replace empty string with something sensible */
2075 ast_str_append(res, 0, "<none>");
2078 return ast_str_buffer(*res);
2082 /*! \brief Convert authority code to a list of options. Note that the EVENT_FLAG_ALL
2083 * authority will always be returned. */
2084 static const char *authority_to_str(int authority, struct ast_str **res)
2089 ast_str_reset(*res);
2090 if (authority != EVENT_FLAG_SHUTDOWN) {
2091 for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
2092 if (authority & perms[i].num) {
2093 ast_str_append(res, 0, "%s%s", sep, perms[i].label);
2099 if (ast_str_strlen(*res) == 0) {
2100 /* replace empty string with something sensible */
2101 ast_str_append(res, 0, "<none>");
2104 return ast_str_buffer(*res);
2107 /*! Tells you if smallstr exists inside bigstr
2108 which is delim by delim and uses no buf or stringsep
2109 ast_instring("this|that|more","this",'|') == 1;
2111 feel free to move this to app.c -anthm */
2112 static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
2114 const char *val = bigstr, *next;
2117 if ((next = strchr(val, delim))) {
2118 if (!strncmp(val, smallstr, (next - val))) {
2124 return !strcmp(smallstr, val);
2126 } while (*(val = (next + 1)));
2131 static int get_perm(const char *instr)
2139 for (x = 0; x < ARRAY_LEN(perms); x++) {
2140 if (ast_instring(instr, perms[x].label, ',')) {
2141 ret |= perms[x].num;
2149 * A number returns itself, false returns 0, true returns all flags,
2150 * other strings return the flags that are set.
2152 static int strings_to_mask(const char *string)
2156 if (ast_strlen_zero(string)) {
2160 for (p = string; *p; p++) {
2161 if (*p < '0' || *p > '9') {
2165 if (!*p) { /* all digits */
2166 return atoi(string);
2168 if (ast_false(string)) {
2171 if (ast_true(string)) { /* all permissions */
2173 for (x = 0; x < ARRAY_LEN(perms); x++) {
2174 ret |= perms[x].num;
2178 return get_perm(string);
2181 /*! \brief Unreference manager session object.
2182 If no more references, then go ahead and delete it */
2183 static struct mansession_session *unref_mansession(struct mansession_session *s)
2185 int refcount = ao2_ref(s, -1);
2186 if (manager_debug) {
2187 ast_debug(1, "Mansession: %p refcount now %d\n", s, refcount - 1);
2192 static void event_filter_destructor(void *obj)
2194 regex_t *regex_filter = obj;
2195 regfree(regex_filter);
2198 static void session_destructor(void *obj)
2200 struct mansession_session *session = obj;
2201 struct eventqent *eqe = session->last_ev;
2202 struct ast_datastore *datastore;
2204 /* Get rid of each of the data stores on the session */
2205 while ((datastore = AST_LIST_REMOVE_HEAD(&session->datastores, entry))) {
2206 /* Free the data store */
2207 ast_datastore_free(datastore);
2211 ast_atomic_fetchadd_int(&eqe->usecount, -1);
2213 if (session->chanvars) {
2214 ast_variables_destroy(session->chanvars);
2217 if (session->whitefilters) {
2218 ao2_t_ref(session->whitefilters, -1, "decrement ref for white container, should be last one");
2221 if (session->blackfilters) {
2222 ao2_t_ref(session->blackfilters, -1, "decrement ref for black container, should be last one");
2225 ast_mutex_destroy(&session->notify_lock);
2228 /*! \brief Allocate manager session structure and add it to the list of sessions */
2229 static struct mansession_session *build_mansession(const struct ast_sockaddr *addr)
2231 struct ao2_container *sessions;
2232 struct mansession_session *newsession;
2234 newsession = ao2_alloc(sizeof(*newsession), session_destructor);
2239 newsession->whitefilters = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
2240 newsession->blackfilters = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
2241 if (!newsession->whitefilters || !newsession->blackfilters) {
2242 ao2_ref(newsession, -1);
2246 newsession->waiting_thread = AST_PTHREADT_NULL;
2247 newsession->writetimeout = 100;
2248 newsession->send_events = -1;
2249 ast_sockaddr_copy(&newsession->addr, addr);
2251 ast_mutex_init(&newsession->notify_lock);
2253 sessions = ao2_global_obj_ref(mgr_sessions);
2255 ao2_link(sessions, newsession);
2256 ao2_ref(sessions, -1);
2262 static int mansession_cmp_fn(void *obj, void *arg, int flags)
2264 struct mansession_session *s = obj;
2266 return !strcasecmp(s->username, str) ? CMP_MATCH : 0;
2269 static void session_destroy(struct mansession_session *s)
2271 struct ao2_container *sessions;
2273 sessions = ao2_global_obj_ref(mgr_sessions);
2275 ao2_unlink(sessions, s);
2276 ao2_ref(sessions, -1);
2278 unref_mansession(s);
2282 static int check_manager_session_inuse(const char *name)
2284 struct ao2_container *sessions;
2285 struct mansession_session *session;
2288 sessions = ao2_global_obj_ref(mgr_sessions);
2290 session = ao2_find(sessions, (char *) name, 0);
2291 ao2_ref(sessions, -1);
2293 unref_mansession(session);
2302 * lookup an entry in the list of registered users.
2303 * must be called with the list lock held.
2305 static struct ast_manager_user *get_manager_by_name_locked(const char *name)
2307 struct ast_manager_user *user = NULL;
2309 AST_RWLIST_TRAVERSE(&users, user, list) {
2310 if (!strcasecmp(user->username, name)) {
2318 /*! \brief Get displayconnects config option.
2319 * \param session manager session to get parameter from.
2320 * \return displayconnects config option value.
2322 static int manager_displayconnects(struct mansession_session *session)
2324 struct ast_manager_user *user = NULL;
2327 AST_RWLIST_RDLOCK(&users);
2328 if ((user = get_manager_by_name_locked(session->username))) {
2329 ret = user->displayconnects;
2331 AST_RWLIST_UNLOCK(&users);
2337 static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance);
2340 static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2342 struct manager_action *cur;
2343 struct ast_str *authority;
2346 const char *auth_str;
2348 char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64];
2349 char arguments_title[64], privilege_title[64], final_response_title[64], list_responses_title[64];
2354 e->command = "manager show command";
2356 "Usage: manager show command <actionname> [<actionname> [<actionname> [...]]]\n"
2357 " Shows the detailed description for a specific Asterisk manager interface command.\n";
2360 l = strlen(a->word);
2361 AST_RWLIST_RDLOCK(&actions);
2362 AST_RWLIST_TRAVERSE(&actions, cur, list) {
2363 if (!strncasecmp(a->word, cur->action, l)) {
2364 if (ast_cli_completion_add(ast_strdup(cur->action))) {
2369 AST_RWLIST_UNLOCK(&actions);
2373 return CLI_SHOWUSAGE;
2376 authority = ast_str_alloca(MAX_AUTH_PERM_STRING);
2379 /* setup the titles */
2380 term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2381 term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
2382 term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
2383 term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
2384 term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
2385 term_color(privilege_title, "[Privilege]\n", COLOR_MAGENTA, 0, 40);
2386 term_color(final_response_title, "[Final Response]\n", COLOR_MAGENTA, 0, 40);
2387 term_color(list_responses_title, "[List Responses]\n", COLOR_MAGENTA, 0, 40);
2390 AST_RWLIST_RDLOCK(&actions);
2391 AST_RWLIST_TRAVERSE(&actions, cur, list) {
2392 for (num = 3; num < a->argc; num++) {
2393 if (!strcasecmp(cur->action, a->argv[num])) {
2394 auth_str = authority_to_str(cur->authority, &authority);
2397 if (cur->docsrc == AST_XML_DOC) {
2398 char *syntax = ast_xmldoc_printable(S_OR(cur->syntax, "Not available"), 1);
2399 char *synopsis = ast_xmldoc_printable(S_OR(cur->synopsis, "Not available"), 1);
2400 char *description = ast_xmldoc_printable(S_OR(cur->description, "Not available"), 1);
2401 char *arguments = ast_xmldoc_printable(S_OR(cur->arguments, "Not available"), 1);
2402 char *seealso = ast_xmldoc_printable(S_OR(cur->seealso, "Not available"), 1);
2403 char *privilege = ast_xmldoc_printable(S_OR(auth_str, "Not available"), 1);
2404 char *responses = ast_xmldoc_printable("None", 1);
2406 if (!syntax || !synopsis || !description || !arguments
2407 || !seealso || !privilege || !responses) {
2410 ast_free(description);
2411 ast_free(arguments);
2413 ast_free(privilege);
2414 ast_free(responses);
2415 ast_cli(a->fd, "Allocation failure.\n");
2416 AST_RWLIST_UNLOCK(&actions);
2421 ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s",
2422 syntax_title, syntax,
2423 synopsis_title, synopsis,
2424 description_title, description,
2425 arguments_title, arguments,
2426 seealso_title, seealso,
2427 privilege_title, privilege,
2428 list_responses_title);
2430 if (!cur->list_responses) {
2431 ast_cli(a->fd, "%s\n\n", responses);
2433 struct ast_xml_doc_item *temp;
2434 for (temp = cur->list_responses; temp; temp = AST_LIST_NEXT(temp, next)) {
2435 ast_cli(a->fd, "Event: %s\n", temp->name);
2436 print_event_instance(a, temp);
2440 ast_cli(a->fd, "%s", final_response_title);
2442 if (!cur->final_response) {
2443 ast_cli(a->fd, "%s\n\n", responses);
2445 ast_cli(a->fd, "Event: %s\n", cur->final_response->name);
2446 print_event_instance(a, cur->final_response);
2451 ast_free(description);
2452 ast_free(arguments);
2454 ast_free(privilege);
2455 ast_free(responses);
2459 ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
2460 cur->action, cur->synopsis,
2462 S_OR(cur->description, ""));
2467 AST_RWLIST_UNLOCK(&actions);
2472 static char *handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2476 e->command = "manager set debug [on|off]";
2477 e->usage = "Usage: manager set debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
2484 ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
2485 } else if (a->argc == 4) {
2486 if (!strcasecmp(a->argv[3], "on")) {
2488 } else if (!strcasecmp(a->argv[3], "off")) {
2491 return CLI_SHOWUSAGE;
2497 static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2499 struct ast_manager_user *user = NULL;
2501 struct ast_str *rauthority = ast_str_alloca(MAX_AUTH_PERM_STRING);
2502 struct ast_str *wauthority = ast_str_alloca(MAX_AUTH_PERM_STRING);
2503 struct ast_variable *v;
2507 e->command = "manager show user";
2509 " Usage: manager show user <user>\n"
2510 " Display all information related to the manager user specified.\n";
2513 l = strlen(a->word);
2517 AST_RWLIST_RDLOCK(&users);
2518 AST_RWLIST_TRAVERSE(&users, user, list) {
2519 if (!strncasecmp(a->word, user->username, l)) {
2520 if (ast_cli_completion_add(ast_strdup(user->username))) {
2525 AST_RWLIST_UNLOCK(&users);
2530 return CLI_SHOWUSAGE;
2533 AST_RWLIST_RDLOCK(&users);
2535 if (!(user = get_manager_by_name_locked(a->argv[3]))) {
2536 ast_cli(a->fd, "There is no manager called %s\n", a->argv[3]);
2537 AST_RWLIST_UNLOCK(&users);
2541 ast_cli(a->fd, "\n");
2548 " displayconnects: %s\n"
2549 "allowmultiplelogin: %s\n",
2550 S_OR(user->username, "(N/A)"),
2551 (user->secret ? "<Set>" : "(N/A)"),
2552 ((user->acl && !ast_acl_list_is_empty(user->acl)) ? "yes" : "no"),
2553 user_authority_to_str(user->readperm, &rauthority),
2554 user_authority_to_str(user->writeperm, &wauthority),
2555 (user->displayconnects ? "yes" : "no"),
2556 (user->allowmultiplelogin ? "yes" : "no"));
2557 ast_cli(a->fd, " Variables: \n");
2558 for (v = user->chanvars ; v ; v = v->next) {
2559 ast_cli(a->fd, " %s = %s\n", v->name, v->value);
2561 if (!ast_acl_list_is_empty(user->acl)) {
2562 ast_acl_output(a->fd, user->acl, NULL);
2565 AST_RWLIST_UNLOCK(&users);
2570 static char *handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2572 struct ast_manager_user *user = NULL;
2576 e->command = "manager show users";
2578 "Usage: manager show users\n"
2579 " Prints a listing of all managers that are currently configured on that\n"
2586 return CLI_SHOWUSAGE;
2589 AST_RWLIST_RDLOCK(&users);
2591 /* If there are no users, print out something along those lines */
2592 if (AST_RWLIST_EMPTY(&users)) {
2593 ast_cli(a->fd, "There are no manager users.\n");
2594 AST_RWLIST_UNLOCK(&users);
2598 ast_cli(a->fd, "\nusername\n--------\n");
2600 AST_RWLIST_TRAVERSE(&users, user, list) {
2601 ast_cli(a->fd, "%s\n", user->username);
2605 AST_RWLIST_UNLOCK(&users);
2607 ast_cli(a->fd,"-------------------\n"
2608 "%d manager users configured.\n", count_amu);
2612 /*! \brief CLI command manager list commands */
2613 static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2615 struct manager_action *cur;
2617 int space_remaining;
2618 #define HSMC_FORMAT " %-*.*s %-.*s\n"
2621 e->command = "manager show commands";
2623 "Usage: manager show commands\n"
2624 " Prints a listing of all the available Asterisk manager interface commands.\n";
2630 AST_RWLIST_RDLOCK(&actions);
2631 AST_RWLIST_TRAVERSE(&actions, cur, list) {
2632 int incoming_len = strlen(cur->action);
2633 if (incoming_len > name_len) {
2634 name_len = incoming_len;
2638 space_remaining = MGR_SHOW_TERMINAL_WIDTH - name_len - 4;
2639 if (space_remaining < 0) {
2640 space_remaining = 0;
2643 ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, "Action", space_remaining, "Synopsis");
2644 ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, "------", space_remaining, "--------");
2646 AST_RWLIST_TRAVERSE(&actions, cur, list) {
2647 ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, cur->action, space_remaining, cur->synopsis);
2649 AST_RWLIST_UNLOCK(&actions);
2654 /*! \brief CLI command manager list connected */
2655 static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2657 struct ao2_container *sessions;
2658 struct mansession_session *session;
2659 time_t now = time(NULL);
2660 #define HSMCONN_FORMAT1 " %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
2661 #define HSMCONN_FORMAT2 " %-15.15s %-55.55s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
2663 struct ao2_iterator i;
2667 e->command = "manager show connected";
2669 "Usage: manager show connected\n"
2670 " Prints a listing of the users that are currently connected to the\n"
2671 "Asterisk manager interface.\n";
2677 ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
2679 sessions = ao2_global_obj_ref(mgr_sessions);
2681 i = ao2_iterator_init(sessions, 0);
2682 ao2_ref(sessions, -1);
2683 while ((session = ao2_iterator_next(&i))) {
2685 ast_cli(a->fd, HSMCONN_FORMAT2, session->username,
2686 ast_sockaddr_stringify_addr(&session->addr),
2687 (int) (session->sessionstart),
2688 (int) (now - session->sessionstart),
2689 session->stream ? ast_iostream_get_fd(session->stream) : -1,
2692 session->writeperm);
2694 ao2_unlock(session);
2695 unref_mansession(session);
2697 ao2_iterator_destroy(&i);
2699 ast_cli(a->fd, "%d users connected.\n", count);
2704 /*! \brief CLI command manager list eventq */
2705 /* Should change to "manager show connected" */
2706 static char *handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2708 struct eventqent *s;
2711 e->command = "manager show eventq";
2713 "Usage: manager show eventq\n"
2714 " Prints a listing of all events pending in the Asterisk manger\n"
2720 AST_RWLIST_RDLOCK(&all_events);
2721 AST_RWLIST_TRAVERSE(&all_events, s, eq_next) {
2722 ast_cli(a->fd, "Usecount: %d\n", s->usecount);
2723 ast_cli(a->fd, "Category: %d\n", s->category);
2724 ast_cli(a->fd, "Event:\n%s", s->eventdata);
2726 AST_RWLIST_UNLOCK(&all_events);
2731 static int reload_module(void);
2733 /*! \brief CLI command manager reload */
2734 static char *handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2738 e->command = "manager reload";
2740 "Usage: manager reload\n"
2741 " Reloads the manager configuration.\n";
2747 return CLI_SHOWUSAGE;
2753 static struct eventqent *advance_event(struct eventqent *e)
2755 struct eventqent *next;
2757 AST_RWLIST_RDLOCK(&all_events);
2758 if ((next = AST_RWLIST_NEXT(e, eq_next))) {
2759 ast_atomic_fetchadd_int(&next->usecount, 1);
2760 ast_atomic_fetchadd_int(&e->usecount, -1);
2762 AST_RWLIST_UNLOCK(&all_events);
2766 #define GET_HEADER_FIRST_MATCH 0
2767 #define GET_HEADER_LAST_MATCH 1
2768 #define GET_HEADER_SKIP_EMPTY 2
2771 * \brief Return a matching header value.
2774 * Generic function to return either the first or the last
2775 * matching header from a list of variables, possibly skipping
2778 * \note At the moment there is only one use of this function in
2779 * this file, so we make it static.
2781 * \note Never returns NULL.
2783 static const char *__astman_get_header(const struct message *m, char *var, int mode)
2785 int x, l = strlen(var);
2786 const char *result = "";
2792 for (x = 0; x < m->hdrcount; x++) {
2793 const char *h = m->headers[x];
2794 if (!strncasecmp(var, h, l) && h[l] == ':') {
2795 const char *value = h + l + 1;
2796 value = ast_skip_blanks(value); /* ignore leading spaces in the value */
2797 /* found a potential candidate */
2798 if ((mode & GET_HEADER_SKIP_EMPTY) && ast_strlen_zero(value)) {
2799 continue; /* not interesting */
2801 if (mode & GET_HEADER_LAST_MATCH) {
2802 result = value; /* record the last match so far */
2813 * \brief Return the first matching variable from an array.
2815 * \note This is the legacy function and is implemented in
2816 * therms of __astman_get_header().
2818 * \note Never returns NULL.
2820 const char *astman_get_header(const struct message *m, char *var)
2822 return __astman_get_header(m, var, GET_HEADER_FIRST_MATCH);
2826 * \brief Append additional headers into the message structure from params.
2828 * \note You likely want to initialize m->hdrcount to 0 before calling this.
2830 static void astman_append_headers(struct message *m, const struct ast_variable *params)
2832 const struct ast_variable *v;
2834 for (v = params; v && m->hdrcount < ARRAY_LEN(m->headers); v = v->next) {
2835 if (ast_asprintf((char**)&m->headers[m->hdrcount], "%s: %s", v->name, v->value) > -1) {
2842 * \brief Free headers inside message structure, but not the message structure itself.
2844 static void astman_free_headers(struct message *m)
2846 while (m->hdrcount) {
2848 ast_free((void *) m->headers[m->hdrcount]);
2849 m->headers[m->hdrcount] = NULL;
2855 * \brief Process one "Variable:" header value string.
2857 * \param head Current list of AMI variables to get new values added.
2858 * \param hdr_val Header value string to process.
2860 * \return New variable list head.
2862 static struct ast_variable *man_do_variable_value(struct ast_variable *head, const char *hdr_val)
2865 AST_DECLARE_APP_ARGS(args,
2866 AST_APP_ARG(vars)[64];
2869 hdr_val = ast_skip_blanks(hdr_val); /* ignore leading spaces in the value */
2870 parse = ast_strdupa(hdr_val);
2872 /* Break the header value string into name=val pair items. */
2873 AST_STANDARD_APP_ARGS(args, parse);
2877 /* Process each name=val pair item. */
2878 for (y = 0; y < args.argc; y++) {
2879 struct ast_variable *cur;
2883 if (!args.vars[y]) {
2886 var = val = args.vars[y];
2889 /* XXX We may wish to trim whitespace from the strings. */
2890 if (!val || ast_strlen_zero(var)) {
2894 /* Create new variable list node and prepend it to the list. */
2895 cur = ast_variable_new(var, val, "");
2906 struct ast_variable *astman_get_variables(const struct message *m)
2908 return astman_get_variables_order(m, ORDER_REVERSE);
2911 struct ast_variable *astman_get_variables_order(const struct message *m,
2912 enum variable_orders order)
2916 struct ast_variable *head = NULL;
2918 static const char var_hdr[] = "Variable:";
2920 /* Process all "Variable:" headers. */
2921 varlen = strlen(var_hdr);
2922 for (x = 0; x < m->hdrcount; x++) {
2923 if (strncasecmp(var_hdr, m->headers[x], varlen)) {
2926 head = man_do_variable_value(head, m->headers[x] + varlen);
2929 if (order == ORDER_NATURAL) {
2930 head = ast_variables_reverse(head);
2936 /*! \brief access for hooks to send action messages to ami */
2937 int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
2941 struct manager_action *act_found;
2942 struct mansession s = {.session = NULL, };
2943 struct message m = { 0 };
2953 /* Create our own copy of the AMI action msg string. */
2954 src = dup_str = ast_strdup(msg);
2959 /* convert msg string to message struct */
2960 curlen = strlen(src);
2961 for (x = 0; x < curlen; x++) {
2962 int cr; /* set if we have \r */
2963 if (src[x] == '\r' && x+1 < curlen && src[x+1] == '\n')
2964 cr = 2; /* Found. Update length to include \r\n */
2965 else if (src[x] == '\n')
2966 cr = 1; /* also accept \n only */
2969 /* don't keep empty lines */
2970 if (x && m.hdrcount < ARRAY_LEN(m.headers)) {
2971 /* ... but trim \r\n and terminate the header string */
2973 m.headers[m.hdrcount++] = src;
2976 curlen -= x; /* remaining size */
2977 src += x; /* update pointer */
2978 x = -1; /* reset loop */
2981 action = astman_get_header(&m, "Action");
2984 if (!strcasecmp(action, "login")) {
2988 act_found = action_find(action);
2994 * we have to simulate a session for this action request
2995 * to be able to pass it down for processing
2996 * This is necessary to meet the previous design of manager.c
3001 ao2_lock(act_found);
3002 if (act_found->registered && act_found->func) {
3003 struct ast_module *mod_ref = ast_module_running_ref(act_found->module);
3005 ao2_unlock(act_found);
3006 /* If the action is in a module it must be running. */
3007 if (!act_found->module || mod_ref) {
3008 ret = act_found->func(&s, &m);
3009 ast_module_unref(mod_ref);
3012 ao2_unlock(act_found);
3014 ao2_t_ref(act_found, -1, "done with found action object");
3022 * helper function to send a string to the socket.
3023 * Return -1 on error (e.g. buffer full).
3025 static int send_string(struct mansession *s, char *string)
3027 struct ast_iostream *stream;
3030 /* It's a result from one of the hook's action invocation */
3033 * to send responses, we're using the same function
3034 * as for receiving events. We call the event "HookResponse"
3036 s->hook->helper(EVENT_FLAG_HOOKRESPONSE, "HookResponse", string);
3040 stream = s->stream ? s->stream : s->session->stream;
3042 len = strlen(string);
3043 ast_iostream_set_timeout_inactivity(stream, s->session->writetimeout);
3044 res = ast_iostream_write(stream, string, len);
3045 ast_iostream_set_timeout_disable(stream);
3055 * \brief thread local buffer for astman_append
3057 * \note This can not be defined within the astman_append() function
3058 * because it declares a couple of functions that get used to
3059 * initialize the thread local storage key.
3061 AST_THREADSTORAGE(astman_append_buf);
3063 AST_THREADSTORAGE(userevent_buf);
3065 /*! \brief initial allocated size for the astman_append_buf and astman_send_*_va */
3066 #define ASTMAN_APPEND_BUF_INITSIZE 256
3068 static void astman_flush(struct mansession *s, struct ast_str *buf)
3070 if (s->hook || (s->tcptls_session && s->tcptls_session->stream)) {
3071 send_string(s, ast_str_buffer(buf));
3073 ast_verbose("No connection stream in astman_append, should not happen\n");
3078 * utility functions for creating AMI replies
3080 void astman_append(struct mansession *s, const char *fmt, ...)
3084 struct ast_str *buf;
3086 if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
3091 res = ast_str_set_va(&buf, 0, fmt, ap);
3093 if (res == AST_DYNSTR_BUILD_FAILED) {
3097 if (s->hook || (s->tcptls_session != NULL && s->tcptls_session->stream != NULL)) {
3098 send_string(s, ast_str_buffer(buf));
3100 ast_verbose("No connection stream in astman_append, should not happen\n");
3104 /*! \note NOTE: XXX this comment is unclear and possibly wrong.
3105 Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
3106 hold the session lock _or_ be running in an action callback (in which case s->session->busy will
3107 be non-zero). In either of these cases, there is no need to lock-protect the session's
3108 fd, since no other output will be sent (events will be queued), and no input will
3109 be read until either the current action finishes or get_input() obtains the session
3113 /*! \todo XXX MSG_MOREDATA should go to a header file. */
3114 #define MSG_MOREDATA ((char *)astman_send_response)
3116 /*! \brief send a response with an optional message,
3117 * and terminate it with an empty line.
3118 * m is used only to grab the 'ActionID' field.
3120 * Use the explicit constant MSG_MOREDATA to remove the empty line.
3121 * XXX MSG_MOREDATA should go to a header file.
3123 static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
3125 const char *id = astman_get_header(m, "ActionID");
3126 struct ast_str *buf;
3128 buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE);
3133 ast_str_set(&buf, 0, "Response: %s\r\n", resp);
3135 if (!ast_strlen_zero(id)) {
3136 ast_str_append(&buf, 0, "ActionID: %s\r\n", id);
3140 /* Start, complete, cancelled */
3141 ast_str_append(&buf, 0, "EventList: %s\r\n", listflag);
3144 if (msg != MSG_MOREDATA) {
3146 ast_str_append(&buf, 0, "Message: %s\r\n", msg);
3148 ast_str_append(&buf, 0, "\r\n");
3151 astman_flush(s, buf);
3154 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
3156 astman_send_response_full(s, m, resp, msg, NULL);
3159 void astman_send_error(struct mansession *s, const struct message *m, char *error)
3161 astman_send_response_full(s, m, "Error", error, NULL);
3164 void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt, ...)
3168 struct ast_str *buf;
3171 if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
3176 res = ast_str_set_va(&buf, 0, fmt, ap);
3178 if (res == AST_DYNSTR_BUILD_FAILED) {
3182 /* astman_append will use the same underlying buffer, so copy the message out
3183 * before sending the response */
3184 msg = ast_str_buffer(buf);
3186 msg = ast_strdupa(msg);
3188 astman_send_response_full(s, m, "Error", msg, NULL);
3191 void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
3193 astman_send_response_full(s, m, "Success", msg, NULL);
3196 static void astman_start_ack(struct mansession *s, const struct message *m)
3198 astman_send_response_full(s, m, "Success", MSG_MOREDATA, NULL);
3201 void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
3203 astman_send_response_full(s, m, "Success", msg, listflag);
3206 static struct ast_str *astman_send_list_complete_start_common(struct mansession *s, const struct message *m, const char *event_name, int count)
3208 const char *id = astman_get_header(m, "ActionID");
3209 struct ast_str *buf;
3211 buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE);
3216 ast_str_set(&buf, 0, "Event: %s\r\n", event_name);
3217 if (!ast_strlen_zero(id)) {
3218 ast_str_append(&buf, 0, "ActionID: %s\r\n", id);
3220 ast_str_append(&buf, 0,
3221 "EventList: Complete\r\n"
3222 "ListItems: %d\r\n",
3228 static void astman_send_list_complete(struct mansession *s, const struct message *m, const char *event_name, int count)
3230 struct ast_str *buf = astman_send_list_complete_start_common(s, m, event_name, count);
3232 ast_str_append(&buf, 0, "\r\n");
3233 astman_flush(s, buf);
3237 void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
3239 struct ast_str *buf = astman_send_list_complete_start_common(s, m, event_name, count);
3241 astman_flush(s, buf);
3245 void astman_send_list_complete_end(struct mansession *s)
3247 astman_append(s, "\r\n");
3250 /*! \brief Lock the 'mansession' structure. */
3251 static void mansession_lock(struct mansession *s)
3253 ast_mutex_lock(&s->lock);
3256 /*! \brief Unlock the 'mansession' structure. */
3257 static void mansession_unlock(struct mansession *s)
3259 ast_mutex_unlock(&s->lock);
3263 Rather than braindead on,off this now can also accept a specific int mask value
3264 or a ',' delim list of mask strings (the same as manager.conf) -anthm
3266 static int set_eventmask(struct mansession *s, const char *eventmask)
3268 int maskint = strings_to_mask(eventmask);
3270 ao2_lock(s->session);
3272 s->session->send_events = maskint;
3274 ao2_unlock(s->session);
3279 static enum ast_transport mansession_get_transport(const struct mansession *s)
3281 return s->tcptls_session->parent->tls_cfg ? AST_TRANSPORT_TLS :
3285 static void report_invalid_user(const struct mansession *s, const char *username)
3287 char session_id[32];
3288 struct ast_security_event_inval_acct_id inval_acct_id = {
3289 .common.event_type = AST_SECURITY_EVENT_INVAL_ACCT_ID,
3290 .common.version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
3291 .common.service = "AMI",
3292 .common.account_id = username,
3293 .common.session_tv = &s->session->sessionstart_tv,
3294 .common.local_addr = {
3295 .addr = &s->tcptls_session->parent->local_address,
3296 .transport = mansession_get_transport(s),
3298 .common.remote_addr = {
3299 .addr = &s->session->addr,
3300 .transport = mansession_get_transport(s),
3302 .common.session_id = session_id,
3305 snprintf(session_id, sizeof(session_id), "%p", s);
3307 ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
3310 static void report_failed_acl(const struct mansession *s, const char *username)
3312 char session_id[32];
3313 struct ast_security_event_failed_acl failed_acl_event = {
3314 .common.event_type = AST_SECURITY_EVENT_FAILED_ACL,
3315 .common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
3316 .common.service = "AMI",
3317 .common.account_id = username,
3318 .common.session_tv = &s->session->sessionstart_tv,
3319 .common.local_addr = {
3320 .addr = &s->tcptls_session->parent->local_address,
3321 .transport = mansession_get_transport(s),
3323 .common.remote_addr = {
3324 .addr = &s->session->addr,
3325 .transport = mansession_get_transport(s),
3327 .common.session_id = session_id,
3330 snprintf(session_id, sizeof(session_id), "%p", s->session);
3332 ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
3335 static void report_inval_password(const struct mansession *s, const char *username)
3337 char session_id[32];
3338 struct ast_security_event_inval_password inval_password = {
3339 .common.event_type = AST_SECURITY_EVENT_INVAL_PASSWORD,
3340 .common.version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION,
3341 .common.service = "AMI",
3342 .common.account_id = username,
3343 .common.session_tv = &s->session->sessionstart_tv,
3344 .common.local_addr = {
3345 .addr = &s->tcptls_session->parent->local_address,
3346 .transport = mansession_get_transport(s),
3348 .common.remote_addr = {
3349 .addr = &s->session->addr,
3350 .transport = mansession_get_transport(s),
3352 .common.session_id = session_id,
3355 snprintf(session_id, sizeof(session_id), "%p", s->session);
3357 ast_security_event_report(AST_SEC_EVT(&inval_password));
3360 static void report_auth_success(const struct mansession *s)
3362 char session_id[32];
3363 struct ast_security_event_successful_auth successful_auth = {
3364 .common.event_type = AST_SECURITY_EVENT_SUCCESSFUL_AUTH,
3365 .common.version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
3366 .common.service = "AMI",
3367 .common.account_id = s->session->username,
3368 .common.session_tv = &s->session->sessionstart_tv,
3369 .common.local_addr = {
3370 .addr = &s->tcptls_session->parent->local_address,
3371 .transport = mansession_get_transport(s),
3373 .common.remote_addr = {
3374 .addr = &s->session->addr,
3375 .transport = mansession_get_transport(s),
3377 .common.session_id = session_id,
3380 snprintf(session_id, sizeof(session_id), "%p", s->session);
3382 ast_security_event_report(AST_SEC_EVT(&successful_auth));
3385 static void report_req_not_allowed(const struct mansession *s, const char *action)
3387 char session_id[32];
3388 char request_type[64];
3389 struct ast_security_event_req_not_allowed req_not_allowed = {
3390 .common.event_type = AST_SECURITY_EVENT_REQ_NOT_ALLOWED,
3391 .common.version = AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION,
3392 .common.service = "AMI",
3393 .common.account_id = s->session->username,
3394 .common.session_tv = &s->session->sessionstart_tv,
3395 .common.local_addr = {
3396 .addr = &s->tcptls_session->parent->local_address,
3397 .transport = mansession_get_transport(s),
3399 .common.remote_addr = {
3400 .addr = &s->session->addr,
3401 .transport = mansession_get_transport(s),
3403 .common.session_id = session_id,
3405 .request_type = request_type,
3408 snprintf(session_id, sizeof(session_id), "%p", s->session);
3409 snprintf(request_type, sizeof(request_type), "Action: %s", action);
3411 ast_security_event_report(AST_SEC_EVT(&req_not_allowed));
3414 static void report_req_bad_format(const struct mansession *s, const char *action)
3416 char session_id[32];
3417 char request_type[64];
3418 struct ast_security_event_req_bad_format req_bad_format = {
3419 .common.event_type = AST_SECURITY_EVENT_REQ_BAD_FORMAT,
3420 .common.version = AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION,
3421 .common.service = "AMI",
3422 .common.account_id = s->session->username,
3423 .common.session_tv = &s->session->sessionstart_tv,
3424 .common.local_addr = {
3425 .addr = &s->tcptls_session->parent->local_address,
3426 .transport = mansession_get_transport(s),
3428 .common.remote_addr = {
3429 .addr = &s->session->addr,
3430 .transport = mansession_get_transport(s),
3432 .common.session_id = session_id,
3434 .request_type = request_type,
3437 snprintf(session_id, sizeof(session_id), "%p", s->session);
3438 snprintf(request_type, sizeof(request_type), "Action: %s", action);
3440 ast_security_event_report(AST_SEC_EVT(&req_bad_format));
3443 static void report_failed_challenge_response(const struct mansession *s,
3444 const char *response, const char *expected_response)
3446 char session_id[32];
3447 struct ast_security_event_chal_resp_failed chal_resp_failed = {
3448 .common.event_type = AST_SECURITY_EVENT_CHAL_RESP_FAILED,
3449 .common.version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
3450 .common.service = "AMI",
3451 .common.account_id = s->session->username,
3452 .common.session_tv = &s->session->sessionstart_tv,
3453 .common.local_addr = {
3454 .addr = &s->tcptls_session->parent->local_address,
3455 .transport = mansession_get_transport(s),
3457 .common.remote_addr = {
3458 .addr = &s->session->addr,
3459 .transport = mansession_get_transport(s),
3461 .common.session_id = session_id,
3463 .challenge = s->session->challenge,
3464 .response = response,
3465 .expected_response = expected_response,
3468 snprintf(session_id, sizeof(session_id), "%p", s->session);
3470 ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
3473 static void report_session_limit(const struct mansession *s)
3475 char session_id[32];
3476 struct ast_security_event_session_limit session_limit = {
3477 .common.event_type = AST_SECURITY_EVENT_SESSION_LIMIT,
3478 .common.version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
3479 .common.service = "AMI",
3480 .common.account_id = s->session->username,
3481 .common.session_tv = &s->session->sessionstart_tv,
3482 .common.local_addr = {
3483 .addr = &s->tcptls_session->parent->local_address,
3484 .transport = mansession_get_transport(s),
3486 .common.remote_addr = {
3487 .addr = &s->session->addr,
3488 .transport = mansession_get_transport(s),
3490 .common.session_id = session_id,
3493 snprintf(session_id, sizeof(session_id), "%p", s->session);
3495 ast_security_event_report(AST_SEC_EVT(&session_limit));
3499 * Here we start with action_ handlers for AMI actions,
3500 * and the internal functions used by them.
3501 * Generally, the handlers are called action_foo()
3504 /* helper function for action_login() */
3505 static int authenticate(struct mansession *s, const struct message *m)
3507 const char *username = astman_get_header(m, "Username");
3508 const char *password = astman_get_header(m, "Secret");
3510 struct ast_manager_user *user = NULL;
3511 regex_t *regex_filter;
3512 struct ao2_iterator filter_iter;
3514 if (ast_strlen_zero(username)) { /* missing username */
3518 /* locate user in locked state */
3519 AST_RWLIST_WRLOCK(&users);
3521 if (!(user = get_manager_by_name_locked(username))) {
3522 report_invalid_user(s, username);
3523 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3524 } else if (user->acl && (ast_apply_acl(user->acl, &s->session->addr, "Manager User ACL: ") == AST_SENSE_DENY)) {
3525 report_failed_acl(s, username);
3526 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3527 } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
3528 const char *key = astman_get_header(m, "Key");
3529 if (!ast_strlen_zero(key) && !ast_strlen_zero(s->session->challenge) && user->secret) {
3532 char md5key[256] = "";
3533 struct MD5Context md5;
3534 unsigned char digest[16];
3537 MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
3538 MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
3539 MD5Final(digest, &md5);
3540 for (x = 0; x < 16; x++)
3541 len += sprintf(md5key + len, "%02hhx", digest[x]);
3542 if (!strcmp(md5key, key)) {
3545 report_failed_challenge_response(s, key, md5key);
3548 ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
3549 S_OR(s->session->challenge, ""));
3551 } else if (user->secret) {
3552 if (!strcmp(password, user->secret)) {
3555 report_inval_password(s, username);
3560 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3561 AST_RWLIST_UNLOCK(&users);
3567 /* All of the user parameters are copied to the session so that in the event
3568 * of a reload and a configuration change, the session parameters are not
3570 ast_copy_string(s->session->username, username, sizeof(s->session->username));
3571 s->session->readperm = user->readperm;
3572 s->session->writeperm = user->writeperm;
3573 s->session->writetimeout = user->writetimeout;
3574 if (user->chanvars) {
3575 s->session->chanvars = ast_variables_dup(user->chanvars);
3578 filter_iter = ao2_iterator_init(user->whitefilters, 0);
3579 while ((regex_filter = ao2_iterator_next(&filter_iter))) {
3580 ao2_t_link(s->session->whitefilters, regex_filter, "add white user filter to session");
3581 ao2_t_ref(regex_filter, -1, "remove iterator ref");
3583 ao2_iterator_destroy(&filter_iter);
3585 filter_iter = ao2_iterator_init(user->blackfilters, 0);
3586 while ((regex_filter = ao2_iterator_next(&filter_iter))) {
3587 ao2_t_link(s->session->blackfilters, regex_filter, "add black user filter to session");
3588 ao2_t_ref(regex_filter, -1, "remove iterator ref");
3590 ao2_iterator_destroy(&filter_iter);
3592 s->session->sessionstart = time(NULL);
3593 s->session->sessionstart_tv = ast_tvnow();
3594 set_eventmask(s, astman_get_header(m, "Events"));
3596 report_auth_success(s);
3598 AST_RWLIST_UNLOCK(&users);
3602 static int action_ping(struct mansession *s, const struct message *m)
3604 const char *actionid = astman_get_header(m, "ActionID");
3605 struct timeval now = ast_tvnow();
3607 astman_append(s, "Response: Success\r\n");
3608 if (!ast_strlen_zero(actionid)){
3609 astman_append(s, "ActionID: %s\r\n", actionid);
3614 "Timestamp: %ld.%06lu\r\n"
3616 (long) now.tv_sec, (unsigned long) now.tv_usec);
3620 static int action_getconfig(struct mansession *s, const struct message *m)
3622 struct ast_config *cfg;
3623 const char *fn = astman_get_header(m, "Filename");
3624 const char *category = astman_get_header(m, "Category");
3625 const char *filter = astman_get_header(m, "Filter");
3626 const char *category_name;
3629 struct ast_category *cur_category = NULL;
3630 struct ast_variable *v;
3631 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3633 if (ast_strlen_zero(fn)) {
3634 astman_send_error(s, m, "Filename not specified");
3638 cfg = ast_config_load2(fn, "manager", config_flags);
3639 if (cfg == CONFIG_STATUS_FILEMISSING) {
3640 astman_send_error(s, m, "Config file not found");
3642 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
3643 astman_send_error(s, m, "Config file has invalid format");
3647 astman_start_ack(s, m);
3648 while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
3649 struct ast_str *templates;
3651 category_name = ast_category_get_name(cur_category);
3653 astman_append(s, "Category-%06d: %s\r\n", catcount, category_name);
3655 if (ast_category_is_template(cur_category)) {
3656 astman_append(s, "IsTemplate-%06d: %d\r\n", catcount, 1);
3659 if ((templates = ast_category_get_templates(cur_category))
3660 && ast_str_strlen(templates) > 0) {
3661 astman_append(s, "Templates-%06d: %s\r\n", catcount, ast_str_buffer(templates));
3662 ast_free(templates);
3665 for (v = ast_category_first(cur_category); v; v = v->next) {
3666 astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
3672 if (!ast_strlen_zero(category) && catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
3673 astman_append(s, "No categories found\r\n");
3676 ast_config_destroy(cfg);
3677 astman_append(s, "\r\n");
3682 static int action_listcategories(struct mansession *s, const struct message *m)
3684 struct ast_config *cfg;
3685 const char *fn = astman_get_header(m, "Filename");
3686 const char *match = astman_get_header(m, "Match");
3687 struct ast_category *category = NULL;
3688 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3691 if (ast_strlen_zero(fn)) {
3692 astman_send_error(s, m, "Filename not specified");
3696 if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
3697 astman_send_error(s, m, "Config file not found");
3699 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
3700 astman_send_error(s, m, "Config file has invalid format");
3704 astman_start_ack(s, m);
3705 while ((category = ast_category_browse_filtered(cfg, NULL, category, match))) {
3706 astman_append(s, "Category-%06d: %s\r\n", catcount, ast_category_get_name(category));
3710 if (catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
3711 astman_append(s, "Error: no categories found\r\n");
3714 ast_config_destroy(cfg);
3715 astman_append(s, "\r\n");
3720 /*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
3721 static void json_escape(char *out, const char *in)
3724 if (*in == '\\' || *in == '\"') {
3734 * \brief Append a JSON escaped string to the manager stream.
3736 * \param s AMI stream to append a string.
3737 * \param str String to append to the stream after JSON escaping it.
3741 static void astman_append_json(struct mansession *s, const char *str)
3745 buf = ast_alloca(2 * strlen(str) + 1);
3746 json_escape(buf, str);
3747 astman_append(s, "%s", buf);
3750 static int action_getconfigjson(struct mansession *s, const struct message *m)
3752 struct ast_config *cfg;
3753 const char *fn = astman_get_header(m, "Filename");
3754 const char *filter = astman_get_header(m, "Filter");
3755 const char *category = astman_get_header(m, "Category");
3756 struct ast_category *cur_category = NULL;
3757 const char *category_name;
3758 struct ast_variable *v;
3760 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3762 if (ast_strlen_zero(fn)) {
3763 astman_send_error(s, m, "Filename not specified");
3767 if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
3768 astman_send_error(s, m, "Config file not found");
3770 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
3771 astman_send_error(s, m, "Config file has invalid format");
3775 astman_start_ack(s, m);
3776 astman_append(s, "JSON: {");
3777 while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
3779 struct ast_str *templates;
3781 category_name = ast_category_get_name(cur_category);
3782 astman_append(s, "%s\"", comma1 ? "," : "");
3783 astman_append_json(s, category_name);
3784 astman_append(s, "\":{");
3787 if (ast_category_is_template(cur_category)) {
3788 astman_append(s, "\"istemplate\":1");
3792 if ((templates = ast_category_get_templates(cur_category))
3793 && ast_str_strlen(templates) > 0) {
3794 astman_append(s, "%s", comma2 ? "," : "");
3795 astman_append(s, "\"templates\":\"%s\"", ast_str_buffer(templates));
3796 ast_free(templates);
3800 for (v = ast_category_first(cur_category); v; v = v->next) {
3801 astman_append(s, "%s\"", comma2 ? "," : "");
3802 astman_append_json(s, v->name);
3803 astman_append(s, "\":\"");
3804 astman_append_json(s, v->value);
3805 astman_append(s, "\"");
3809 astman_append(s, "}");
3811 astman_append(s, "}\r\n\r\n");
3813 ast_config_destroy(cfg);
3818 /*! \brief helper function for action_updateconfig */
3819 static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
3823 const char *action, *cat, *var, *value, *match, *line, *options;
3824 struct ast_variable *v;
3825 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
3826 enum error_type result = 0;
3828 for (x = 0; x < 100000; x++) {