Asterisk - The Open Source Telephony Project GIT-master-2de1a68
manager.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief The Asterisk Management Interface - AMI
22 *
23 * \author Mark Spencer <markster@digium.com>
24 *
25 * OpenSSL http://www.openssl.org - for AMI/SSL
26 *
27 * At the moment this file contains a number of functions, namely:
28 *
29 * - data structures storing AMI state
30 * - AMI-related API functions, used by internal asterisk components
31 * - handlers for AMI-related CLI functions
32 * - handlers for AMI functions (available through the AMI socket)
33 * - the code for the main AMI listener thread and individual session threads
34 * - the http handlers invoked for AMI-over-HTTP by the threads in main/http.c
35 *
36 * \ref amiconf
37 */
38
39/*! \li \ref manager.c uses the configuration file \ref manager.conf and \ref users.conf
40 * \addtogroup configuration_file
41 */
42
43/*! \page manager.conf manager.conf
44 * \verbinclude manager.conf.sample
45 */
46
47/*! \page users.conf users.conf
48 * \verbinclude users.conf.sample
49 */
50
51/*** MODULEINFO
52 <support_level>core</support_level>
53 ***/
54
55#include "asterisk.h"
56
57#include "asterisk/paths.h" /* use various ast_config_AST_* */
58#include <ctype.h>
59#include <sys/time.h>
60#include <signal.h>
61#include <sys/mman.h>
62#include <sys/types.h>
63#include <regex.h>
64
65#include "asterisk/channel.h"
66#include "asterisk/file.h"
67#include "asterisk/manager.h"
68#include "asterisk/module.h"
69#include "asterisk/config.h"
70#include "asterisk/callerid.h"
71#include "asterisk/core_local.h"
72#include "asterisk/lock.h"
73#include "asterisk/cli.h"
74#include "asterisk/app.h"
75#include "asterisk/mwi.h"
76#include "asterisk/pbx.h"
77#include "asterisk/md5.h"
78#include "asterisk/acl.h"
79#include "asterisk/utils.h"
80#include "asterisk/tcptls.h"
81#include "asterisk/http.h"
85#include "asterisk/term.h"
86#include "asterisk/astobj2.h"
87#include "asterisk/features.h"
89#include "asterisk/aoc.h"
90#include "asterisk/strings.h"
96#include "asterisk/test.h"
97#include "asterisk/json.h"
98#include "asterisk/bridge.h"
100#include "asterisk/rtp_engine.h"
102#include "asterisk/translate.h"
104#include "asterisk/message.h"
105
106/*** DOCUMENTATION
107 <manager name="Ping" language="en_US">
108 <synopsis>
109 Keepalive command.
110 </synopsis>
111 <syntax>
112 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
113 </syntax>
114 <description>
115 <para>A 'Ping' action will elicit a 'Pong' response. Used to keep the
116 manager connection open.</para>
117 </description>
118 </manager>
119 <manager name="Events" language="en_US">
120 <synopsis>
121 Control Event Flow.
122 </synopsis>
123 <syntax>
124 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
125 <parameter name="EventMask" required="true">
126 <enumlist>
127 <enum name="on">
128 <para>If all events should be sent.</para>
129 </enum>
130 <enum name="off">
131 <para>If no events should be sent.</para>
132 </enum>
133 <enum name="system,call,log,...">
134 <para>To select which flags events should have to be sent.</para>
135 </enum>
136 </enumlist>
137 </parameter>
138 </syntax>
139 <description>
140 <para>Enable/Disable sending of events to this manager client.</para>
141 </description>
142 </manager>
143 <manager name="Logoff" language="en_US">
144 <synopsis>
145 Logoff Manager.
146 </synopsis>
147 <syntax>
148 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
149 </syntax>
150 <description>
151 <para>Logoff the current manager session.</para>
152 </description>
153 <see-also>
154 <ref type="manager">Login</ref>
155 </see-also>
156 </manager>
157 <manager name="Login" language="en_US">
158 <synopsis>
159 Login Manager.
160 </synopsis>
161 <syntax>
162 <parameter name="ActionID">
163 <para>ActionID for this transaction. Will be returned.</para>
164 </parameter>
165 <parameter name="Username" required="true">
166 <para>Username to login with as specified in manager.conf.</para>
167 </parameter>
168 <parameter name="Secret">
169 <para>Secret to login with as specified in manager.conf.</para>
170 </parameter>
171 </syntax>
172 <description>
173 <para>Login Manager.</para>
174 </description>
175 <see-also>
176 <ref type="manager">Logoff</ref>
177 </see-also>
178 </manager>
179 <manager name="Challenge" language="en_US">
180 <synopsis>
181 Generate Challenge for MD5 Auth.
182 </synopsis>
183 <syntax>
184 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
185 <parameter name="AuthType" required="true">
186 <para>Digest algorithm to use in the challenge. Valid values are:</para>
187 <enumlist>
188 <enum name="MD5" />
189 </enumlist>
190 </parameter>
191 </syntax>
192 <description>
193 <para>Generate a challenge for MD5 authentication.</para>
194 </description>
195 </manager>
196 <manager name="Hangup" language="en_US">
197 <synopsis>
198 Hangup channel.
199 </synopsis>
200 <syntax>
201 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
202 <parameter name="Channel" required="true">
203 <para>The exact channel name to be hungup, or to use a regular expression, set this parameter to: /regex/</para>
204 <para>Example exact channel: SIP/provider-0000012a</para>
205 <para>Example regular expression: /^SIP/provider-.*$/</para>
206 </parameter>
207 <parameter name="Cause">
208 <para>Numeric hangup cause.</para>
209 </parameter>
210 </syntax>
211 <description>
212 <para>Hangup a channel.</para>
213 </description>
214 </manager>
215 <manager name="Status" language="en_US">
216 <synopsis>
217 List channel status.
218 </synopsis>
219 <syntax>
220 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
221 <parameter name="Channel" required="false">
222 <para>The name of the channel to query for status.</para>
223 </parameter>
224 <parameter name="Variables">
225 <para>Comma <literal>,</literal> separated list of variable to include.</para>
226 </parameter>
227 <parameter name="AllVariables">
228 <para>If set to "true", the Status event will include all channel variables for
229 the requested channel(s).</para>
230 <enumlist>
231 <enum name="true"/>
232 <enum name="false"/>
233 </enumlist>
234 </parameter>
235 </syntax>
236 <description>
237 <para>Will return the status information of each channel along with the
238 value for the specified channel variables.</para>
239 </description>
240 <responses>
241 <list-elements>
242 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Status'])" />
243 </list-elements>
244 <xi:include xpointer="xpointer(/docs/managerEvent[@name='StatusComplete'])" />
245 </responses>
246 </manager>
247 <managerEvent language="en_US" name="Status">
248 <managerEventInstance class="EVENT_FLAG_CALL">
249 <synopsis>Raised in response to a Status command.</synopsis>
250 <syntax>
251 <parameter name="ActionID" required="false"/>
252 <channel_snapshot/>
253 <parameter name="Type">
254 <para>Type of channel</para>
255 </parameter>
256 <parameter name="DNID">
257 <para>Dialed number identifier</para>
258 </parameter>
259 <parameter name="EffectiveConnectedLineNum">
260 </parameter>
261 <parameter name="EffectiveConnectedLineName">
262 </parameter>
263 <parameter name="TimeToHangup">
264 <para>Absolute lifetime of the channel</para>
265 </parameter>
266 <parameter name="BridgeID">
267 <para>Identifier of the bridge the channel is in, may be empty if not in one</para>
268 </parameter>
269 <parameter name="Application">
270 <para>Application currently executing on the channel</para>
271 </parameter>
272 <parameter name="Data">
273 <para>Data given to the currently executing channel</para>
274 </parameter>
275 <parameter name="Nativeformats">
276 <para>Media formats the connected party is willing to send or receive</para>
277 </parameter>
278 <parameter name="Readformat">
279 <para>Media formats that frames from the channel are received in</para>
280 </parameter>
281 <parameter name="Readtrans">
282 <para>Translation path for media received in native formats</para>
283 </parameter>
284 <parameter name="Writeformat">
285 <para>Media formats that frames to the channel are accepted in</para>
286 </parameter>
287 <parameter name="Writetrans">
288 <para>Translation path for media sent to the connected party</para>
289 </parameter>
290 <parameter name="Callgroup">
291 <para>Configured call group on the channel</para>
292 </parameter>
293 <parameter name="Pickupgroup">
294 <para>Configured pickup group on the channel</para>
295 </parameter>
296 <parameter name="Seconds">
297 <para>Number of seconds the channel has been active</para>
298 </parameter>
299 </syntax>
300 <see-also>
301 <ref type="manager">Status</ref>
302 </see-also>
303 </managerEventInstance>
304 </managerEvent>
305 <managerEvent language="en_US" name="StatusComplete">
306 <managerEventInstance class="EVENT_FLAG_CALL">
307 <synopsis>Raised in response to a Status command.</synopsis>
308 <syntax>
309 <parameter name="Items">
310 <para>Number of Status events returned</para>
311 </parameter>
312 </syntax>
313 <see-also>
314 <ref type="manager">Status</ref>
315 </see-also>
316 </managerEventInstance>
317 </managerEvent>
318 <manager name="Setvar" language="en_US">
319 <synopsis>
320 Sets a channel variable or function value.
321 </synopsis>
322 <syntax>
323 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
324 <parameter name="Channel">
325 <para>Channel to set variable for.</para>
326 </parameter>
327 <parameter name="Variable" required="true">
328 <para>Variable name, function or expression.</para>
329 </parameter>
330 <parameter name="Value" required="true">
331 <para>Variable or function value.</para>
332 </parameter>
333 </syntax>
334 <description>
335 <para>This command can be used to set the value of channel variables or dialplan
336 functions.</para>
337 <note>
338 <para>If a channel name is not provided then the variable is considered global.</para>
339 </note>
340 </description>
341 <see-also>
342 <ref type="manager">Getvar</ref>
343 </see-also>
344 </manager>
345 <manager name="Getvar" language="en_US">
346 <synopsis>
347 Gets a channel variable or function value.
348 </synopsis>
349 <syntax>
350 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
351 <parameter name="Channel">
352 <para>Channel to read variable from.</para>
353 </parameter>
354 <parameter name="Variable" required="true">
355 <para>Variable name, function or expression.</para>
356 </parameter>
357 </syntax>
358 <description>
359 <para>Get the value of a channel variable or function return.</para>
360 <note>
361 <para>If a channel name is not provided then the variable is considered global.</para>
362 </note>
363 </description>
364 <see-also>
365 <ref type="manager">Setvar</ref>
366 </see-also>
367 </manager>
368 <manager name="GetConfig" language="en_US">
369 <synopsis>
370 Retrieve configuration.
371 </synopsis>
372 <syntax>
373 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
374 <parameter name="Filename" required="true">
375 <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
376 </parameter>
377 <parameter name="Category">
378 <para>Category in configuration file.</para>
379 </parameter>
380 <parameter name="Filter">
381 <para>A comma separated list of
382 <replaceable>name_regex</replaceable>=<replaceable>value_regex</replaceable>
383 expressions which will cause only categories whose variables match all expressions
384 to be considered. The special variable name <literal>TEMPLATES</literal>
385 can be used to control whether templates are included. Passing
386 <literal>include</literal> as the value will include templates
387 along with normal categories. Passing
388 <literal>restrict</literal> as the value will restrict the operation to
389 ONLY templates. Not specifying a <literal>TEMPLATES</literal> expression
390 results in the default behavior which is to not include templates.</para>
391 </parameter>
392 </syntax>
393 <description>
394 <para>This action will dump the contents of a configuration
395 file by category and contents or optionally by specified category only.
396 In the case where a category name is non-unique, a filter may be specified
397 to match only categories with matching variable values.</para>
398 </description>
399 <see-also>
400 <ref type="manager">GetConfigJSON</ref>
401 <ref type="manager">UpdateConfig</ref>
402 <ref type="manager">CreateConfig</ref>
403 <ref type="manager">ListCategories</ref>
404 </see-also>
405 </manager>
406 <manager name="GetConfigJSON" language="en_US">
407 <synopsis>
408 Retrieve configuration (JSON format).
409 </synopsis>
410 <syntax>
411 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
412 <parameter name="Filename" required="true">
413 <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
414 </parameter>
415 <parameter name="Category">
416 <para>Category in configuration file.</para>
417 </parameter>
418 <parameter name="Filter">
419 <xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
420 </parameter>
421 </syntax>
422 <description>
423 <para>This action will dump the contents of a configuration file by category
424 and contents in JSON format or optionally by specified category only.
425 This only makes sense to be used using rawman over the HTTP interface.
426 In the case where a category name is non-unique, a filter may be specified
427 to match only categories with matching variable values.</para>
428 </description>
429 <see-also>
430 <ref type="manager">GetConfig</ref>
431 <ref type="manager">UpdateConfig</ref>
432 <ref type="manager">CreateConfig</ref>
433 <ref type="manager">ListCategories</ref>
434 </see-also>
435 </manager>
436 <manager name="UpdateConfig" language="en_US">
437 <synopsis>
438 Update basic configuration.
439 </synopsis>
440 <syntax>
441 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
442 <parameter name="SrcFilename" required="true">
443 <para>Configuration filename to read (e.g. <filename>foo.conf</filename>).</para>
444 </parameter>
445 <parameter name="DstFilename" required="true">
446 <para>Configuration filename to write (e.g. <filename>foo.conf</filename>)</para>
447 </parameter>
448 <parameter name="Reload">
449 <para>Whether or not a reload should take place (or name of specific module).</para>
450 </parameter>
451 <parameter name="PreserveEffectiveContext">
452 <para>Whether the effective category contents should be preserved on template change. Default is true (pre 13.2 behavior).</para>
453 </parameter>
454 <parameter name="Action-000000">
455 <para>Action to take.</para>
456 <para>0's represent 6 digit number beginning with 000000.</para>
457 <enumlist>
458 <enum name="NewCat" />
459 <enum name="RenameCat" />
460 <enum name="DelCat" />
461 <enum name="EmptyCat" />
462 <enum name="Update" />
463 <enum name="Delete" />
464 <enum name="Append" />
465 <enum name="Insert" />
466 </enumlist>
467 </parameter>
468 <parameter name="Cat-000000">
469 <para>Category to operate on.</para>
470 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
471 </parameter>
472 <parameter name="Var-000000">
473 <para>Variable to work on.</para>
474 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
475 </parameter>
476 <parameter name="Value-000000">
477 <para>Value to work on.</para>
478 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
479 </parameter>
480 <parameter name="Match-000000">
481 <para>Extra match required to match line.</para>
482 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
483 </parameter>
484 <parameter name="Line-000000">
485 <para>Line in category to operate on (used with delete and insert actions).</para>
486 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
487 </parameter>
488 <parameter name="Options-000000">
489 <para>A comma separated list of action-specific options.</para>
490 <enumlist>
491 <enum name="NewCat"><para>One or more of the following... </para>
492 <enumlist>
493 <enum name="allowdups"><para>Allow duplicate category names.</para></enum>
494 <enum name="template"><para>This category is a template.</para></enum>
495 <enum name="inherit=&quot;template[,...]&quot;"><para>Templates from which to inherit.</para></enum>
496 </enumlist>
497 </enum>
498 </enumlist>
499 <para> </para>
500 <para>The following actions share the same options...</para>
501 <enumlist>
502 <enum name="RenameCat"/>
503 <enum name="DelCat"/>
504 <enum name="EmptyCat"/>
505 <enum name="Update"/>
506 <enum name="Delete"/>
507 <enum name="Append"/>
508 <enum name="Insert"><para> </para>
509 <enumlist>
510 <enum name="catfilter=&quot;&lt;expression&gt;[,...]&quot;"><para> </para>
511 <xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
512 <para><literal>catfilter</literal> is most useful when a file
513 contains multiple categories with the same name and you wish to
514 operate on specific ones instead of all of them.</para>
515 </enum>
516 </enumlist>
517 </enum>
518 </enumlist>
519 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
520 </parameter>
521 </syntax>
522 <description>
523 <para>This action will modify, create, or delete configuration elements
524 in Asterisk configuration files.</para>
525 </description>
526 <see-also>
527 <ref type="manager">GetConfig</ref>
528 <ref type="manager">GetConfigJSON</ref>
529 <ref type="manager">CreateConfig</ref>
530 <ref type="manager">ListCategories</ref>
531 </see-also>
532 </manager>
533 <manager name="CreateConfig" language="en_US">
534 <synopsis>
535 Creates an empty file in the configuration directory.
536 </synopsis>
537 <syntax>
538 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
539 <parameter name="Filename" required="true">
540 <para>The configuration filename to create (e.g. <filename>foo.conf</filename>).</para>
541 </parameter>
542 </syntax>
543 <description>
544 <para>This action will create an empty file in the configuration
545 directory. This action is intended to be used before an UpdateConfig
546 action.</para>
547 </description>
548 <see-also>
549 <ref type="manager">GetConfig</ref>
550 <ref type="manager">GetConfigJSON</ref>
551 <ref type="manager">UpdateConfig</ref>
552 <ref type="manager">ListCategories</ref>
553 </see-also>
554 </manager>
555 <manager name="ListCategories" language="en_US">
556 <synopsis>
557 List categories in configuration file.
558 </synopsis>
559 <syntax>
560 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
561 <parameter name="Filename" required="true">
562 <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
563 </parameter>
564 </syntax>
565 <description>
566 <para>This action will dump the categories in a given file.</para>
567 </description>
568 <see-also>
569 <ref type="manager">GetConfig</ref>
570 <ref type="manager">GetConfigJSON</ref>
571 <ref type="manager">UpdateConfig</ref>
572 <ref type="manager">CreateConfig</ref>
573 </see-also>
574 </manager>
575 <manager name="Redirect" language="en_US">
576 <synopsis>
577 Redirect (transfer) a call.
578 </synopsis>
579 <syntax>
580 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
581 <parameter name="Channel" required="true">
582 <para>Channel to redirect.</para>
583 </parameter>
584 <parameter name="ExtraChannel">
585 <para>Second call leg to transfer (optional).</para>
586 </parameter>
587 <parameter name="Exten" required="true">
588 <para>Extension to transfer to.</para>
589 </parameter>
590 <parameter name="ExtraExten">
591 <para>Extension to transfer extrachannel to (optional).</para>
592 </parameter>
593 <parameter name="Context" required="true">
594 <para>Context to transfer to.</para>
595 </parameter>
596 <parameter name="ExtraContext">
597 <para>Context to transfer extrachannel to (optional).</para>
598 </parameter>
599 <parameter name="Priority" required="true">
600 <para>Priority to transfer to.</para>
601 </parameter>
602 <parameter name="ExtraPriority">
603 <para>Priority to transfer extrachannel to (optional).</para>
604 </parameter>
605 </syntax>
606 <description>
607 <para>Redirect (transfer) a call.</para>
608 </description>
609 <see-also>
610 <ref type="manager">BlindTransfer</ref>
611 </see-also>
612 </manager>
613 <manager name="Atxfer" language="en_US">
614 <synopsis>
615 Attended transfer.
616 </synopsis>
617 <syntax>
618 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
619 <parameter name="Channel" required="true">
620 <para>Transferer's channel.</para>
621 </parameter>
622 <parameter name="Exten" required="true">
623 <para>Extension to transfer to.</para>
624 </parameter>
625 <parameter name="Context">
626 <para>Context to transfer to.</para>
627 </parameter>
628 </syntax>
629 <description>
630 <para>Attended transfer.</para>
631 </description>
632 <see-also>
633 <ref type="managerEvent">AttendedTransfer</ref>
634 </see-also>
635 </manager>
636 <manager name="CancelAtxfer" language="en_US">
637 <since>
638 <version>13.18.0</version>
639 <version>14.7.0</version>
640 <version>15.1.0</version>
641 <version>16.0.0</version>
642 </since>
643 <synopsis>
644 Cancel an attended transfer.
645 </synopsis>
646 <syntax>
647 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
648 <parameter name="Channel" required="true">
649 <para>The transferer channel.</para>
650 </parameter>
651 </syntax>
652 <description>
653 <para>Cancel an attended transfer. Note, this uses the configured cancel attended transfer
654 feature option (atxferabort) to cancel the transfer. If not available this action will fail.
655 </para>
656 </description>
657 <see-also>
658 <ref type="managerEvent">AttendedTransfer</ref>
659 </see-also>
660 </manager>
661 <manager name="Originate" language="en_US">
662 <synopsis>
663 Originate a call.
664 </synopsis>
665 <syntax>
666 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
667 <parameter name="Channel" required="true">
668 <para>Channel name to call.</para>
669 </parameter>
670 <parameter name="Exten">
671 <para>Extension to use (requires <literal>Context</literal> and
672 <literal>Priority</literal>)</para>
673 </parameter>
674 <parameter name="Context">
675 <para>Context to use (requires <literal>Exten</literal> and
676 <literal>Priority</literal>)</para>
677 </parameter>
678 <parameter name="Priority">
679 <para>Priority to use (requires <literal>Exten</literal> and
680 <literal>Context</literal>)</para>
681 </parameter>
682 <parameter name="Application">
683 <para>Application to execute.</para>
684 </parameter>
685 <parameter name="Data">
686 <para>Data to use (requires <literal>Application</literal>).</para>
687 </parameter>
688 <parameter name="Timeout" default="30000">
689 <para>How long to wait for call to be answered (in ms.).</para>
690 </parameter>
691 <parameter name="CallerID">
692 <para>Caller ID to be set on the outgoing channel.</para>
693 </parameter>
694 <parameter name="Variable">
695 <para>Channel variable to set, multiple Variable: headers are allowed.</para>
696 </parameter>
697 <parameter name="Account">
698 <para>Account code.</para>
699 </parameter>
700 <parameter name="EarlyMedia">
701 <para>Set to <literal>true</literal> to force call bridge on early media..</para>
702 </parameter>
703 <parameter name="Async">
704 <para>Set to <literal>true</literal> for fast origination.</para>
705 </parameter>
706 <parameter name="Codecs">
707 <para>Comma-separated list of codecs to use for this call.</para>
708 </parameter>
709 <parameter name="ChannelId">
710 <para>Channel UniqueId to be set on the channel.</para>
711 </parameter>
712 <parameter name="OtherChannelId">
713 <para>Channel UniqueId to be set on the second local channel.</para>
714 </parameter>
715 <parameter name="PreDialGoSub">
716 <para>PreDialGoSub Context,Extension,Priority to set options/headers needed before start the outgoing extension</para>
717 </parameter>
718 </syntax>
719 <description>
720 <para>Generates an outgoing call to a
721 <replaceable>Extension</replaceable>/<replaceable>Context</replaceable>/<replaceable>Priority</replaceable>
722 or <replaceable>Application</replaceable>/<replaceable>Data</replaceable></para>
723 </description>
724 <see-also>
725 <ref type="managerEvent">OriginateResponse</ref>
726 </see-also>
727 </manager>
728 <managerEvent language="en_US" name="OriginateResponse">
729 <managerEventInstance class="EVENT_FLAG_CALL">
730 <synopsis>Raised in response to an Originate command.</synopsis>
731 <syntax>
732 <parameter name="ActionID" required="false"/>
733 <parameter name="Response">
734 <enumlist>
735 <enum name="Failure"/>
736 <enum name="Success"/>
737 </enumlist>
738 </parameter>
739 <parameter name="Channel"/>
740 <parameter name="Context"/>
741 <parameter name="Exten"/>
742 <parameter name="Application"/>
743 <parameter name="Data"/>
744 <parameter name="Reason"/>
745 <parameter name="Uniqueid"/>
746 <parameter name="CallerIDNum"/>
747 <parameter name="CallerIDName"/>
748 </syntax>
749 <see-also>
750 <ref type="manager">Originate</ref>
751 </see-also>
752 </managerEventInstance>
753 </managerEvent>
754 <manager name="Command" language="en_US">
755 <synopsis>
756 Execute Asterisk CLI Command.
757 </synopsis>
758 <syntax>
759 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
760 <parameter name="Command" required="true">
761 <para>Asterisk CLI command to run.</para>
762 </parameter>
763 </syntax>
764 <description>
765 <para>Run a CLI command.</para>
766 </description>
767 </manager>
768 <manager name="ExtensionState" language="en_US">
769 <synopsis>
770 Check Extension Status.
771 </synopsis>
772 <syntax>
773 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
774 <parameter name="Exten" required="true">
775 <para>Extension to check state on.</para>
776 </parameter>
777 <parameter name="Context" required="true">
778 <para>Context for extension.</para>
779 </parameter>
780 </syntax>
781 <description>
782 <para>Report the extension state for given extension. If the extension has a hint,
783 will use devicestate to check the status of the device connected to the extension.</para>
784 <para>Will return an <literal>Extension Status</literal> message. The response will include
785 the hint for the extension and the status.</para>
786 </description>
787 <see-also>
788 <ref type="managerEvent">ExtensionStatus</ref>
789 </see-also>
790 </manager>
791 <manager name="PresenceState" language="en_US">
792 <synopsis>
793 Check Presence State
794 </synopsis>
795 <syntax>
796 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
797 <parameter name="Provider" required="true">
798 <para>Presence Provider to check the state of</para>
799 </parameter>
800 </syntax>
801 <description>
802 <para>Report the presence state for the given presence provider.</para>
803 <para>Will return a <literal>Presence State</literal> message. The response will include the
804 presence state and, if set, a presence subtype and custom message.</para>
805 </description>
806 <see-also>
807 <ref type="managerEvent">PresenceStatus</ref>
808 </see-also>
809 </manager>
810 <manager name="AbsoluteTimeout" language="en_US">
811 <synopsis>
812 Set absolute timeout.
813 </synopsis>
814 <syntax>
815 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
816 <parameter name="Channel" required="true">
817 <para>Channel name to hangup.</para>
818 </parameter>
819 <parameter name="Timeout" required="true">
820 <para>Maximum duration of the call (sec).</para>
821 </parameter>
822 </syntax>
823 <description>
824 <para>Hangup a channel after a certain time. Acknowledges set time with
825 <literal>Timeout Set</literal> message.</para>
826 </description>
827 </manager>
828 <manager name="MailboxStatus" language="en_US">
829 <synopsis>
830 Check mailbox.
831 </synopsis>
832 <syntax>
833 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
834 <parameter name="Mailbox" required="true">
835 <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
836 </parameter>
837 </syntax>
838 <description>
839 <para>Checks a voicemail account for status.</para>
840 <para>Returns whether there are messages waiting.</para>
841 <para>Message: Mailbox Status.</para>
842 <para>Mailbox: <replaceable>mailboxid</replaceable>.</para>
843 <para>Waiting: <literal>0</literal> if messages waiting, <literal>1</literal>
844 if no messages waiting.</para>
845 </description>
846 <see-also>
847 <ref type="manager">MailboxCount</ref>
848 </see-also>
849 </manager>
850 <manager name="MailboxCount" language="en_US">
851 <synopsis>
852 Check Mailbox Message Count.
853 </synopsis>
854 <syntax>
855 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
856 <parameter name="Mailbox" required="true">
857 <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
858 </parameter>
859 </syntax>
860 <description>
861 <para>Checks a voicemail account for new messages.</para>
862 <para>Returns number of urgent, new and old messages.</para>
863 <para>Message: Mailbox Message Count</para>
864 <para>Mailbox: <replaceable>mailboxid</replaceable></para>
865 <para>UrgentMessages: <replaceable>count</replaceable></para>
866 <para>NewMessages: <replaceable>count</replaceable></para>
867 <para>OldMessages: <replaceable>count</replaceable></para>
868 </description>
869 <see-also>
870 <ref type="manager">MailboxStatus</ref>
871 </see-also>
872 </manager>
873 <manager name="ListCommands" language="en_US">
874 <synopsis>
875 List available manager commands.
876 </synopsis>
877 <syntax>
878 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
879 </syntax>
880 <description>
881 <para>Returns the action name and synopsis for every action that
882 is available to the user.</para>
883 </description>
884 </manager>
885 <manager name="SendText" language="en_US">
886 <synopsis>
887 Sends a text message to channel. A content type can be optionally specified. If not set
888 it is set to an empty string allowing a custom handler to default it as it sees fit.
889 </synopsis>
890 <syntax>
891 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
892 <parameter name="Channel" required="true">
893 <para>Channel to send message to.</para>
894 </parameter>
895 <parameter name="Message" required="true">
896 <para>Message to send.</para>
897 </parameter>
898 <parameter name="Content-Type" required="false" default="">
899 <para>The type of content in the message</para>
900 </parameter>
901 </syntax>
902 <description>
903 <para>Sends A Text Message to a channel while in a call.</para>
904 </description>
905 <see-also>
906 <ref type="application">SendText</ref>
907 </see-also>
908 </manager>
909 <manager name="UserEvent" language="en_US">
910 <synopsis>
911 Send an arbitrary event.
912 </synopsis>
913 <syntax>
914 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
915 <parameter name="UserEvent" required="true">
916 <para>Event string to send.</para>
917 </parameter>
918 <parameter name="Header1">
919 <para>Content1.</para>
920 </parameter>
921 <parameter name="HeaderN">
922 <para>ContentN.</para>
923 </parameter>
924 </syntax>
925 <description>
926 <para>Send an event to manager sessions.</para>
927 </description>
928 <see-also>
929 <ref type="managerEvent">UserEvent</ref>
930 <ref type="application">UserEvent</ref>
931 </see-also>
932 </manager>
933 <manager name="WaitEvent" language="en_US">
934 <synopsis>
935 Wait for an event to occur.
936 </synopsis>
937 <syntax>
938 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
939 <parameter name="Timeout" required="true">
940 <para>Maximum time (in seconds) to wait for events, <literal>-1</literal> means forever.</para>
941 </parameter>
942 </syntax>
943 <description>
944 <para>This action will elicit a <literal>Success</literal> response. Whenever
945 a manager event is queued. Once WaitEvent has been called on an HTTP manager
946 session, events will be generated and queued.</para>
947 </description>
948 </manager>
949 <manager name="CoreSettings" language="en_US">
950 <synopsis>
951 Show PBX core settings (version etc).
952 </synopsis>
953 <syntax>
954 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
955 </syntax>
956 <description>
957 <para>Query for Core PBX settings.</para>
958 </description>
959 </manager>
960 <manager name="CoreStatus" language="en_US">
961 <synopsis>
962 Show PBX core status variables.
963 </synopsis>
964 <syntax>
965 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
966 </syntax>
967 <description>
968 <para>Query for Core PBX status.</para>
969 </description>
970 </manager>
971 <manager name="Reload" language="en_US">
972 <synopsis>
973 Send a reload event.
974 </synopsis>
975 <syntax>
976 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
977 <parameter name="Module">
978 <para>Name of the module to reload.</para>
979 </parameter>
980 </syntax>
981 <description>
982 <para>Send a reload event.</para>
983 </description>
984 <see-also>
985 <ref type="manager">ModuleLoad</ref>
986 </see-also>
987 </manager>
988 <managerEvent language="en_US" name="CoreShowChannel">
989 <managerEventInstance class="EVENT_FLAG_CALL">
990 <synopsis>Raised in response to a CoreShowChannels command.</synopsis>
991 <syntax>
992 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
993 <channel_snapshot/>
994 <parameter name="BridgeId">
995 <para>Identifier of the bridge the channel is in, may be empty if not in one</para>
996 </parameter>
997 <parameter name="Application">
998 <para>Application currently executing on the channel</para>
999 </parameter>
1000 <parameter name="ApplicationData">
1001 <para>Data given to the currently executing application</para>
1002 </parameter>
1003 <parameter name="Duration">
1004 <para>The amount of time the channel has existed</para>
1005 </parameter>
1006 </syntax>
1007 <see-also>
1008 <ref type="manager">CoreShowChannels</ref>
1009 <ref type="managerEvent">CoreShowChannelsComplete</ref>
1010 </see-also>
1011 </managerEventInstance>
1012 </managerEvent>
1013 <managerEvent language="en_US" name="CoreShowChannelsComplete">
1014 <managerEventInstance class="EVENT_FLAG_CALL">
1015 <synopsis>Raised at the end of the CoreShowChannel list produced by the CoreShowChannels command.</synopsis>
1016 <syntax>
1017 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1018 <parameter name="EventList">
1019 <para>Conveys the status of the command reponse list</para>
1020 </parameter>
1021 <parameter name="ListItems">
1022 <para>The total number of list items produced</para>
1023 </parameter>
1024 </syntax>
1025 <see-also>
1026 <ref type="manager">CoreShowChannels</ref>
1027 <ref type="managerEvent">CoreShowChannel</ref>
1028 </see-also>
1029 </managerEventInstance>
1030 </managerEvent>
1031 <manager name="CoreShowChannels" language="en_US">
1032 <synopsis>
1033 List currently active channels.
1034 </synopsis>
1035 <syntax>
1036 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1037 </syntax>
1038 <description>
1039 <para>List currently defined channels and some information about them.</para>
1040 </description>
1041 <responses>
1042 <list-elements>
1043 <xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannel'])" />
1044 </list-elements>
1045 <xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannelsComplete'])" />
1046 </responses>
1047 </manager>
1048 <managerEvent language="en_US" name="CoreShowChannelMapComplete">
1049 <managerEventInstance class="EVENT_FLAG_CALL">
1050 <synopsis>Raised at the end of the CoreShowChannelMap list produced by the CoreShowChannelMap command.</synopsis>
1051 <syntax>
1052 <parameter name="EventList">
1053 <para>Conveys the status of the command response list</para>
1054 </parameter>
1055 <parameter name="ListItems">
1056 <para>The total number of list items produced</para>
1057 </parameter>
1058 </syntax>
1059 </managerEventInstance>
1060 </managerEvent>
1061 <manager name="CoreShowChannelMap" language="en_US">
1062 <synopsis>
1063 List all channels connected to the specified channel.
1064 </synopsis>
1065 <syntax>
1066 <parameter name="Channel">
1067 <para>The channel to get the mapping for. Requires a channel name.</para>
1068 </parameter>
1069 </syntax>
1070 <description>
1071 <para>List all channels currently connected to the specified channel. This can be any channel, including
1072 Local channels, and Local channels will be followed through to their other half.</para>
1073 </description>
1074 </manager>
1075 <manager name="LoggerRotate" language="en_US">
1076 <synopsis>
1077 Reload and rotate the Asterisk logger.
1078 </synopsis>
1079 <syntax>
1080 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1081 </syntax>
1082 <description>
1083 <para>Reload and rotate the logger. Analogous to the CLI command 'logger rotate'.</para>
1084 </description>
1085 </manager>
1086 <manager name="ModuleLoad" language="en_US">
1087 <synopsis>
1088 Module management.
1089 </synopsis>
1090 <syntax>
1091 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1092 <parameter name="Module">
1093 <para>Asterisk module name (including .so extension) or subsystem identifier:</para>
1094 <enumlist>
1095 <enum name="cdr" />
1096 <enum name="dnsmgr" />
1097 <enum name="extconfig" />
1098 <enum name="enum" />
1099 <enum name="acl" />
1100 <enum name="manager" />
1101 <enum name="http" />
1102 <enum name="logger" />
1103 <enum name="features" />
1104 <enum name="dsp" />
1105 <enum name="udptl" />
1106 <enum name="indications" />
1107 <enum name="cel" />
1108 <enum name="plc" />
1109 </enumlist>
1110 </parameter>
1111 <parameter name="LoadType" required="true">
1112 <para>The operation to be done on module. Subsystem identifiers may only
1113 be reloaded.</para>
1114 <enumlist>
1115 <enum name="load" />
1116 <enum name="unload" />
1117 <enum name="reload" />
1118 </enumlist>
1119 <para>If no module is specified for a <literal>reload</literal> loadtype,
1120 all modules are reloaded.</para>
1121 </parameter>
1122 </syntax>
1123 <description>
1124 <para>Loads, unloads or reloads an Asterisk module in a running system.</para>
1125 </description>
1126 <see-also>
1127 <ref type="manager">Reload</ref>
1128 <ref type="manager">ModuleCheck</ref>
1129 </see-also>
1130 </manager>
1131 <manager name="ModuleCheck" language="en_US">
1132 <synopsis>
1133 Check if module is loaded.
1134 </synopsis>
1135 <syntax>
1136 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1137 <parameter name="Module" required="true">
1138 <para>Asterisk module name (not including extension).</para>
1139 </parameter>
1140 </syntax>
1141 <description>
1142 <para>Checks if Asterisk module is loaded. Will return Success/Failure.
1143 An empty Version header is also returned (which doesn't contain
1144 the module revision number).</para>
1145 </description>
1146 <see-also>
1147 <ref type="manager">ModuleLoad</ref>
1148 </see-also>
1149 </manager>
1150 <manager name="AOCMessage" language="en_US">
1151 <synopsis>
1152 Generate an Advice of Charge message on a channel.
1153 </synopsis>
1154 <syntax>
1155 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1156 <parameter name="Channel">
1157 <para>Channel name to generate the AOC message on.
1158 This value is required unless ChannelPrefix is given.</para>
1159 </parameter>
1160 <parameter name="ChannelPrefix">
1161 <para>Partial channel prefix. By using this option one can match the beginning part
1162 of a channel name without having to put the entire name in. For example
1163 if a channel name is SIP/snom-00000001 and this value is set to SIP/snom, then
1164 that channel matches and the message will be sent. Note however that only
1165 the first matched channel has the message sent on it. </para>
1166 </parameter>
1167 <parameter name="MsgType" required="true">
1168 <para>Defines what type of AOC message to create, AOC-S, AOC-D or AOC-E</para>
1169 <enumlist>
1170 <enum name="S" />
1171 <enum name="D" />
1172 <enum name="E" />
1173 </enumlist>
1174 </parameter>
1175 <parameter name="ChargeType">
1176 <para>Defines what kind of charge this message represents for AOC-D and AOC-E.</para>
1177 <enumlist>
1178 <enum name="NA" />
1179 <enum name="FREE" />
1180 <enum name="Currency" />
1181 <enum name="Unit" />
1182 </enumlist>
1183 </parameter>
1184 <parameter name="UnitAmount(0)">
1185 <para>This represents the amount of units charged. The ETSI AOC standard specifies that
1186 this value along with the optional UnitType value are entries in a list. To accommodate this
1187 these values take an index value starting at 0 which can be used to generate this list of
1188 unit entries. For Example, If two unit entires were required this could be achieved by setting the
1189 paramter UnitAmount(0)=1234 and UnitAmount(1)=5678. Note that UnitAmount at index 0 is
1190 required when ChargeType=Unit, all other entries in the list are optional.
1191 </para>
1192 </parameter>
1193 <parameter name="UnitType(0)">
1194 <para>Defines the type of unit. ETSI AOC standard specifies this as an integer
1195 value between 1 and 16, but this value is left open to accept any positive
1196 integer. Like the UnitAmount parameter, this value represents a list entry
1197 and has an index parameter that starts at 0.
1198 </para>
1199 </parameter>
1200 <parameter name="CurrencyName">
1201 <para>Specifies the currency's name. Note that this value is truncated after 10 characters.</para>
1202 </parameter>
1203 <parameter name="CurrencyAmount">
1204 <para>Specifies the charge unit amount as a positive integer.
1205 This value is required when ChargeType==Currency (AOC-D or AOC-E) or
1206 RateType==Duration/Flat/Volume (AOC-S).</para>
1207 </parameter>
1208 <parameter name="CurrencyMultiplier">
1209 <para>Specifies the currency multiplier.
1210 This value is required when CurrencyAmount is given.</para>
1211 <enumlist>
1212 <enum name="OneThousandth" />
1213 <enum name="OneHundredth" />
1214 <enum name="OneTenth" />
1215 <enum name="One" />
1216 <enum name="Ten" />
1217 <enum name="Hundred" />
1218 <enum name="Thousand" />
1219 </enumlist>
1220 </parameter>
1221 <parameter name="TotalType" default="Total">
1222 <para>Defines what kind of AOC-D total is represented.</para>
1223 <enumlist>
1224 <enum name="Total" />
1225 <enum name="SubTotal" />
1226 </enumlist>
1227 </parameter>
1228 <parameter name="AOCBillingId">
1229 <para>Represents a billing ID associated with an AOC-D or AOC-E message. Note
1230 that only the first 3 items of the enum are valid AOC-D billing IDs</para>
1231 <enumlist>
1232 <enum name="Normal" />
1233 <enum name="ReverseCharge" />
1234 <enum name="CreditCard" />
1235 <enum name="CallFwdUnconditional" />
1236 <enum name="CallFwdBusy" />
1237 <enum name="CallFwdNoReply" />
1238 <enum name="CallDeflection" />
1239 <enum name="CallTransfer" />
1240 </enumlist>
1241 </parameter>
1242 <parameter name="ChargingAssociationId">
1243 <para>Charging association identifier. This is optional for AOC-E and can be
1244 set to any value between -32768 and 32767</para>
1245 </parameter>
1246 <parameter name="ChargingAssociationNumber">
1247 <para>Represents the charging association party number. This value is optional
1248 for AOC-E.</para>
1249 </parameter>
1250 <parameter name="ChargingAssociationPlan">
1251 <para>Integer representing the charging plan associated with the ChargingAssociationNumber.
1252 The value is bits 7 through 1 of the Q.931 octet containing the type-of-number and
1253 numbering-plan-identification fields.</para>
1254 </parameter>
1255 <parameter name="ChargedItem">
1256 <para>Defines what part of the call is charged in AOC-S. Usually this is set to
1257 BasicCommunication, which refers to the time after the call is answered, but establishment
1258 (CallAttempt) or successful establishment (CallSetup) of a call can also be used.
1259 Other options are available, but these generally do not carry enough information to actually
1260 calculate the price of a call.
1261 It is possible to have multiple ChargedItem entries for a single call -- for example to
1262 charge for both the establishment of the call and the actual call. In this case, each
1263 ChargedItem is described by a ChargedItem: header and all other headers that follow it up to
1264 the next ChargedItem: header.</para>
1265 <enumlist>
1266 <enum name="NA" />
1267 <enum name="SpecialArrangement" />
1268 <enum name="BasicCommunication" />
1269 <enum name="CallAttempt" />
1270 <enum name="CallSetup" />
1271 <enum name="UserUserInfo" />
1272 <enum name="SupplementaryService" />
1273 </enumlist>
1274 </parameter>
1275 <parameter name="RateType">
1276 <para>Defines how an AOC-S ChargedItem is charged.
1277 The Duration option is only available when ChargedItem==BasicCommunication.</para>
1278 <enumlist>
1279 <enum name="NA" />
1280 <enum name="Free" />
1281 <enum name="FreeFromBeginning" />
1282 <enum name="Duration" />
1283 <enum name="Flat" />
1284 <enum name="Volume" />
1285 <enum name="SpecialCode" />
1286 </enumlist>
1287 </parameter>
1288 <parameter name="Time">
1289 <para>Specifies a positive integer which is the amount of time is paid for by one
1290 CurrencyAmount.
1291 This value is required when RateType==Duration.</para>
1292 </parameter>
1293 <parameter name="TimeScale">
1294 <para>Specifies the time multiplier.
1295 This value is required when Time is given.</para>
1296 <enumlist>
1297 <enum name="OneHundredthSecond" />
1298 <enum name="OneTenthSecond" />
1299 <enum name="Second" />
1300 <enum name="TenSeconds" />
1301 <enum name="Minute" />
1302 <enum name="Hour" />
1303 <enum name="Day" />
1304 </enumlist>
1305 </parameter>
1306 <parameter name="Granularity">
1307 <para>Specifies a positive integer which is the size of the charged time increments.
1308 This value is optional when RateType==Duration and ChargingType==StepFunction.</para>
1309 </parameter>
1310 <parameter name="GranularityTimeScale">
1311 <para>Specifies the granularity time multiplier.
1312 This value is required when Granularity is given.</para>
1313 <enumlist>
1314 <enum name="OneHundredthSecond" />
1315 <enum name="OneTenthSecond" />
1316 <enum name="Second" />
1317 <enum name="TenSeconds" />
1318 <enum name="Minute" />
1319 <enum name="Hour" />
1320 <enum name="Day" />
1321 </enumlist>
1322 </parameter>
1323 <parameter name="ChargingType">
1324 <para>Specifies whether the charge increases continuously with time or in increments of
1325 Time or, if provided, Granularity.
1326 This value is required when RateType==Duration.</para>
1327 <enumlist>
1328 <enum name="ContinuousCharging" />
1329 <enum name="StepFunction" />
1330 </enumlist>
1331 </parameter>
1332 <parameter name="VolumeUnit">
1333 <para>Specifies the quantity of which one unit is paid for by one CurrencyAmount.
1334 This value is required when RateType==Volume.</para>
1335 <enumlist>
1336 <enum name="Octet" />
1337 <enum name="Segment" />
1338 <enum name="Message" />
1339 </enumlist>
1340 </parameter>
1341 <parameter name="Code">
1342 <para>Specifies the charging code, which can be set to a value between 1 and 10.
1343 This value is required when ChargedItem==SpecialArrangement or RateType==SpecialCode.</para>
1344 </parameter>
1345 </syntax>
1346 <description>
1347 <para>Generates an AOC-S, AOC-D or AOC-E message on a channel.</para>
1348 </description>
1349 <see-also>
1350 <ref type="managerEvent">AOC-S</ref>
1351 <ref type="managerEvent">AOC-D</ref>
1352 <ref type="managerEvent">AOC-E</ref>
1353 </see-also>
1354 </manager>
1355 <function name="AMI_CLIENT" language="en_US">
1356 <synopsis>
1357 Checks attributes of manager accounts
1358 </synopsis>
1359 <syntax>
1360 <parameter name="loginname" required="true">
1361 <para>Login name, specified in manager.conf</para>
1362 </parameter>
1363 <parameter name="field" required="true">
1364 <para>The manager account attribute to return</para>
1365 <enumlist>
1366 <enum name="sessions"><para>The number of sessions for this AMI account</para></enum>
1367 </enumlist>
1368 </parameter>
1369 </syntax>
1370 <description>
1371 <para>
1372 Currently, the only supported parameter is "sessions" which will return the current number of
1373 active sessions for this AMI account.
1374 </para>
1375 </description>
1376 </function>
1377 <manager name="Filter" language="en_US">
1378 <synopsis>
1379 Dynamically add filters for the current manager session.
1380 </synopsis>
1381 <syntax>
1382 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1383 <parameter name="Operation">
1384 <enumlist>
1385 <enum name="Add">
1386 <para>Add a filter.</para>
1387 </enum>
1388 </enumlist>
1389 </parameter>
1390 <parameter name="Filter">
1391 <para>Filters can be whitelist or blacklist</para>
1392 <para>Example whitelist filter: "Event: Newchannel"</para>
1393 <para>Example blacklist filter: "!Channel: DAHDI.*"</para>
1394 <para>This filter option is used to whitelist or blacklist events per user to be
1395 reported with regular expressions and are allowed if both the regex matches
1396 and the user has read access as defined in manager.conf. Filters are assumed to be for whitelisting
1397 unless preceeded by an exclamation point, which marks it as being black.
1398 Evaluation of the filters is as follows:</para>
1399 <para>- If no filters are configured all events are reported as normal.</para>
1400 <para>- If there are white filters only: implied black all filter processed first, then white filters.</para>
1401 <para>- If there are black filters only: implied white all filter processed first, then black filters.</para>
1402 <para>- If there are both white and black filters: implied black all filter processed first, then white
1403 filters, and lastly black filters.</para>
1404 </parameter>
1405 </syntax>
1406 <description>
1407 <para>The filters added are only used for the current session.
1408 Once the connection is closed the filters are removed.</para>
1409 <para>This comand requires the system permission because
1410 this command can be used to create filters that may bypass
1411 filters defined in manager.conf</para>
1412 </description>
1413 </manager>
1414 <manager name="BlindTransfer" language="en_US">
1415 <synopsis>
1416 Blind transfer channel(s) to the given destination
1417 </synopsis>
1418 <syntax>
1419 <parameter name="Channel" required="true">
1420 </parameter>
1421 <parameter name="Context">
1422 </parameter>
1423 <parameter name="Exten">
1424 </parameter>
1425 </syntax>
1426 <description>
1427 <para>Redirect all channels currently bridged to the specified channel to the specified destination.</para>
1428 </description>
1429 <see-also>
1430 <ref type="manager">Redirect</ref>
1431 <ref type="managerEvent">BlindTransfer</ref>
1432 </see-also>
1433 </manager>
1434 <managerEvent name="ExtensionStatus" language="en_US">
1435 <managerEventInstance class="EVENT_FLAG_CALL">
1436 <synopsis>Raised when a hint changes due to a device state change.</synopsis>
1437 <syntax>
1438 <parameter name="Exten">
1439 <para>Name of the extension.</para>
1440 </parameter>
1441 <parameter name="Context">
1442 <para>Context that owns the extension.</para>
1443 </parameter>
1444 <parameter name="Hint">
1445 <para>Hint set for the extension</para>
1446 </parameter>
1447 <parameter name="Status">
1448 <para>Numerical value of the extension status. Extension
1449 status is determined by the combined device state of all items
1450 contained in the hint.</para>
1451 <enumlist>
1452 <enum name="-2">
1453 <para>The extension was removed from the dialplan.</para>
1454 </enum>
1455 <enum name="-1">
1456 <para>The extension's hint was removed from the dialplan.</para>
1457 </enum>
1458 <enum name="0">
1459 <para><literal>Idle</literal> - Related device(s) are in an idle
1460 state.</para>
1461 </enum>
1462 <enum name="1">
1463 <para><literal>InUse</literal> - Related device(s) are in active
1464 calls but may take more calls.</para>
1465 </enum>
1466 <enum name="2">
1467 <para><literal>Busy</literal> - Related device(s) are in active
1468 calls and may not take any more calls.</para>
1469 </enum>
1470 <enum name="4">
1471 <para><literal>Unavailable</literal> - Related device(s) are
1472 not reachable.</para>
1473 </enum>
1474 <enum name="8">
1475 <para><literal>Ringing</literal> - Related device(s) are
1476 currently ringing.</para>
1477 </enum>
1478 <enum name="9">
1479 <para><literal>InUse&amp;Ringing</literal> - Related device(s)
1480 are currently ringing and in active calls.</para>
1481 </enum>
1482 <enum name="16">
1483 <para><literal>Hold</literal> - Related device(s) are
1484 currently on hold.</para>
1485 </enum>
1486 <enum name="17">
1487 <para><literal>InUse&amp;Hold</literal> - Related device(s)
1488 are currently on hold and in active calls.</para>
1489 </enum>
1490 </enumlist>
1491 </parameter>
1492 <parameter name="StatusText">
1493 <para>Text representation of <literal>Status</literal>.</para>
1494 <enumlist>
1495 <enum name="Idle" />
1496 <enum name="InUse" />
1497 <enum name="Busy" />
1498 <enum name="Unavailable" />
1499 <enum name="Ringing" />
1500 <enum name="InUse&amp;Ringing" />
1501 <enum name="Hold" />
1502 <enum name="InUse&amp;Hold" />
1503 <enum name="Unknown">
1504 <para>Status does not match any of the above values.</para>
1505 </enum>
1506 </enumlist>
1507 </parameter>
1508 </syntax>
1509 <see-also>
1510 <ref type="manager">ExtensionState</ref>
1511 </see-also>
1512 </managerEventInstance>
1513 </managerEvent>
1514 <managerEvent name="PresenceStatus" language="en_US">
1515 <managerEventInstance class="EVENT_FLAG_CALL">
1516 <synopsis>Raised when a hint changes due to a presence state change.</synopsis>
1517 <syntax>
1518 <parameter name="Exten" />
1519 <parameter name="Context" />
1520 <parameter name="Hint" />
1521 <parameter name="Status" />
1522 <parameter name="Subtype" />
1523 <parameter name="Message" />
1524 </syntax>
1525 <see-also>
1526 <ref type="manager">PresenceState</ref>
1527 </see-also>
1528 </managerEventInstance>
1529 </managerEvent>
1530 ***/
1531
1532/*! \addtogroup Group_AMI AMI functions
1533*/
1534/*! @{
1535 Doxygen group */
1536
1551
1556};
1557
1558/*!
1559 * Linked list of events.
1560 * Global events are appended to the list by append_event().
1561 * The usecount is the number of stored pointers to the element,
1562 * excluding the list pointers. So an element that is only in
1563 * the list has a usecount of 0, not 1.
1564 *
1565 * Clients have a pointer to the last event processed, and for each
1566 * of these clients we track the usecount of the elements.
1567 * If we have a pointer to an entry in the list, it is safe to navigate
1568 * it forward because elements will not be deleted, but only appended.
1569 * The worst that can happen is seeing the pointer still NULL.
1570 *
1571 * When the usecount of an element drops to 0, and the element is the
1572 * first in the list, we can remove it. Removal is done within the
1573 * main thread, which is woken up for the purpose.
1574 *
1575 * For simplicity of implementation, we make sure the list is never empty.
1576 */
1578 int usecount; /*!< # of clients who still need the event */
1580 unsigned int seq; /*!< sequence number */
1581 struct timeval tv; /*!< When event was allocated */
1582 AST_RWLIST_ENTRY(eventqent) eq_next;
1583 char eventdata[1]; /*!< really variable size, allocated by append_event() */
1584};
1585
1587
1588static int displayconnects = 1;
1589static int allowmultiplelogin = 1;
1591static int httptimeout = 60;
1593static int manager_enabled = 0;
1594static int subscribed = 0;
1595static int webmanager_enabled = 0;
1596static int manager_debug = 0; /*!< enable some debugging code in the manager */
1597static int authtimeout;
1598static int authlimit;
1601
1602#define DEFAULT_REALM "asterisk"
1603static char global_realm[MAXHOSTNAMELEN]; /*!< Default realm */
1604
1605static int unauth_sessions = 0;
1607
1608/*! \brief A \ref stasis_topic that all topics AMI cares about will be forwarded to */
1610
1611/*! \brief The \ref stasis_message_router for all \ref stasis messages */
1613
1614/*! \brief The \ref stasis_subscription for forwarding the RTP topic to the AMI topic */
1616
1617/*! \brief The \ref stasis_subscription for forwarding the Security topic to the AMI topic */
1619
1620/*!
1621 * \brief Set to true (non-zero) to globally allow all dangerous AMI actions to run
1622 */
1624
1625#ifdef TEST_FRAMEWORK
1626/*! \brief The \ref stasis_subscription for forwarding the Test topic to the AMI topic */
1627static struct stasis_forward *test_suite_forwarder;
1628#endif
1629
1630#define MGR_SHOW_TERMINAL_WIDTH 80
1631
1632#define MAX_VARS 128
1633
1634/*! \brief Fake event class used to end sessions at shutdown */
1635#define EVENT_FLAG_SHUTDOWN -1
1636
1637/*! \brief
1638 * Descriptor for a manager session, either on the AMI socket or over HTTP.
1639 *
1640 * \note
1641 * AMI session have managerid == 0; the entry is created upon a connect,
1642 * and destroyed with the socket.
1643 * HTTP sessions have managerid != 0, the value is used as a search key
1644 * to lookup sessions (using the mansession_id cookie, or nonce key from
1645 * Digest Authentication http header).
1646 */
1647#define MAX_BLACKLIST_CMD_LEN 2
1648static const struct {
1650} command_blacklist[] = {
1651 {{ "module", "load", NULL }},
1652 {{ "module", "unload", NULL }},
1653 {{ "restart", "gracefully", NULL }},
1655
1656static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
1657
1659{
1660 if (!acl_change_sub) {
1665 }
1666}
1667
1669{
1671}
1672
1673/* In order to understand what the heck is going on with the
1674 * mansession_session and mansession structs, we need to have a bit of a history
1675 * lesson.
1676 *
1677 * In the beginning, there was the mansession. The mansession contained data that was
1678 * intrinsic to a manager session, such as the time that it started, the name of the logged-in
1679 * user, etc. In addition to these parameters were the f and fd parameters. For typical manager
1680 * sessions, these were used to represent the TCP socket over which the AMI session was taking
1681 * place. It makes perfect sense for these fields to be a part of the session-specific data since
1682 * the session actually defines this information.
1683 *
1684 * Then came the HTTP AMI sessions. With these, the f and fd fields need to be opened and closed
1685 * for every single action that occurs. Thus the f and fd fields aren't really specific to the session
1686 * but rather to the action that is being executed. Because a single session may execute many commands
1687 * at once, some sort of safety needed to be added in order to be sure that we did not end up with fd
1688 * leaks from one action overwriting the f and fd fields used by a previous action before the previous action
1689 * has had a chance to properly close its handles.
1690 *
1691 * The initial idea to solve this was to use thread synchronization, but this prevented multiple actions
1692 * from being run at the same time in a single session. Some manager actions may block for a long time, thus
1693 * creating a large queue of actions to execute. In addition, this fix did not address the basic architectural
1694 * issue that for HTTP manager sessions, the f and fd variables are not really a part of the session, but are
1695 * part of the action instead.
1696 *
1697 * The new idea was to create a structure on the stack for each HTTP Manager action. This structure would
1698 * contain the action-specific information, such as which file to write to. In order to maintain expectations
1699 * of action handlers and not have to change the public API of the manager code, we would need to name this
1700 * new stacked structure 'mansession' and contain within it the old mansession struct that we used to use.
1701 * We renamed the old mansession struct 'mansession_session' to hopefully convey that what is in this structure
1702 * is session-specific data. The structure that it is wrapped in, called a 'mansession' really contains action-specific
1703 * data.
1704 */
1706 /*! \todo XXX need to document which fields it is protecting */
1707 struct ast_sockaddr addr; /*!< address we are connecting from */
1708 struct ast_iostream *stream; /*!< AMI stream */
1709 int inuse; /*!< number of HTTP sessions using this entry */
1710 int needdestroy; /*!< Whether an HTTP session should be destroyed */
1711 pthread_t waiting_thread; /*!< Sleeping thread using this descriptor */
1712 uint32_t managerid; /*!< Unique manager identifier, 0 for AMI sessions */
1713 time_t sessionstart; /*!< Session start time */
1714 struct timeval sessionstart_tv; /*!< Session start time */
1715 time_t sessiontimeout; /*!< Session timeout if HTTP */
1716 char username[80]; /*!< Logged in username */
1717 char challenge[10]; /*!< Authentication challenge */
1718 int authenticated; /*!< Authentication status */
1719 int readperm; /*!< Authorization for reading */
1720 int writeperm; /*!< Authorization for writing */
1721 char inbuf[1025]; /*!< Buffer - we use the extra byte to add a '\\0' and simplify parsing */
1722 int inlen; /*!< number of buffered bytes */
1723 struct ao2_container *whitefilters; /*!< Manager event filters - white list */
1724 struct ao2_container *blackfilters; /*!< Manager event filters - black list */
1725 struct ast_variable *chanvars; /*!< Channel variables to set for originate */
1726 int send_events; /*!< XXX what ? */
1727 struct eventqent *last_ev; /*!< last event processed. */
1728 int writetimeout; /*!< Timeout for ast_carefulwrite() */
1730 int pending_event; /*!< Pending events indicator in case when waiting_thread is NULL */
1731 time_t noncetime; /*!< Timer for nonce value expiration */
1732 unsigned long oldnonce; /*!< Stale nonce value */
1733 unsigned long nc; /*!< incremental nonce counter */
1734 unsigned int kicked:1; /*!< Flag set if session is forcibly kicked */
1735 ast_mutex_t notify_lock; /*!< Lock for notifying this session of events */
1738};
1739
1744
1745/*! \brief In case you didn't read that giant block of text above the mansession_session struct, the
1746 * \ref mansession is named this solely to keep the API the same in Asterisk. This structure really
1747 * represents data that is different from Manager action to Manager action. The mansession_session pointer
1748 * contained within points to session-specific data.
1749 */
1755 unsigned int write_error:1;
1758};
1759
1760/*! Active manager connection sessions container. */
1761static AO2_GLOBAL_OBJ_STATIC(mgr_sessions);
1762
1763/*! \brief user descriptor, as read from the config file.
1764 *
1765 * \note It is still missing some fields -- e.g. we can have multiple permit and deny
1766 * lines which are not supported here, and readperm/writeperm/writetimeout
1767 * are not stored.
1768 */
1770 char username[80];
1771 char *secret; /*!< Secret for logging in */
1772 int readperm; /*!< Authorization for reading */
1773 int writeperm; /*!< Authorization for writing */
1774 int writetimeout; /*!< Per user Timeout for ast_carefulwrite() */
1775 int displayconnects; /*!< XXX unused */
1776 int allowmultiplelogin; /*!< Per user option*/
1777 int keep; /*!< mark entries created on a reload */
1778 struct ao2_container *whitefilters; /*!< Manager event filters - white list */
1779 struct ao2_container *blackfilters; /*!< Manager event filters - black list */
1780 struct ast_acl_list *acl; /*!< ACL setting */
1781 char *a1_hash; /*!< precalculated A1 for Digest auth */
1782 struct ast_variable *chanvars; /*!< Channel variables to set for originate */
1784};
1785
1786/*! \brief list of users found in the config file */
1788
1789/*! \brief list of actions registered */
1791
1792/*! \brief list of hooks registered */
1794
1795#ifdef AST_XML_DOCS
1796/*! \brief A container of event documentation nodes */
1797static AO2_GLOBAL_OBJ_STATIC(event_docs);
1798#endif
1799
1800static int __attribute__((format(printf, 9, 0))) __manager_event_sessions(
1801 struct ao2_container *sessions,
1802 int category,
1803 const char *event,
1804 int chancount,
1805 struct ast_channel **chans,
1806 const char *file,
1807 int line,
1808 const char *func,
1809 const char *fmt,
1810 ...);
1811static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters);
1812
1813static int match_filter(struct mansession *s, char *eventdata);
1814
1815/*!
1816 * @{ \brief Define AMI message types.
1817 */
1819/*! @} */
1820
1821/*!
1822 * \internal
1823 * \brief Find a registered action object.
1824 *
1825 * \param name Name of AMI action to find.
1826 *
1827 * \return Reffed action found or NULL
1828 */
1829static struct manager_action *action_find(const char *name)
1830{
1831 struct manager_action *act;
1832
1834 AST_RWLIST_TRAVERSE(&actions, act, list) {
1835 if (!strcasecmp(name, act->action)) {
1836 ao2_t_ref(act, +1, "found action object");
1837 break;
1838 }
1839 }
1841
1842 return act;
1843}
1844
1846{
1847 return manager_topic;
1848}
1849
1851{
1852 return stasis_router;
1853}
1854
1855static void manager_json_value_str_append(struct ast_json *value, const char *key,
1856 struct ast_str **res)
1857{
1858 switch (ast_json_typeof(value)) {
1859 case AST_JSON_STRING:
1860 ast_str_append(res, 0, "%s: %s\r\n", key, ast_json_string_get(value));
1861 break;
1862 case AST_JSON_INTEGER:
1863 ast_str_append(res, 0, "%s: %jd\r\n", key, ast_json_integer_get(value));
1864 break;
1865 case AST_JSON_TRUE:
1866 ast_str_append(res, 0, "%s: True\r\n", key);
1867 break;
1868 case AST_JSON_FALSE:
1869 ast_str_append(res, 0, "%s: False\r\n", key);
1870 break;
1871 default:
1872 ast_str_append(res, 0, "%s: \r\n", key);
1873 break;
1874 }
1875}
1876
1877static void manager_json_to_ast_str(struct ast_json *obj, const char *key,
1878 struct ast_str **res, key_exclusion_cb exclusion_cb);
1879
1880static void manager_json_array_with_key(struct ast_json *obj, const char* key,
1881 size_t index, struct ast_str **res,
1882 key_exclusion_cb exclusion_cb)
1883{
1884 struct ast_str *key_str = ast_str_alloca(64);
1885 ast_str_set(&key_str, 0, "%s(%zu)", key, index);
1887 res, exclusion_cb);
1888}
1889
1890static void manager_json_obj_with_key(struct ast_json *obj, const char* key,
1891 const char *parent_key, struct ast_str **res,
1892 key_exclusion_cb exclusion_cb)
1893{
1894 if (parent_key) {
1895 struct ast_str *key_str = ast_str_alloca(64);
1896 ast_str_set(&key_str, 0, "%s/%s", parent_key, key);
1898 res, exclusion_cb);
1899 return;
1900 }
1901
1902 manager_json_to_ast_str(obj, key, res, exclusion_cb);
1903}
1904
1905void manager_json_to_ast_str(struct ast_json *obj, const char *key,
1906 struct ast_str **res, key_exclusion_cb exclusion_cb)
1907{
1908 struct ast_json_iter *i;
1909
1910 /* If obj or res is not given, just return */
1911 if (!obj || !res) {
1912 return;
1913 }
1914
1915 if (!*res && !(*res = ast_str_create(1024))) {
1916 return;
1917 }
1918
1919 if (exclusion_cb && key && exclusion_cb(key)) {
1920 return;
1921 }
1922
1923 if (ast_json_typeof(obj) != AST_JSON_OBJECT &&
1925 manager_json_value_str_append(obj, key, res);
1926 return;
1927 }
1928
1929 if (ast_json_typeof(obj) == AST_JSON_ARRAY) {
1930 size_t j;
1931 for (j = 0; j < ast_json_array_size(obj); ++j) {
1933 key, j, res, exclusion_cb);
1934 }
1935 return;
1936 }
1937
1938 for (i = ast_json_object_iter(obj); i;
1939 i = ast_json_object_iter_next(obj, i)) {
1942 key, res, exclusion_cb);
1943 }
1944}
1945
1947{
1948 struct ast_str *res = ast_str_create(1024);
1949
1950 if (!ast_json_is_null(blob)) {
1951 manager_json_to_ast_str(blob, NULL, &res, exclusion_cb);
1952 }
1953
1954 return res;
1955}
1956
1957#define manager_event_sessions(sessions, category, event, contents , ...) \
1958 __manager_event_sessions(sessions, category, event, 0, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, contents , ## __VA_ARGS__)
1959
1960#define any_manager_listeners(sessions) \
1961 ((sessions && ao2_container_count(sessions)) || !AST_RWLIST_EMPTY(&manager_hooks))
1962
1963static void manager_default_msg_cb(void *data, struct stasis_subscription *sub,
1964 struct stasis_message *message)
1965{
1966 struct ao2_container *sessions;
1967 struct ast_manager_event_blob *ev;
1968
1970 /* Not an AMI message; disregard */
1971 return;
1972 }
1973
1974 sessions = ao2_global_obj_ref(mgr_sessions);
1976 /* Nobody is listening */
1978 return;
1979 }
1980
1982 if (!ev) {
1983 /* Conversion failure */
1985 return;
1986 }
1987
1989 "%s", ev->extra_fields);
1990 ao2_ref(ev, -1);
1992}
1993
1994static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub,
1995 struct stasis_message *message)
1996{
1997 struct ast_json_payload *payload;
1998 int class_type;
1999 const char *type;
2000 struct ast_json *event;
2001 struct ast_str *event_buffer;
2002 struct ao2_container *sessions;
2003
2004 sessions = ao2_global_obj_ref(mgr_sessions);
2006 /* Nobody is listening */
2008 return;
2009 }
2010
2011 payload = stasis_message_data(message);
2012 class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type"));
2013 type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
2014 event = ast_json_object_get(payload->json, "event");
2015
2017 if (!event_buffer) {
2018 ast_log(AST_LOG_WARNING, "Error while creating payload for event %s\n", type);
2020 return;
2021 }
2023 "%s", ast_str_buffer(event_buffer));
2024 ast_free(event_buffer);
2026}
2027
2028void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
2029{
2030 RAII_VAR(struct ast_json *, event_info, NULL, ast_json_unref);
2031 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2033
2034 if (!obj || !ast_manager_get_generic_type()) {
2035 return;
2036 }
2037
2038 ast_json_ref(obj);
2039 event_info = ast_json_pack("{s: s, s: i, s: o}",
2040 "type", type,
2041 "class_type", class_type,
2042 "event", obj);
2043 if (!event_info) {
2044 return;
2045 }
2046
2047 payload = ast_json_payload_create(event_info);
2048 if (!payload) {
2049 return;
2050 }
2052 if (!message) {
2053 return;
2054 }
2056}
2057
2058/*! \brief Add a custom hook to be called when an event is fired */
2060{
2064}
2065
2066/*! \brief Delete a custom hook to be called when an event is fired */
2068{
2070 AST_RWLIST_REMOVE(&manager_hooks, hook, list);
2072}
2073
2075{
2076 return manager_enabled;
2077}
2078
2080{
2082}
2083
2084/*!
2085 * Grab a reference to the last event, update usecount as needed.
2086 * Can handle a NULL pointer.
2087 */
2088static struct eventqent *grab_last(void)
2089{
2090 struct eventqent *ret;
2091
2094 /* the list is never empty now, but may become so when
2095 * we optimize it in the future, so be prepared.
2096 */
2097 if (ret) {
2099 }
2101 return ret;
2102}
2103
2104/*!
2105 * Purge unused events. Remove elements from the head
2106 * as long as their usecount is 0 and there is a next element.
2107 */
2108static void purge_events(void)
2109{
2110 struct eventqent *ev;
2111 struct timeval now = ast_tvnow();
2112
2114 while ( (ev = AST_RWLIST_FIRST(&all_events)) &&
2115 ev->usecount == 0 && AST_RWLIST_NEXT(ev, eq_next)) {
2117 ast_free(ev);
2118 }
2119
2121 /* Never release the last event */
2122 if (!AST_RWLIST_NEXT(ev, eq_next)) {
2123 break;
2124 }
2125
2126 /* 2.5 times whatever the HTTP timeout is (maximum 2.5 hours) is the maximum time that we will definitely cache an event */
2127 if (ev->usecount == 0 && ast_tvdiff_sec(now, ev->tv) > (httptimeout > 3600 ? 3600 : httptimeout) * 2.5) {
2129 ast_free(ev);
2130 }
2131 }
2134}
2135
2136/*!
2137 * helper functions to convert back and forth between
2138 * string and numeric representation of set of flags
2139 */
2140static const struct permalias {
2141 int num;
2142 const char *label;
2143} perms[] = {
2144 { EVENT_FLAG_SYSTEM, "system" },
2145 { EVENT_FLAG_CALL, "call" },
2146 { EVENT_FLAG_LOG, "log" },
2147 { EVENT_FLAG_VERBOSE, "verbose" },
2148 { EVENT_FLAG_COMMAND, "command" },
2149 { EVENT_FLAG_AGENT, "agent" },
2150 { EVENT_FLAG_USER, "user" },
2151 { EVENT_FLAG_CONFIG, "config" },
2152 { EVENT_FLAG_DTMF, "dtmf" },
2153 { EVENT_FLAG_REPORTING, "reporting" },
2154 { EVENT_FLAG_CDR, "cdr" },
2155 { EVENT_FLAG_DIALPLAN, "dialplan" },
2156 { EVENT_FLAG_ORIGINATE, "originate" },
2157 { EVENT_FLAG_AGI, "agi" },
2158 { EVENT_FLAG_CC, "cc" },
2159 { EVENT_FLAG_AOC, "aoc" },
2160 { EVENT_FLAG_TEST, "test" },
2161 { EVENT_FLAG_SECURITY, "security" },
2162 { EVENT_FLAG_MESSAGE, "message" },
2163 { INT_MAX, "all" },
2164 { 0, "none" },
2166
2167/*! Maximum string length of the AMI authority permission string buildable from perms[]. */
2168#define MAX_AUTH_PERM_STRING 150
2169
2170/*! \brief Checks to see if a string which can be used to evaluate functions should be rejected */
2171static int function_capable_string_allowed_with_auths(const char *evaluating, int writepermlist)
2172{
2173 if (!(writepermlist & EVENT_FLAG_SYSTEM)
2174 && (
2175 strstr(evaluating, "SHELL") || /* NoOp(${SHELL(rm -rf /)}) */
2176 strstr(evaluating, "EVAL") /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
2177 )) {
2178 return 0;
2179 }
2180 return 1;
2181}
2182
2183/*! \brief Convert authority code to a list of options for a user. This will only
2184 * display those authority codes that have an explicit match on authority */
2185static const char *user_authority_to_str(int authority, struct ast_str **res)
2186{
2187 int i;
2188 char *sep = "";
2189
2190 ast_str_reset(*res);
2191 for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
2192 if ((authority & perms[i].num) == perms[i].num) {
2193 ast_str_append(res, 0, "%s%s", sep, perms[i].label);
2194 sep = ",";
2195 }
2196 }
2197
2198 if (ast_str_strlen(*res) == 0) {
2199 /* replace empty string with something sensible */
2200 ast_str_append(res, 0, "<none>");
2201 }
2202
2203 return ast_str_buffer(*res);
2204}
2205
2206
2207/*! \brief Convert authority code to a list of options. Note that the EVENT_FLAG_ALL
2208 * authority will always be returned. */
2209static const char *authority_to_str(int authority, struct ast_str **res)
2210{
2211 int i;
2212 char *sep = "";
2213
2214 ast_str_reset(*res);
2215 if (authority != EVENT_FLAG_SHUTDOWN) {
2216 for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
2217 if (authority & perms[i].num) {
2218 ast_str_append(res, 0, "%s%s", sep, perms[i].label);
2219 sep = ",";
2220 }
2221 }
2222 }
2223
2224 if (ast_str_strlen(*res) == 0) {
2225 /* replace empty string with something sensible */
2226 ast_str_append(res, 0, "<none>");
2227 }
2228
2229 return ast_str_buffer(*res);
2230}
2231
2232/*! Tells you if smallstr exists inside bigstr
2233 which is delim by delim and uses no buf or stringsep
2234 ast_instring("this|that|more","this",'|') == 1;
2235
2236 feel free to move this to app.c -anthm */
2237static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
2238{
2239 const char *val = bigstr, *next;
2240
2241 do {
2242 if ((next = strchr(val, delim))) {
2243 if (!strncmp(val, smallstr, (next - val))) {
2244 return 1;
2245 } else {
2246 continue;
2247 }
2248 } else {
2249 return !strcmp(smallstr, val);
2250 }
2251 } while (*(val = (next + 1)));
2252
2253 return 0;
2254}
2255
2256static int get_perm(const char *instr)
2257{
2258 int x = 0, ret = 0;
2259
2260 if (!instr) {
2261 return 0;
2262 }
2263
2264 for (x = 0; x < ARRAY_LEN(perms); x++) {
2265 if (ast_instring(instr, perms[x].label, ',')) {
2266 ret |= perms[x].num;
2267 }
2268 }
2269
2270 return ret;
2271}
2272
2273/*!
2274 * A number returns itself, false returns 0, true returns all flags,
2275 * other strings return the flags that are set.
2276 */
2277static int strings_to_mask(const char *string)
2278{
2279 const char *p;
2280
2281 if (ast_strlen_zero(string)) {
2282 return -1;
2283 }
2284
2285 for (p = string; *p; p++) {
2286 if (*p < '0' || *p > '9') {
2287 break;
2288 }
2289 }
2290 if (!*p) { /* all digits */
2291 return atoi(string);
2292 }
2293 if (ast_false(string)) {
2294 return 0;
2295 }
2296 if (ast_true(string)) { /* all permissions */
2297 int x, ret = 0;
2298 for (x = 0; x < ARRAY_LEN(perms); x++) {
2299 ret |= perms[x].num;
2300 }
2301 return ret;
2302 }
2303 return get_perm(string);
2304}
2305
2306/*! \brief Unreference manager session object.
2307 If no more references, then go ahead and delete it */
2309{
2310 int refcount = ao2_ref(s, -1);
2311 if (manager_debug) {
2312 ast_debug(1, "Mansession: %p refcount now %d\n", s, refcount - 1);
2313 }
2314 return NULL;
2315}
2316
2317static void event_filter_destructor(void *obj)
2318{
2319 regex_t *regex_filter = obj;
2320 regfree(regex_filter);
2321}
2322
2323static void session_destructor(void *obj)
2324{
2325 struct mansession_session *session = obj;
2326 struct eventqent *eqe = session->last_ev;
2327 struct ast_datastore *datastore;
2328
2329 /* Get rid of each of the data stores on the session */
2330 while ((datastore = AST_LIST_REMOVE_HEAD(&session->datastores, entry))) {
2331 /* Free the data store */
2332 ast_datastore_free(datastore);
2333 }
2334
2335 if (eqe) {
2337 }
2338 if (session->chanvars) {
2339 ast_variables_destroy(session->chanvars);
2340 }
2341
2342 if (session->whitefilters) {
2343 ao2_t_ref(session->whitefilters, -1, "decrement ref for white container, should be last one");
2344 }
2345
2346 if (session->blackfilters) {
2347 ao2_t_ref(session->blackfilters, -1, "decrement ref for black container, should be last one");
2348 }
2349
2350 ast_mutex_destroy(&session->notify_lock);
2351}
2352
2353/*! \brief Allocate manager session structure and add it to the list of sessions */
2355{
2356 struct ao2_container *sessions;
2357 struct mansession_session *newsession;
2358
2359 newsession = ao2_alloc(sizeof(*newsession), session_destructor);
2360 if (!newsession) {
2361 return NULL;
2362 }
2363
2366 if (!newsession->whitefilters || !newsession->blackfilters) {
2367 ao2_ref(newsession, -1);
2368 return NULL;
2369 }
2370
2371 newsession->waiting_thread = AST_PTHREADT_NULL;
2372 newsession->writetimeout = 100;
2373 newsession->send_events = -1;
2374 ast_sockaddr_copy(&newsession->addr, addr);
2375
2376 ast_mutex_init(&newsession->notify_lock);
2377
2378 sessions = ao2_global_obj_ref(mgr_sessions);
2379 if (sessions) {
2380 ao2_link(sessions, newsession);
2381 ao2_ref(sessions, -1);
2382 }
2383
2384 return newsession;
2385}
2386
2387static int mansession_cmp_fn(void *obj, void *arg, int flags)
2388{
2389 struct mansession_session *s = obj;
2390 char *str = arg;
2391 return !strcasecmp(s->username, str) ? CMP_MATCH : 0;
2392}
2393
2395{
2396 struct ao2_container *sessions;
2397
2398 sessions = ao2_global_obj_ref(mgr_sessions);
2399 if (sessions) {
2400 ao2_unlink(sessions, s);
2401 ao2_ref(sessions, -1);
2402 }
2404}
2405
2406
2407static int check_manager_session_inuse(const char *name)
2408{
2409 struct ao2_container *sessions;
2411 int inuse = 0;
2412
2413 sessions = ao2_global_obj_ref(mgr_sessions);
2414 if (sessions) {
2415 session = ao2_find(sessions, (char *) name, 0);
2416 ao2_ref(sessions, -1);
2417 if (session) {
2419 inuse = 1;
2420 }
2421 }
2422 return inuse;
2423}
2424
2425
2426/*!
2427 * lookup an entry in the list of registered users.
2428 * must be called with the list lock held.
2429 */
2431{
2432 struct ast_manager_user *user = NULL;
2433
2434 AST_RWLIST_TRAVERSE(&users, user, list) {
2435 if (!strcasecmp(user->username, name)) {
2436 break;
2437 }
2438 }
2439
2440 return user;
2441}
2442
2443/*! \brief Get displayconnects config option.
2444 * \param session manager session to get parameter from.
2445 * \return displayconnects config option value.
2446 */
2448{
2449 struct ast_manager_user *user = NULL;
2450 int ret = 0;
2451
2453 if ((user = get_manager_by_name_locked(session->username))) {
2454 ret = user->displayconnects;
2455 }
2457
2458 return ret;
2459}
2460
2461#ifdef AST_XML_DOCS
2462static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance);
2463#endif
2464
2465static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2466{
2467 struct manager_action *cur;
2468 struct ast_str *authority;
2469 int num;
2470 int l;
2471 const char *auth_str;
2472#ifdef AST_XML_DOCS
2473 char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64];
2474 char arguments_title[64], privilege_title[64], final_response_title[64], list_responses_title[64];
2475#endif
2476
2477 switch (cmd) {
2478 case CLI_INIT:
2479 e->command = "manager show command";
2480 e->usage =
2481 "Usage: manager show command <actionname> [<actionname> [<actionname> [...]]]\n"
2482 " Shows the detailed description for a specific Asterisk manager interface command.\n";
2483 return NULL;
2484 case CLI_GENERATE:
2485 l = strlen(a->word);
2487 AST_RWLIST_TRAVERSE(&actions, cur, list) {
2488 if (!strncasecmp(a->word, cur->action, l)) {
2490 break;
2491 }
2492 }
2493 }
2495 return NULL;
2496 }
2497 if (a->argc < 4) {
2498 return CLI_SHOWUSAGE;
2499 }
2500
2502
2503#ifdef AST_XML_DOCS
2504 /* setup the titles */
2505 term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2506 term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
2507 term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
2508 term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
2509 term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
2510 term_color(privilege_title, "[Privilege]\n", COLOR_MAGENTA, 0, 40);
2511 term_color(final_response_title, "[Final Response]\n", COLOR_MAGENTA, 0, 40);
2512 term_color(list_responses_title, "[List Responses]\n", COLOR_MAGENTA, 0, 40);
2513#endif
2514
2516 AST_RWLIST_TRAVERSE(&actions, cur, list) {
2517 for (num = 3; num < a->argc; num++) {
2518 if (!strcasecmp(cur->action, a->argv[num])) {
2519 auth_str = authority_to_str(cur->authority, &authority);
2520
2521#ifdef AST_XML_DOCS
2522 if (cur->docsrc == AST_XML_DOC) {
2523 char *syntax = ast_xmldoc_printable(S_OR(cur->syntax, "Not available"), 1);
2524 char *synopsis = ast_xmldoc_printable(S_OR(cur->synopsis, "Not available"), 1);
2525 char *description = ast_xmldoc_printable(S_OR(cur->description, "Not available"), 1);
2526 char *arguments = ast_xmldoc_printable(S_OR(cur->arguments, "Not available"), 1);
2527 char *seealso = ast_xmldoc_printable(S_OR(cur->seealso, "Not available"), 1);
2528 char *privilege = ast_xmldoc_printable(S_OR(auth_str, "Not available"), 1);
2529 char *responses = ast_xmldoc_printable("None", 1);
2530
2531 if (!syntax || !synopsis || !description || !arguments
2532 || !seealso || !privilege || !responses) {
2533 ast_free(syntax);
2535 ast_free(description);
2536 ast_free(arguments);
2537 ast_free(seealso);
2538 ast_free(privilege);
2539 ast_free(responses);
2540 ast_cli(a->fd, "Allocation failure.\n");
2542
2543 return CLI_FAILURE;
2544 }
2545
2546 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",
2547 syntax_title, syntax,
2548 synopsis_title, synopsis,
2549 description_title, description,
2550 arguments_title, arguments,
2551 seealso_title, seealso,
2552 privilege_title, privilege,
2553 list_responses_title);
2554
2555 if (!cur->list_responses) {
2556 ast_cli(a->fd, "%s\n\n", responses);
2557 } else {
2558 struct ast_xml_doc_item *temp;
2559 for (temp = cur->list_responses; temp; temp = AST_LIST_NEXT(temp, next)) {
2560 ast_cli(a->fd, "Event: %s\n", temp->name);
2561 print_event_instance(a, temp);
2562 }
2563 }
2564
2565 ast_cli(a->fd, "%s", final_response_title);
2566
2567 if (!cur->final_response) {
2568 ast_cli(a->fd, "%s\n\n", responses);
2569 } else {
2570 ast_cli(a->fd, "Event: %s\n", cur->final_response->name);
2572 }
2573
2579 ast_free(privilege);
2580 ast_free(responses);
2581 } else
2582#endif
2583 {
2584 ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
2585 cur->action, cur->synopsis,
2586 auth_str,
2587 S_OR(cur->description, ""));
2588 }
2589 }
2590 }
2591 }
2593
2594 return CLI_SUCCESS;
2595}
2596
2597static char *handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2598{
2599 switch (cmd) {
2600 case CLI_INIT:
2601 e->command = "manager set debug [on|off]";
2602 e->usage = "Usage: manager set debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
2603 return NULL;
2604 case CLI_GENERATE:
2605 return NULL;
2606 }
2607
2608 if (a->argc == 3) {
2609 ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
2610 } else if (a->argc == 4) {
2611 if (!strcasecmp(a->argv[3], "on")) {
2612 manager_debug = 1;
2613 } else if (!strcasecmp(a->argv[3], "off")) {
2614 manager_debug = 0;
2615 } else {
2616 return CLI_SHOWUSAGE;
2617 }
2618 }
2619 return CLI_SUCCESS;
2620}
2621
2622static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2623{
2624 struct ast_manager_user *user = NULL;
2625 int l;
2626 struct ast_str *rauthority = ast_str_alloca(MAX_AUTH_PERM_STRING);
2627 struct ast_str *wauthority = ast_str_alloca(MAX_AUTH_PERM_STRING);
2628 struct ast_variable *v;
2629
2630 switch (cmd) {
2631 case CLI_INIT:
2632 e->command = "manager show user";
2633 e->usage =
2634 " Usage: manager show user <user>\n"
2635 " Display all information related to the manager user specified.\n";
2636 return NULL;
2637 case CLI_GENERATE:
2638 l = strlen(a->word);
2639 if (a->pos != 3) {
2640 return NULL;
2641 }
2643 AST_RWLIST_TRAVERSE(&users, user, list) {
2644 if (!strncasecmp(a->word, user->username, l)) {
2645 if (ast_cli_completion_add(ast_strdup(user->username))) {
2646 break;
2647 }
2648 }
2649 }
2651 return NULL;
2652 }
2653
2654 if (a->argc != 4) {
2655 return CLI_SHOWUSAGE;
2656 }
2657
2659
2660 if (!(user = get_manager_by_name_locked(a->argv[3]))) {
2661 ast_cli(a->fd, "There is no manager called %s\n", a->argv[3]);
2663 return CLI_SUCCESS;
2664 }
2665
2666 ast_cli(a->fd, "\n");
2667 ast_cli(a->fd,
2668 " username: %s\n"
2669 " secret: %s\n"
2670 " ACL: %s\n"
2671 " read perm: %s\n"
2672 " write perm: %s\n"
2673 " displayconnects: %s\n"
2674 "allowmultiplelogin: %s\n",
2675 S_OR(user->username, "(N/A)"),
2676 (user->secret ? "<Set>" : "(N/A)"),
2677 ((user->acl && !ast_acl_list_is_empty(user->acl)) ? "yes" : "no"),
2678 user_authority_to_str(user->readperm, &rauthority),
2679 user_authority_to_str(user->writeperm, &wauthority),
2680 (user->displayconnects ? "yes" : "no"),
2681 (user->allowmultiplelogin ? "yes" : "no"));
2682 ast_cli(a->fd, " Variables: \n");
2683 for (v = user->chanvars ; v ; v = v->next) {
2684 ast_cli(a->fd, " %s = %s\n", v->name, v->value);
2685 }
2686 if (!ast_acl_list_is_empty(user->acl)) {
2687 ast_acl_output(a->fd, user->acl, NULL);
2688 }
2689
2691
2692 return CLI_SUCCESS;
2693}
2694
2695static char *handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2696{
2697 struct ast_manager_user *user = NULL;
2698 int count_amu = 0;
2699 switch (cmd) {
2700 case CLI_INIT:
2701 e->command = "manager show users";
2702 e->usage =
2703 "Usage: manager show users\n"
2704 " Prints a listing of all managers that are currently configured on that\n"
2705 " system.\n";
2706 return NULL;
2707 case CLI_GENERATE:
2708 return NULL;
2709 }
2710 if (a->argc != 3) {
2711 return CLI_SHOWUSAGE;
2712 }
2713
2715
2716 /* If there are no users, print out something along those lines */
2717 if (AST_RWLIST_EMPTY(&users)) {
2718 ast_cli(a->fd, "There are no manager users.\n");
2720 return CLI_SUCCESS;
2721 }
2722
2723 ast_cli(a->fd, "\nusername\n--------\n");
2724
2725 AST_RWLIST_TRAVERSE(&users, user, list) {
2726 ast_cli(a->fd, "%s\n", user->username);
2727 count_amu++;
2728 }
2729
2731
2732 ast_cli(a->fd,"-------------------\n"
2733 "%d manager users configured.\n", count_amu);
2734 return CLI_SUCCESS;
2735}
2736
2737/*! \brief CLI command manager list commands */
2738static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2739{
2740 struct manager_action *cur;
2741 int name_len = 1;
2742 int space_remaining;
2743#define HSMC_FORMAT " %-*.*s %-.*s\n"
2744 switch (cmd) {
2745 case CLI_INIT:
2746 e->command = "manager show commands";
2747 e->usage =
2748 "Usage: manager show commands\n"
2749 " Prints a listing of all the available Asterisk manager interface commands.\n";
2750 return NULL;
2751 case CLI_GENERATE:
2752 return NULL;
2753 }
2754
2756 AST_RWLIST_TRAVERSE(&actions, cur, list) {
2757 int incoming_len = strlen(cur->action);
2758 if (incoming_len > name_len) {
2759 name_len = incoming_len;
2760 }
2761 }
2762
2763 space_remaining = MGR_SHOW_TERMINAL_WIDTH - name_len - 4;
2764 if (space_remaining < 0) {
2765 space_remaining = 0;
2766 }
2767
2768 ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, "Action", space_remaining, "Synopsis");
2769 ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, "------", space_remaining, "--------");
2770
2771 AST_RWLIST_TRAVERSE(&actions, cur, list) {
2772 ast_cli(a->fd, HSMC_FORMAT, name_len, name_len, cur->action, space_remaining, cur->synopsis);
2773 }
2775
2776 return CLI_SUCCESS;
2777}
2778
2779/*! \brief CLI command manager kick session */
2780static char *handle_kickmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2781{
2782 struct ao2_container *sessions;
2784 struct ao2_iterator i;
2785 int fd = -1;
2786 int found = 0;
2787
2788 switch (cmd) {
2789 case CLI_INIT:
2790 e->command = "manager kick session";
2791 e->usage =
2792 "Usage: manager kick session <file descriptor>\n"
2793 " Kick an active Asterisk Manager Interface session\n";
2794 return NULL;
2795 case CLI_GENERATE:
2796 return NULL;
2797 }
2798
2799 if (a->argc != 4) {
2800 return CLI_SHOWUSAGE;
2801 }
2802
2803 fd = atoi(a->argv[3]);
2804 if (fd <= 0) { /* STDOUT won't be a valid AMI fd either */
2805 ast_cli(a->fd, "Invalid AMI file descriptor: %s\n", a->argv[3]);
2806 return CLI_FAILURE;
2807 }
2808
2809 sessions = ao2_global_obj_ref(mgr_sessions);
2810 if (sessions) {
2812 ao2_ref(sessions, -1);
2813 while ((session = ao2_iterator_next(&i))) {
2815 if (session->stream) {
2816 if (ast_iostream_get_fd(session->stream) == fd) {
2817 if (session->kicked) {
2818 ast_cli(a->fd, "Manager session using file descriptor %d has already been kicked\n", fd);
2821 break;
2822 }
2823 fd = ast_iostream_get_fd(session->stream);
2824 found = fd;
2825 ast_cli(a->fd, "Kicking manager session connected using file descriptor %d\n", fd);
2826 ast_mutex_lock(&session->notify_lock);
2827 session->kicked = 1;
2828 if (session->waiting_thread != AST_PTHREADT_NULL) {
2829 pthread_kill(session->waiting_thread, SIGURG);
2830 }
2831 ast_mutex_unlock(&session->notify_lock);
2834 break;
2835 }
2836 }
2839 }
2841 }
2842
2843 if (!found) {
2844 ast_cli(a->fd, "No manager session found using file descriptor %d\n", fd);
2845 }
2846 return CLI_SUCCESS;
2847}
2848
2849/*! \brief CLI command manager list connected */
2850static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2851{
2852 struct ao2_container *sessions;
2854 time_t now = time(NULL);
2855#define HSMCONN_FORMAT1 " %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-10.10s %-10.10s\n"
2856#define HSMCONN_FORMAT2 " %-15.15s %-55.55s %-10d %-10d %-8d %-8d %-10.10d %-10.10d\n"
2857 int count = 0;
2858 struct ao2_iterator i;
2859
2860 switch (cmd) {
2861 case CLI_INIT:
2862 e->command = "manager show connected";
2863 e->usage =
2864 "Usage: manager show connected\n"
2865 " Prints a listing of the users that are currently connected to the\n"
2866 "Asterisk manager interface.\n";
2867 return NULL;
2868 case CLI_GENERATE:
2869 return NULL;
2870 }
2871
2872 ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "ReadPerms", "WritePerms");
2873
2874 sessions = ao2_global_obj_ref(mgr_sessions);
2875 if (sessions) {
2877 ao2_ref(sessions, -1);
2878 while ((session = ao2_iterator_next(&i))) {
2880 ast_cli(a->fd, HSMCONN_FORMAT2, session->username,
2882 (int) (session->sessionstart),
2883 (int) (now - session->sessionstart),
2884 session->stream ? ast_iostream_get_fd(session->stream) : -1,
2885 session->inuse,
2886 session->readperm,
2887 session->writeperm);
2888 count++;
2891 }
2893 }
2894 ast_cli(a->fd, "%d users connected.\n", count);
2895
2896 return CLI_SUCCESS;
2897}
2898
2899/*! \brief CLI command manager list eventq */
2900/* Should change to "manager show connected" */
2901static char *handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2902{
2903 struct eventqent *s;
2904 switch (cmd) {
2905 case CLI_INIT:
2906 e->command = "manager show eventq";
2907 e->usage =
2908 "Usage: manager show eventq\n"
2909 " Prints a listing of all events pending in the Asterisk manger\n"
2910 "event queue.\n";
2911 return NULL;
2912 case CLI_GENERATE:
2913 return NULL;
2914 }
2916 AST_RWLIST_TRAVERSE(&all_events, s, eq_next) {
2917 ast_cli(a->fd, "Usecount: %d\n", s->usecount);
2918 ast_cli(a->fd, "Category: %d\n", s->category);
2919 ast_cli(a->fd, "Event:\n%s", s->eventdata);
2920 }
2922
2923 return CLI_SUCCESS;
2924}
2925
2926static int reload_module(void);
2927
2928/*! \brief CLI command manager reload */
2929static char *handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2930{
2931 switch (cmd) {
2932 case CLI_INIT:
2933 e->command = "manager reload";
2934 e->usage =
2935 "Usage: manager reload\n"
2936 " Reloads the manager configuration.\n";
2937 return NULL;
2938 case CLI_GENERATE:
2939 return NULL;
2940 }
2941 if (a->argc > 2) {
2942 return CLI_SHOWUSAGE;
2943 }
2944 reload_module();
2945 return CLI_SUCCESS;
2946}
2947
2948static struct eventqent *advance_event(struct eventqent *e)
2949{
2950 struct eventqent *next;
2951
2953 if ((next = AST_RWLIST_NEXT(e, eq_next))) {
2956 }
2958 return next;
2959}
2960
2961#define GET_HEADER_FIRST_MATCH 0
2962#define GET_HEADER_LAST_MATCH 1
2963#define GET_HEADER_SKIP_EMPTY 2
2964
2965/*!
2966 * \brief Return a matching header value.
2967 *
2968 * \details
2969 * Generic function to return either the first or the last
2970 * matching header from a list of variables, possibly skipping
2971 * empty strings.
2972 *
2973 * \note At the moment there is only one use of this function in
2974 * this file, so we make it static.
2975 *
2976 * \note Never returns NULL.
2977 */
2978static const char *__astman_get_header(const struct message *m, char *var, int mode)
2979{
2980 int x, l = strlen(var);
2981 const char *result = "";
2982
2983 if (!m) {
2984 return result;
2985 }
2986
2987 for (x = 0; x < m->hdrcount; x++) {
2988 const char *h = m->headers[x];
2989 if (!strncasecmp(var, h, l) && h[l] == ':') {
2990 const char *value = h + l + 1;
2991 value = ast_skip_blanks(value); /* ignore leading spaces in the value */
2992 /* found a potential candidate */
2993 if ((mode & GET_HEADER_SKIP_EMPTY) && ast_strlen_zero(value)) {
2994 continue; /* not interesting */
2995 }
2996 if (mode & GET_HEADER_LAST_MATCH) {
2997 result = value; /* record the last match so far */
2998 } else {
2999 return value;
3000 }
3001 }
3002 }
3003
3004 return result;
3005}
3006
3007/*!
3008 * \brief Return the first matching variable from an array.
3009 *
3010 * \note This is the legacy function and is implemented in
3011 * therms of __astman_get_header().
3012 *
3013 * \note Never returns NULL.
3014 */
3015const char *astman_get_header(const struct message *m, char *var)
3016{
3018}
3019
3020/*!
3021 * \brief Append additional headers into the message structure from params.
3022 *
3023 * \note You likely want to initialize m->hdrcount to 0 before calling this.
3024 */
3025static void astman_append_headers(struct message *m, const struct ast_variable *params)
3026{
3027 const struct ast_variable *v;
3028
3029 for (v = params; v && m->hdrcount < ARRAY_LEN(m->headers); v = v->next) {
3030 if (ast_asprintf((char**)&m->headers[m->hdrcount], "%s: %s", v->name, v->value) > -1) {
3031 ++m->hdrcount;
3032 }
3033 }
3034}
3035
3036/*!
3037 * \brief Free headers inside message structure, but not the message structure itself.
3038 */
3039static void astman_free_headers(struct message *m)
3040{
3041 while (m->hdrcount) {
3042 --m->hdrcount;
3043 ast_free((void *) m->headers[m->hdrcount]);
3044 m->headers[m->hdrcount] = NULL;
3045 }
3046}
3047
3048/*!
3049 * \internal
3050 * \brief Process one "Variable:" header value string.
3051 *
3052 * \param head Current list of AMI variables to get new values added.
3053 * \param hdr_val Header value string to process.
3054 *
3055 * \return New variable list head.
3056 */
3057static struct ast_variable *man_do_variable_value(struct ast_variable *head, const char *hdr_val)
3058{
3059 char *parse;
3061 AST_APP_ARG(vars)[64];
3062 );
3063
3064 hdr_val = ast_skip_blanks(hdr_val); /* ignore leading spaces in the value */
3065 parse = ast_strdupa(hdr_val);
3066
3067 /* Break the header value string into name=val pair items. */
3069 if (args.argc) {
3070 int y;
3071
3072 /* Process each name=val pair item. */
3073 for (y = 0; y < args.argc; y++) {
3074 struct ast_variable *cur;
3075 char *var;
3076 char *val;
3077
3078 if (!args.vars[y]) {
3079 continue;
3080 }
3081 var = val = args.vars[y];
3082 strsep(&val, "=");
3083
3084 /* XXX We may wish to trim whitespace from the strings. */
3085 if (!val || ast_strlen_zero(var)) {
3086 continue;
3087 }
3088
3089 /* Create new variable list node and prepend it to the list. */
3090 cur = ast_variable_new(var, val, "");
3091 if (cur) {
3092 cur->next = head;
3093 head = cur;
3094 }
3095 }
3096 }
3097
3098 return head;
3099}
3100
3102{
3104}
3105
3108{
3109 int varlen;
3110 int x;
3111 struct ast_variable *head = NULL;
3112
3113 static const char var_hdr[] = "Variable:";
3114
3115 /* Process all "Variable:" headers. */
3116 varlen = strlen(var_hdr);
3117 for (x = 0; x < m->hdrcount; x++) {
3118 if (strncasecmp(var_hdr, m->headers[x], varlen)) {
3119 continue;
3120 }
3121 head = man_do_variable_value(head, m->headers[x] + varlen);
3122 }
3123
3124 if (order == ORDER_NATURAL) {
3125 head = ast_variables_reverse(head);
3126 }
3127
3128 return head;
3129}
3130
3131/*! \brief access for hooks to send action messages to ami */
3132int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
3133{
3134 const char *action;
3135 int ret = 0;
3136 struct manager_action *act_found;
3137 struct mansession s = {.session = NULL, };
3138 struct message m = { 0 };
3139 char *dup_str;
3140 char *src;
3141 int x = 0;
3142 int curlen;
3143
3144 if (hook == NULL) {
3145 return -1;
3146 }
3147
3148 /* Create our own copy of the AMI action msg string. */
3149 src = dup_str = ast_strdup(msg);
3150 if (!dup_str) {
3151 return -1;
3152 }
3153
3154 /* convert msg string to message struct */
3155 curlen = strlen(src);
3156 for (x = 0; x < curlen; x++) {
3157 int cr; /* set if we have \r */
3158 if (src[x] == '\r' && x+1 < curlen && src[x+1] == '\n')
3159 cr = 2; /* Found. Update length to include \r\n */
3160 else if (src[x] == '\n')
3161 cr = 1; /* also accept \n only */
3162 else
3163 continue;
3164 /* don't keep empty lines */
3165 if (x && m.hdrcount < ARRAY_LEN(m.headers)) {
3166 /* ... but trim \r\n and terminate the header string */
3167 src[x] = '\0';
3168 m.headers[m.hdrcount++] = src;
3169 }
3170 x += cr;
3171 curlen -= x; /* remaining size */
3172 src += x; /* update pointer */
3173 x = -1; /* reset loop */
3174 }
3175
3176 action = astman_get_header(&m, "Action");
3177
3178 do {
3179 if (!strcasecmp(action, "login")) {
3180 break;
3181 }
3182
3183 act_found = action_find(action);
3184 if (!act_found) {
3185 break;
3186 }
3187
3188 /*
3189 * we have to simulate a session for this action request
3190 * to be able to pass it down for processing
3191 * This is necessary to meet the previous design of manager.c
3192 */
3193 s.hook = hook;
3194
3195 ret = -1;
3196 ao2_lock(act_found);
3197 if (act_found->registered && act_found->func) {
3198 struct ast_module *mod_ref = ast_module_running_ref(act_found->module);
3199
3200 ao2_unlock(act_found);
3201 /* If the action is in a module it must be running. */
3202 if (!act_found->module || mod_ref) {
3203 ret = act_found->func(&s, &m);
3204 ast_module_unref(mod_ref);
3205 }
3206 } else {
3207 ao2_unlock(act_found);
3208 }
3209 ao2_t_ref(act_found, -1, "done with found action object");
3210 } while (0);
3211
3212 ast_free(dup_str);
3213 return ret;
3214}
3215
3216/*!
3217 * helper function to send a string to the socket.
3218 * Return -1 on error (e.g. buffer full).
3219 */
3220static int send_string(struct mansession *s, char *string)
3221{
3222 struct ast_iostream *stream;
3223 int len, res;
3224
3225 /* It's a result from one of the hook's action invocation */
3226 if (s->hook) {
3227 /*
3228 * to send responses, we're using the same function
3229 * as for receiving events. We call the event "HookResponse"
3230 */
3231 s->hook->helper(EVENT_FLAG_HOOKRESPONSE, "HookResponse", string);
3232 return 0;
3233 }
3234
3235 stream = s->stream ? s->stream : s->session->stream;
3236
3237 len = strlen(string);
3239 res = ast_iostream_write(stream, string, len);
3241
3242 if (res < len) {
3243 s->write_error = 1;
3244 }
3245
3246 return res;
3247}
3248
3249/*!
3250 * \brief thread local buffer for astman_append
3251 *
3252 * \note This can not be defined within the astman_append() function
3253 * because it declares a couple of functions that get used to
3254 * initialize the thread local storage key.
3255 */
3257
3259
3260/*! \brief initial allocated size for the astman_append_buf and astman_send_*_va */
3261#define ASTMAN_APPEND_BUF_INITSIZE 256
3262
3263static void astman_flush(struct mansession *s, struct ast_str *buf)
3264{
3265 if (s->hook || (s->tcptls_session && s->tcptls_session->stream)) {
3267 } else {
3268 ast_verbose("No connection stream in astman_append, should not happen\n");
3269 }
3270}
3271
3272/*!
3273 * utility functions for creating AMI replies
3274 */
3275void astman_append(struct mansession *s, const char *fmt, ...)
3276{
3277 int res;
3278 va_list ap;
3279 struct ast_str *buf;
3280
3282 return;
3283 }
3284
3285 va_start(ap, fmt);
3286 res = ast_str_set_va(&buf, 0, fmt, ap);
3287 va_end(ap);
3288 if (res == AST_DYNSTR_BUILD_FAILED) {
3289 return;
3290 }
3291
3292 if (s->hook || (s->tcptls_session != NULL && s->tcptls_session->stream != NULL)) {
3294 } else {
3295 ast_verbose("No connection stream in astman_append, should not happen\n");
3296 }
3297}
3298
3299/*! \note NOTE: XXX this comment is unclear and possibly wrong.
3300 Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
3301 hold the session lock _or_ be running in an action callback (in which case s->session->busy will
3302 be non-zero). In either of these cases, there is no need to lock-protect the session's
3303 fd, since no other output will be sent (events will be queued), and no input will
3304 be read until either the current action finishes or get_input() obtains the session
3305 lock.
3306 */
3307
3308/*! \todo XXX MSG_MOREDATA should go to a header file. */
3309#define MSG_MOREDATA ((char *)astman_send_response)
3310
3311/*! \brief send a response with an optional message,
3312 * and terminate it with an empty line.
3313 * m is used only to grab the 'ActionID' field.
3314 *
3315 * Use the explicit constant MSG_MOREDATA to remove the empty line.
3316 * XXX MSG_MOREDATA should go to a header file.
3317 */
3318static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
3319{
3320 const char *id = astman_get_header(m, "ActionID");
3321 struct ast_str *buf;
3322
3324 if (!buf) {
3325 return;
3326 }
3327
3328 ast_str_set(&buf, 0, "Response: %s\r\n", resp);
3329
3330 if (!ast_strlen_zero(id)) {
3331 ast_str_append(&buf, 0, "ActionID: %s\r\n", id);
3332 }
3333
3334 if (listflag) {
3335 /* Start, complete, cancelled */
3336 ast_str_append(&buf, 0, "EventList: %s\r\n", listflag);
3337 }
3338
3339 if (msg != MSG_MOREDATA) {
3340 if (msg) {
3341 ast_str_append(&buf, 0, "Message: %s\r\n", msg);
3342 }
3343 ast_str_append(&buf, 0, "\r\n");
3344 }
3345
3346 astman_flush(s, buf);
3347}
3348
3349void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
3350{
3351 astman_send_response_full(s, m, resp, msg, NULL);
3352}
3353
3354void astman_send_error(struct mansession *s, const struct message *m, char *error)
3355{
3356 astman_send_response_full(s, m, "Error", error, NULL);
3357}
3358
3359void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt, ...)
3360{
3361 int res;
3362 va_list ap;
3363 struct ast_str *buf;
3364 char *msg;
3365
3367 return;
3368 }
3369
3370 va_start(ap, fmt);
3371 res = ast_str_set_va(&buf, 0, fmt, ap);
3372 va_end(ap);
3373 if (res == AST_DYNSTR_BUILD_FAILED) {
3374 return;
3375 }
3376
3377 /* astman_append will use the same underlying buffer, so copy the message out
3378 * before sending the response */
3379 msg = ast_str_buffer(buf);
3380 if (msg) {
3381 msg = ast_strdupa(msg);
3382 }
3383 astman_send_response_full(s, m, "Error", msg, NULL);
3384}
3385
3386void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
3387{
3388 astman_send_response_full(s, m, "Success", msg, NULL);
3389}
3390
3391static void astman_start_ack(struct mansession *s, const struct message *m)
3392{
3393 astman_send_response_full(s, m, "Success", MSG_MOREDATA, NULL);
3394}
3395
3396void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
3397{
3398 astman_send_response_full(s, m, "Success", msg, listflag);
3399}
3400
3401static struct ast_str *astman_send_list_complete_start_common(struct mansession *s, const struct message *m, const char *event_name, int count)
3402{
3403 const char *id = astman_get_header(m, "ActionID");
3404 struct ast_str *buf;
3405
3407 if (!buf) {
3408 return NULL;
3409 }
3410
3411 ast_str_set(&buf, 0, "Event: %s\r\n", event_name);
3412 if (!ast_strlen_zero(id)) {
3413 ast_str_append(&buf, 0, "ActionID: %s\r\n", id);
3414 }
3415 ast_str_append(&buf, 0,
3416 "EventList: Complete\r\n"
3417 "ListItems: %d\r\n",
3418 count);
3419
3420 return buf;
3421}
3422
3423static void astman_send_list_complete(struct mansession *s, const struct message *m, const char *event_name, int count)
3424{
3425 struct ast_str *buf = astman_send_list_complete_start_common(s, m, event_name, count);
3426 if (buf) {
3427 ast_str_append(&buf, 0, "\r\n");
3428 astman_flush(s, buf);
3429 }
3430}
3431
3432void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
3433{
3434 struct ast_str *buf = astman_send_list_complete_start_common(s, m, event_name, count);
3435 if (buf) {
3436 astman_flush(s, buf);
3437 }
3438}
3439
3441{
3442 astman_append(s, "\r\n");
3443}
3444
3445/*! \brief Lock the 'mansession' structure. */
3446static void mansession_lock(struct mansession *s)
3447{
3448 ast_mutex_lock(&s->lock);
3449}
3450
3451/*! \brief Unlock the 'mansession' structure. */
3452static void mansession_unlock(struct mansession *s)
3453{
3455}
3456
3457/*! \brief
3458 Rather than braindead on,off this now can also accept a specific int mask value
3459 or a ',' delim list of mask strings (the same as manager.conf) -anthm
3460*/
3461static int set_eventmask(struct mansession *s, const char *eventmask)
3462{
3463 int maskint = strings_to_mask(eventmask);
3464
3465 ao2_lock(s->session);
3466 if (maskint >= 0) {
3467 s->session->send_events = maskint;
3468 }
3469 ao2_unlock(s->session);
3470
3471 return maskint;
3472}
3473
3475{
3478}
3479
3480static void report_invalid_user(const struct mansession *s, const char *username)
3481{
3482 char session_id[32];
3483 struct ast_security_event_inval_acct_id inval_acct_id = {
3486 .common.service = "AMI",
3487 .common.account_id = username,
3488 .common.session_tv = &s->session->sessionstart_tv,
3489 .common.local_addr = {
3490 .addr = &s->tcptls_session->parent->local_address,
3491 .transport = mansession_get_transport(s),
3492 },
3493 .common.remote_addr = {
3494 .addr = &s->session->addr,
3495 .transport = mansession_get_transport(s),
3496 },
3497 .common.session_id = session_id,
3498 };
3499
3500 snprintf(session_id, sizeof(session_id), "%p", s);
3501
3502 ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
3503}
3504
3505static void report_failed_acl(const struct mansession *s, const char *username)
3506{
3507 char session_id[32];
3508 struct ast_security_event_failed_acl failed_acl_event = {
3510 .common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
3511 .common.service = "AMI",
3512 .common.account_id = username,
3513 .common.session_tv = &s->session->sessionstart_tv,
3514 .common.local_addr = {
3515 .addr = &s->tcptls_session->parent->local_address,
3516 .transport = mansession_get_transport(s),
3517 },
3518 .common.remote_addr = {
3519 .addr = &s->session->addr,
3520 .transport = mansession_get_transport(s),
3521 },
3522 .common.session_id = session_id,
3523 };
3524
3525 snprintf(session_id, sizeof(session_id), "%p", s->session);
3526
3527 ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
3528}
3529
3530static void report_inval_password(const struct mansession *s, const char *username)
3531{
3532 char session_id[32];
3533 struct ast_security_event_inval_password inval_password = {
3536 .common.service = "AMI",
3537 .common.account_id = username,
3538 .common.session_tv = &s->session->sessionstart_tv,
3539 .common.local_addr = {
3540 .addr = &s->tcptls_session->parent->local_address,
3541 .transport = mansession_get_transport(s),
3542 },
3543 .common.remote_addr = {
3544 .addr = &s->session->addr,
3545 .transport = mansession_get_transport(s),
3546 },
3547 .common.session_id = session_id,
3548 };
3549
3550 snprintf(session_id, sizeof(session_id), "%p", s->session);
3551
3552 ast_security_event_report(AST_SEC_EVT(&inval_password));
3553}
3554
3555static void report_auth_success(const struct mansession *s)
3556{
3557 char session_id[32];
3558 struct ast_security_event_successful_auth successful_auth = {
3561 .common.service = "AMI",
3562 .common.account_id = s->session->username,
3563 .common.session_tv = &s->session->sessionstart_tv,
3564 .common.local_addr = {
3565 .addr = &s->tcptls_session->parent->local_address,
3566 .transport = mansession_get_transport(s),
3567 },
3568 .common.remote_addr = {
3569 .addr = &s->session->addr,
3570 .transport = mansession_get_transport(s),
3571 },
3572 .common.session_id = session_id,
3573 };
3574
3575 snprintf(session_id, sizeof(session_id), "%p", s->session);
3576
3577 ast_security_event_report(AST_SEC_EVT(&successful_auth));
3578}
3579
3580static void report_req_not_allowed(const struct mansession *s, const char *action)
3581{
3582 char session_id[32];
3583 char request_type[64];
3584 struct ast_security_event_req_not_allowed req_not_allowed = {
3587 .common.service = "AMI",
3588 .common.account_id = s->session->username,
3589 .common.session_tv = &s->session->sessionstart_tv,
3590 .common.local_addr = {
3591 .addr = &s->tcptls_session->parent->local_address,
3592 .transport = mansession_get_transport(s),
3593 },
3594 .common.remote_addr = {
3595 .addr = &s->session->addr,
3596 .transport = mansession_get_transport(s),
3597 },
3598 .common.session_id = session_id,
3599
3600 .request_type = request_type,
3601 };
3602
3603 snprintf(session_id, sizeof(session_id), "%p", s->session);
3604 snprintf(request_type, sizeof(request_type), "Action: %s", action);
3605
3606 ast_security_event_report(AST_SEC_EVT(&req_not_allowed));
3607}
3608
3609static void report_req_bad_format(const struct mansession *s, const char *action)
3610{
3611 char session_id[32];
3612 char request_type[64];
3613 struct ast_security_event_req_bad_format req_bad_format = {
3616 .common.service = "AMI",
3617 .common.account_id = s->session->username,
3618 .common.session_tv = &s->session->sessionstart_tv,
3619 .common.local_addr = {
3620 .addr = &s->tcptls_session->parent->local_address,
3621 .transport = mansession_get_transport(s),
3622 },
3623 .common.remote_addr = {
3624 .addr = &s->session->addr,
3625 .transport = mansession_get_transport(s),
3626 },
3627 .common.session_id = session_id,
3628
3629 .request_type = request_type,
3630 };
3631
3632 snprintf(session_id, sizeof(session_id), "%p", s->session);
3633 snprintf(request_type, sizeof(request_type), "Action: %s", action);
3634
3635 ast_security_event_report(AST_SEC_EVT(&req_bad_format));
3636}
3637
3639 const char *response, const char *expected_response)
3640{
3641 char session_id[32];
3642 struct ast_security_event_chal_resp_failed chal_resp_failed = {
3645 .common.service = "AMI",
3646 .common.account_id = s->session->username,
3647 .common.session_tv = &s->session->sessionstart_tv,
3648 .common.local_addr = {
3649 .addr = &s->tcptls_session->parent->local_address,
3650 .transport = mansession_get_transport(s),
3651 },
3652 .common.remote_addr = {
3653 .addr = &s->session->addr,
3654 .transport = mansession_get_transport(s),
3655 },
3656 .common.session_id = session_id,
3657
3658 .challenge = s->session->challenge,
3659 .response = response,
3660 .expected_response = expected_response,
3661 };
3662
3663 snprintf(session_id, sizeof(session_id), "%p", s->session);
3664
3665 ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
3666}
3667
3668static void report_session_limit(const struct mansession *s)
3669{
3670 char session_id[32];
3672 .common.event_type = AST_SECURITY_EVENT_SESSION_LIMIT,
3674 .common.service = "AMI",
3675 .common.account_id = s->session->username,
3676 .common.session_tv = &s->session->sessionstart_tv,
3677 .common.local_addr = {
3678 .addr = &s->tcptls_session->parent->local_address,
3679 .transport = mansession_get_transport(s),
3680 },
3681 .common.remote_addr = {
3682 .addr = &s->session->addr,
3683 .transport = mansession_get_transport(s),
3684 },
3685 .common.session_id = session_id,
3686 };
3687
3688 snprintf(session_id, sizeof(session_id), "%p", s->session);
3689
3691}
3692
3693/*
3694 * Here we start with action_ handlers for AMI actions,
3695 * and the internal functions used by them.
3696 * Generally, the handlers are called action_foo()
3697 */
3698
3699/* helper function for action_login() */
3700static int authenticate(struct mansession *s, const struct message *m)
3701{
3702 const char *username = astman_get_header(m, "Username");
3703 const char *password = astman_get_header(m, "Secret");
3704 int error = -1;
3705 struct ast_manager_user *user = NULL;
3706 regex_t *regex_filter;
3707 struct ao2_iterator filter_iter;
3708
3709 if (ast_strlen_zero(username)) { /* missing username */
3710 return -1;
3711 }
3712
3713 /* locate user in locked state */
3715
3716 if (!(user = get_manager_by_name_locked(username))) {
3717 report_invalid_user(s, username);
3718 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3719 } else if (user->acl && (ast_apply_acl(user->acl, &s->session->addr, "Manager User ACL: ") == AST_SENSE_DENY)) {
3720 report_failed_acl(s, username);
3721 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3722 } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
3723 const char *key = astman_get_header(m, "Key");
3724 if (!ast_strlen_zero(key) && !ast_strlen_zero(s->session->challenge) && user->secret) {
3725 int x;
3726 int len = 0;
3727 char md5key[256] = "";
3728 struct MD5Context md5;
3729 unsigned char digest[16];
3730
3731 MD5Init(&md5);
3732 MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
3733 MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
3734 MD5Final(digest, &md5);
3735 for (x = 0; x < 16; x++)
3736 len += sprintf(md5key + len, "%02hhx", digest[x]);
3737 if (!strcmp(md5key, key)) {
3738 error = 0;
3739 } else {
3740 report_failed_challenge_response(s, key, md5key);
3741 }
3742 } else {
3743 ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
3744 S_OR(s->session->challenge, ""));
3745 }
3746 } else if (user->secret) {
3747 if (!strcmp(password, user->secret)) {
3748 error = 0;
3749 } else {
3750 report_inval_password(s, username);
3751 }
3752 }
3753
3754 if (error) {
3755 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3757 return -1;
3758 }
3759
3760 /* auth complete */
3761
3762 /* All of the user parameters are copied to the session so that in the event
3763 * of a reload and a configuration change, the session parameters are not
3764 * changed. */
3765 ast_copy_string(s->session->username, username, sizeof(s->session->username));
3766 s->session->readperm = user->readperm;
3767 s->session->writeperm = user->writeperm;
3768 s->session->writetimeout = user->writetimeout;
3769 if (user->chanvars) {
3770 s->session->chanvars = ast_variables_dup(user->chanvars);
3771 }
3772
3773 filter_iter = ao2_iterator_init(user->whitefilters, 0);
3774 while ((regex_filter = ao2_iterator_next(&filter_iter))) {
3775 ao2_t_link(s->session->whitefilters, regex_filter, "add white user filter to session");
3776 ao2_t_ref(regex_filter, -1, "remove iterator ref");
3777 }
3778 ao2_iterator_destroy(&filter_iter);
3779
3780 filter_iter = ao2_iterator_init(user->blackfilters, 0);
3781 while ((regex_filter = ao2_iterator_next(&filter_iter))) {
3782 ao2_t_link(s->session->blackfilters, regex_filter, "add black user filter to session");
3783 ao2_t_ref(regex_filter, -1, "remove iterator ref");
3784 }
3785 ao2_iterator_destroy(&filter_iter);
3786
3787 s->session->sessionstart = time(NULL);
3789 set_eventmask(s, astman_get_header(m, "Events"));
3790
3792
3794 return 0;
3795}
3796
3797static int action_ping(struct mansession *s, const struct message *m)
3798{
3799 const char *actionid = astman_get_header(m, "ActionID");
3800 struct timeval now = ast_tvnow();
3801
3802 astman_append(s, "Response: Success\r\n");
3803 if (!ast_strlen_zero(actionid)){
3804 astman_append(s, "ActionID: %s\r\n", actionid);
3805 }
3807 s,
3808 "Ping: Pong\r\n"
3809 "Timestamp: %ld.%06lu\r\n"
3810 "\r\n",
3811 (long) now.tv_sec, (unsigned long) now.tv_usec);
3812 return 0;
3813}
3814
3815void astman_live_dangerously(int new_live_dangerously)
3816{
3817 if (new_live_dangerously && !live_dangerously)
3818 {
3819 ast_log(LOG_WARNING, "Manager Configuration load protection disabled.\n");
3820 }
3821
3822 if (!new_live_dangerously && live_dangerously)
3823 {
3824 ast_log(LOG_NOTICE, "Manager Configuration load protection enabled.\n");
3825 }
3826 live_dangerously = new_live_dangerously;
3827}
3828
3829/**
3830 * \brief Check if a file is restricted or not
3831 *
3832 * \return 0 on success
3833 * \return 1 on restricted file
3834 * \return -1 on failure
3835 */
3836static int restrictedFile(const char *filename)
3837{
3838 char *stripped_filename;
3839 RAII_VAR(char *, path, NULL, ast_free);
3840 RAII_VAR(char *, real_path, NULL, ast_std_free);
3841
3842 if (live_dangerously) {
3843 return 0;
3844 }
3845
3846 stripped_filename = ast_strip(ast_strdupa(filename));
3847
3848 /* If the file path starts with '/', don't prepend ast_config_AST_CONFIG_DIR */
3849 if (stripped_filename[0] == '/') {
3850 real_path = realpath(stripped_filename, NULL);
3851 } else {
3852 if (ast_asprintf(&path, "%s/%s", ast_config_AST_CONFIG_DIR, stripped_filename) == -1) {
3853 return -1;
3854 }
3855 real_path = realpath(path, NULL);
3856 }
3857
3858 if (!real_path) {
3859 return -1;
3860 }
3861
3862 if (!ast_begins_with(real_path, ast_config_AST_CONFIG_DIR)) {
3863 return 1;
3864 }
3865
3866 return 0;
3867}
3868
3869static int action_getconfig(struct mansession *s, const struct message *m)
3870{
3871 struct ast_config *cfg;
3872 const char *fn = astman_get_header(m, "Filename");
3873 const char *category = astman_get_header(m, "Category");
3874 const char *filter = astman_get_header(m, "Filter");
3875 const char *category_name;
3876 int catcount = 0;
3877 int lineno = 0;
3878 int ret = 0;
3879 struct ast_category *cur_category = NULL;
3880 struct ast_variable *v;
3881 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3882
3883 if (ast_strlen_zero(fn)) {
3884 astman_send_error(s, m, "Filename not specified");
3885 return 0;
3886 }
3887
3888 ret = restrictedFile(fn);
3889 if (ret == 1) {
3890 astman_send_error(s, m, "File requires escalated priveledges");
3891 return 0;
3892 } else if (ret == -1) {
3893 astman_send_error(s, m, "Config file not found");
3894 return 0;
3895 }
3896
3897 cfg = ast_config_load2(fn, "manager", config_flags);
3898 if (cfg == CONFIG_STATUS_FILEMISSING) {
3899 astman_send_error(s, m, "Config file not found");
3900 return 0;
3901 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
3902 astman_send_error(s, m, "Config file has invalid format");
3903 return 0;
3904 }
3905
3906 astman_start_ack(s, m);
3907 while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
3908 struct ast_str *templates;
3909
3910 category_name = ast_category_get_name(cur_category);
3911 lineno = 0;
3912 astman_append(s, "Category-%06d: %s\r\n", catcount, category_name);
3913
3914 if (ast_category_is_template(cur_category)) {
3915 astman_append(s, "IsTemplate-%06d: %d\r\n", catcount, 1);
3916 }
3917
3918 if ((templates = ast_category_get_templates(cur_category))
3919 && ast_str_strlen(templates) > 0) {
3920 astman_append(s, "Templates-%06d: %s\r\n", catcount, ast_str_buffer(templates));
3922 }
3923
3924 for (v = ast_category_first(cur_category); v; v = v->next) {
3925 astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
3926 }
3927
3928 catcount++;
3929 }
3930
3931 if (!ast_strlen_zero(category) && catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
3932 astman_append(s, "No categories found\r\n");
3933 }
3934
3935 ast_config_destroy(cfg);
3936 astman_append(s, "\r\n");
3937
3938 return 0;
3939}
3940
3941static int action_listcategories(struct mansession *s, const struct message *m)
3942{
3943 struct ast_config *cfg;
3944 const char *fn = astman_get_header(m, "Filename");
3945 const char *match = astman_get_header(m, "Match");
3946 struct ast_category *category = NULL;
3947 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3948 int catcount = 0;
3949
3950 if (ast_strlen_zero(fn)) {
3951 astman_send_error(s, m, "Filename not specified");
3952 return 0;
3953 }
3954
3955 if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
3956 astman_send_error(s, m, "Config file not found");
3957 return 0;
3958 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
3959 astman_send_error(s, m, "Config file has invalid format");
3960 return 0;
3961 }
3962
3963 astman_start_ack(s, m);
3964 while ((category = ast_category_browse_filtered(cfg, NULL, category, match))) {
3965 astman_append(s, "Category-%06d: %s\r\n", catcount, ast_category_get_name(category));
3966 catcount++;
3967 }
3968
3969 if (catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
3970 astman_append(s, "Error: no categories found\r\n");
3971 }
3972
3973 ast_config_destroy(cfg);
3974 astman_append(s, "\r\n");
3975
3976 return 0;
3977}
3978
3979/*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
3980static void json_escape(char *out, const char *in)
3981{
3982 for (; *in; in++) {
3983 if (*in == '\\' || *in == '\"') {
3984 *out++ = '\\';
3985 }
3986 *out++ = *in;
3987 }
3988 *out = '\0';
3989}
3990
3991/*!
3992 * \internal
3993 * \brief Append a JSON escaped string to the manager stream.
3994 *
3995 * \param s AMI stream to append a string.
3996 * \param str String to append to the stream after JSON escaping it.
3997 */
3998static void astman_append_json(struct mansession *s, const char *str)
3999{
4000 char *buf;
4001
4002 buf = ast_alloca(2 * strlen(str) + 1);
4004 astman_append(s, "%s", buf);
4005}
4006
4007static int action_getconfigjson(struct mansession *s, const struct message *m)
4008{
4009 struct ast_config *cfg;
4010 const char *fn = astman_get_header(m, "Filename");
4011 const char *filter = astman_get_header(m, "Filter");
4012 const char *category = astman_get_header(m, "Category");
4013 struct ast_category *cur_category = NULL;
4014 const char *category_name;
4015 struct ast_variable *v;
4016 int comma1 = 0;
4017 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
4018
4019 if (ast_strlen_zero(fn)) {
4020 astman_send_error(s, m, "Filename not specified");
4021 return 0;
4022 }
4023
4024 if (restrictedFile(fn)) {
4025 astman_send_error(s, m, "File requires escalated priveledges");
4026 return 0;
4027 }
4028
4029 if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
4030 astman_send_error(s, m, "Config file not found");
4031 return 0;
4032 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
4033 astman_send_error(s, m, "Config file has invalid format");
4034 return 0;
4035 }
4036
4037 astman_start_ack(s, m);
4038 astman_append(s, "JSON: {");
4039 while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
4040 int comma2 = 0;
4041 struct ast_str *templates;
4042
4043 category_name = ast_category_get_name(cur_category);
4044 astman_append(s, "%s\"", comma1 ? "," : "");
4045 astman_append_json(s, category_name);
4046 astman_append(s, "\":{");
4047 comma1 = 1;
4048
4049 if (ast_category_is_template(cur_category)) {
4050 astman_append(s, "\"istemplate\":1");
4051 comma2 = 1;
4052 }
4053
4054 if ((templates = ast_category_get_templates(cur_category))
4055 && ast_str_strlen(templates) > 0) {
4056 astman_append(s, "%s", comma2 ? "," : "");
4057 astman_append(s, "\"templates\":\"%s\"", ast_str_buffer(templates));
4059 comma2 = 1;
4060 }
4061
4062 for (v = ast_category_first(cur_category); v; v = v->next) {
4063 astman_append(s, "%s\"", comma2 ? "," : "");
4064 astman_append_json(s, v->name);
4065 astman_append(s, "\":\"");
4067 astman_append(s, "\"");
4068 comma2 = 1;
4069 }
4070
4071 astman_append(s, "}");
4072 }
4073 astman_append(s, "}\r\n\r\n");
4074
4075 ast_config_destroy(cfg);
4076
4077 return 0;
4078}
4079
4080/*! \brief helper function for action_updateconfig */
4081static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
4082{
4083 int x;
4084 char hdr[40];
4085 const char *action, *cat, *var, *value, *match, *line, *options;
4086 struct ast_variable *v;
4087 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
4088 enum error_type result = 0;
4089
4090 for (x = 0; x < 100000; x++) { /* 100000 = the max number of allowed updates + 1 */
4091 unsigned int object = 0;
4092 char *dupoptions;
4093 int allowdups = 0;
4094 int istemplate = 0;
4095 int ignoreerror = 0;
4096 RAII_VAR(char *, inherit, NULL, ast_free);
4097 RAII_VAR(char *, catfilter, NULL, ast_free);
4098 char *token;
4099 int foundvar = 0;
4100 int foundcat = 0;
4101 struct ast_category *category = NULL;
4102
4103 snprintf(hdr, sizeof(hdr), "Action-%06d", x);
4104 action = astman_get_header(m, hdr);
4105 if (ast_strlen_zero(action)) /* breaks the for loop if no action header */
4106 break; /* this could cause problems if actions come in misnumbered */
4107
4108 snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
4109 cat = astman_get_header(m, hdr);
4110 if (ast_strlen_zero(cat)) { /* every action needs a category */
4112 break;
4113 }
4114
4115 snprintf(hdr, sizeof(hdr), "Var-%06d", x);
4116 var = astman_get_header(m, hdr);
4117
4118 snprintf(hdr, sizeof(hdr), "Value-%06d", x);
4119 value = astman_get_header(m, hdr);
4120
4121 if (!ast_strlen_zero(value) && *value == '>') {
4122 object = 1;
4123 value++;
4124 }
4125
4126 snprintf(hdr, sizeof(hdr), "Match-%06d", x);
4127 match = astman_get_header(m, hdr);
4128
4129 snprintf(hdr, sizeof(hdr), "Line-%06d", x);
4130 line = astman_get_header(m, hdr);
4131
4132 snprintf(hdr, sizeof(hdr), "Options-%06d", x);
4133 options = astman_get_header(m, hdr);
4134 if (!ast_strlen_zero(options)) {
4135 char copy[strlen(options) + 1];
4136 strcpy(copy, options); /* safe */
4137 dupoptions = copy;
4138 while ((token = ast_strsep(&dupoptions, ',', AST_STRSEP_STRIP))) {
4139 if (!strcasecmp("allowdups", token)) {
4140 allowdups = 1;
4141 continue;
4142 }
4143 if (!strcasecmp("template", token)) {
4144 istemplate = 1;
4145 continue;
4146 }
4147 if (!strcasecmp("ignoreerror", token)) {
4148 ignoreerror = 1;
4149 continue;
4150 }
4151 if (ast_begins_with(token, "inherit")) {
4152 char *c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
4153 c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
4154 if (c) {
4155 inherit = ast_strdup(c);
4156 }
4157 continue;
4158 }
4159 if (ast_begins_with(token, "catfilter")) {
4160 char *c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
4161 c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
4162 if (c) {
4163 catfilter = ast_strdup(c);
4164 }
4165 continue;
4166 }
4167 }
4168 }
4169
4170 if (!strcasecmp(action, "newcat")) {
4171 struct ast_category *template;
4172 char *tmpl_name = NULL;
4173
4174 if (!allowdups) {
4175 if (ast_category_get(cfg, cat, "TEMPLATES=include")) {
4176 if (ignoreerror) {
4177 continue;
4178 } else {
4179 result = FAILURE_NEWCAT; /* already exist */
4180 break;
4181 }
4182 }
4183 }
4184
4185 if (istemplate) {
4186 category = ast_category_new_template(cat, dfn, -1);
4187 } else {
4188 category = ast_category_new(cat, dfn, -1);
4189 }
4190
4191 if (!category) {
4193 break;
4194 }
4195
4196 if (inherit) {
4197 while ((tmpl_name = ast_strsep(&inherit, ',', AST_STRSEP_STRIP))) {
4198 if ((template = ast_category_get(cfg, tmpl_name, "TEMPLATES=restrict"))) {
4199 if (ast_category_inherit(category, template)) {
4201 break;
4202 }
4203 } else {
4204 ast_category_destroy(category);
4205 category = NULL;
4206 result = FAILURE_TEMPLATE; /* template not found */
4207 break;
4208 }
4209 }
4210 }
4211
4212 if (category != NULL) {
4213 if (ast_strlen_zero(match)) {
4214 ast_category_append(cfg, category);
4215 } else {
4216 if (ast_category_insert(cfg, category, match)) {
4217 ast_category_destroy(category);
4219 break;
4220 }
4221 }
4222 }
4223 } else if (!strcasecmp(action, "renamecat")) {
4224 if (ast_strlen_zero(value)) {
4226 break;
4227 }
4228
4229 foundcat = 0;
4230 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4231 ast_category_rename(category, value);
4232 foundcat = 1;
4233 }
4234
4235 if (!foundcat) {
4237 break;
4238 }
4239 } else if (!strcasecmp(action, "delcat")) {
4240 foundcat = 0;
4241 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4242 category = ast_category_delete(cfg, category);
4243 foundcat = 1;
4244 }
4245
4246 if (!foundcat && !ignoreerror) {
4248 break;
4249 }
4250 } else if (!strcasecmp(action, "emptycat")) {
4251 foundcat = 0;
4252 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4253 ast_category_empty(category);
4254 foundcat = 1;
4255 }
4256
4257 if (!foundcat) {
4259 break;
4260 }
4261 } else if (!strcasecmp(action, "update")) {
4262 if (ast_strlen_zero(var)) {
4264 break;
4265 }
4266
4267 foundcat = 0;
4268 foundvar = 0;
4269 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4270 if (!ast_variable_update(category, var, value, match, object)) {
4271 foundvar = 1;
4272 }
4273 foundcat = 1;
4274 }
4275
4276 if (!foundcat) {
4278 break;
4279 }
4280
4281 if (!foundvar) {
4283 break;
4284 }
4285 } else if (!strcasecmp(action, "delete")) {
4286 if ((ast_strlen_zero(var) && ast_strlen_zero(line))) {
4288 break;
4289 }
4290
4291 foundcat = 0;
4292 foundvar = 0;
4293 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4294 if (!ast_variable_delete(category, var, match, line)) {
4295 foundvar = 1;
4296 }
4297 foundcat = 1;
4298 }
4299
4300 if (!foundcat) {
4302 break;
4303 }
4304
4305 if (!foundvar && !ignoreerror) {
4307 break;
4308 }
4309 } else if (!strcasecmp(action, "append")) {
4310 if (ast_strlen_zero(var)) {
4312 break;
4313 }
4314
4315 foundcat = 0;
4316 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4317 if (!(v = ast_variable_new(var, value, dfn))) {
4319 break;
4320 }
4321 if (object || (match && !strcasecmp(match, "object"))) {
4322 v->object = 1;
4323 }
4324 ast_variable_append(category, v);
4325 foundcat = 1;
4326 }
4327
4328 if (!foundcat) {
4330 break;
4331 }
4332 } else if (!strcasecmp(action, "insert")) {
4333 if (ast_strlen_zero(var) || ast_strlen_zero(line)) {
4335 break;
4336 }
4337
4338 foundcat = 0;
4339 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
4340 if (!(v = ast_variable_new(var, value, dfn))) {
4342 break;
4343 }
4344 ast_variable_insert(category, v, line);
4345 foundcat = 1;
4346 }
4347
4348 if (!foundcat) {
4350 break;
4351 }
4352 }
4353 else {
4354 ast_log(LOG_WARNING, "Action-%06d: %s not handled\n", x, action);
4356 break;
4357 }
4358 }
4359 ast_free(str1);
4360 ast_free(str2);
4361 return result;
4362}
4363
4364static int action_updateconfig(struct mansession *s, const struct message *m)
4365{
4366 struct ast_config *cfg;
4367 const char *sfn = astman_get_header(m, "SrcFilename");
4368 const char *dfn = astman_get_header(m, "DstFilename");
4369 int res;
4370 const char *rld = astman_get_header(m, "Reload");
4371 int preserve_effective_context = CONFIG_SAVE_FLAG_PRESERVE_EFFECTIVE_CONTEXT;
4372 const char *preserve_effective_context_string = astman_get_header(m, "PreserveEffectiveContext");
4373 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
4374 enum error_type result;
4375
4376 if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
4377 astman_send_error(s, m, "Filename not specified");
4378 return 0;
4379 }
4380 if (restrictedFile(sfn) || restrictedFile(dfn)) {
4381 astman_send_error(s, m, "File requires escalated priveledges");
4382 return 0;
4383 }
4384 if (!(cfg = ast_config_load2(sfn, "manager", config_flags))) {
4385 astman_send_error(s, m, "Config file not found");
4386 return 0;
4387 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
4388 astman_send_error(s, m, "Config file has invalid format");
4389 return 0;
4390 }
4391 result = handle_updates(s, m, cfg, dfn);
4392 if (!result) {
4393 ast_include_rename(cfg, sfn, dfn); /* change the include references from dfn to sfn, so things match up */
4394 if (!ast_strlen_zero(preserve_effective_context_string) && !ast_true(preserve_effective_context_string)) {
4395 preserve_effective_context = CONFIG_SAVE_FLAG_NONE;
4396 }
4397 res = ast_config_text_file_save2(dfn, cfg, "Manager", preserve_effective_context);
4398 ast_config_destroy(cfg);
4399 if (res) {
4400 astman_send_error(s, m, "Save of config failed");
4401 return 0;
4402 }
4403 astman_send_ack(s, m, NULL);
4404 if (!ast_strlen_zero(rld)) {
4405 if (ast_true(rld)) {
4406 ast_module_reload(NULL); /* Reload everything */
4407 } else if (!ast_false(rld)) {
4408 ast_module_reload(rld); /* Reload the specific module */
4409 }
4410 }
4411 } else {
4412 ast_config_destroy(cfg);
4413 switch(result) {
4414 case UNKNOWN_ACTION:
4415 astman_send_error(s, m, "Unknown action command");
4416 break;
4417 case UNKNOWN_CATEGORY:
4418 astman_send_error(s, m, "Given category does not exist");
4419 break;
4421 astman_send_error(s, m, "Category not specified");
4422 break;
4424 astman_send_error(s, m, "Problem with category, value, or line (if required)");
4425 break;
4426 case FAILURE_ALLOCATION:
4427 astman_send_error(s, m, "Memory allocation failure, this should not happen");
4428 break;
4429 case FAILURE_NEWCAT:
4430 astman_send_error(s, m, "Create category did not complete successfully");
4431 break;
4432 case FAILURE_DELCAT:
4433 astman_send_error(s, m, "Delete category did not complete successfully");
4434 break;
4435 case FAILURE_EMPTYCAT:
4436 astman_send_error(s, m, "Empty category did not complete successfully");
4437 break;
4438 case FAILURE_UPDATE:
4439 astman_send_error(s, m, "Update did not complete successfully");
4440 break;
4441 case FAILURE_DELETE:
4442 astman_send_error(s, m, "Delete did not complete successfully");
4443 break;
4444 case FAILURE_APPEND:
4445 astman_send_error(s, m, "Append did not complete successfully");
4446 break;
4447 case FAILURE_TEMPLATE:
4448 astman_send_error(s, m, "Template category not found");
4449 break;
4450 }
4451 }
4452 return 0;
4453}
4454
4455static int action_createconfig(struct mansession *s, const struct message *m)
4456{
4457 int fd;
4458 const char *fn = astman_get_header(m, "Filename");
4459 struct ast_str *filepath = ast_str_alloca(PATH_MAX);
4460 ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
4461 ast_str_append(&filepath, 0, "%s", fn);
4462
4463 if ((fd = open(ast_str_buffer(filepath), O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
4464 close(fd);
4465 astman_send_ack(s, m, "New configuration file created successfully");
4466 } else {
4467 astman_send_error(s, m, strerror(errno));
4468 }
4469
4470 return 0;
4471}
4472
4473static int action_waitevent(struct mansession *s, const struct message *m)
4474{
4475 const char *timeouts = astman_get_header(m, "Timeout");
4476 int timeout = -1;
4477 int x;
4478 int needexit = 0;
4479 const char *id = astman_get_header(m, "ActionID");
4480 char idText[256];
4481
4482 if (!ast_strlen_zero(id)) {
4483 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
4484 } else {
4485 idText[0] = '\0';
4486 }
4487
4488 if (!ast_strlen_zero(timeouts)) {
4489 sscanf(timeouts, "%30i", &timeout);
4490 if (timeout < -1) {
4491 timeout = -1;
4492 }
4493 /* XXX maybe put an upper bound, or prevent the use of 0 ? */
4494 }
4495
4498 pthread_kill(s->session->waiting_thread, SIGURG);
4499 }
4501
4502 ao2_lock(s->session);
4503
4504 if (s->session->managerid) { /* AMI-over-HTTP session */
4505 /*
4506 * Make sure the timeout is within the expire time of the session,
4507 * as the client will likely abort the request if it does not see
4508 * data coming after some amount of time.
4509 */
4510 time_t now = time(NULL);
4511 int max = s->session->sessiontimeout - now - 10;
4512
4513 if (max < 0) { /* We are already late. Strange but possible. */
4514 max = 0;
4515 }
4516 if (timeout < 0 || timeout > max) {
4517 timeout = max;
4518 }
4519 if (!s->session->send_events) { /* make sure we record events */
4520 s->session->send_events = -1;
4521 }
4522 }
4523 ao2_unlock(s->session);
4524
4526 s->session->waiting_thread = pthread_self(); /* let new events wake up this thread */
4528 ast_debug(1, "Starting waiting for an event!\n");
4529
4530 for (x = 0; x < timeout || timeout < 0; x++) {
4531 ao2_lock(s->session);
4532 if (AST_RWLIST_NEXT(s->session->last_ev, eq_next)) {
4533 needexit = 1;
4534 }
4535 if (s->session->needdestroy) {
4536 needexit = 1;
4537 }
4538 ao2_unlock(s->session);
4539 /* We can have multiple HTTP session point to the same mansession entry.
4540 * The way we deal with it is not very nice: newcomers kick out the previous
4541 * HTTP session. XXX this needs to be improved.
4542 */
4544 if (s->session->waiting_thread != pthread_self()) {
4545 needexit = 1;
4546 }
4548 if (needexit) {
4549 break;
4550 }
4551 if (s->session->managerid == 0) { /* AMI session */
4553 break;
4554 }
4555 } else { /* HTTP session */
4556 sleep(1);
4557 }
4558 }
4559 ast_debug(1, "Finished waiting for an event!\n");
4560
4562 if (s->session->waiting_thread == pthread_self()) {
4563 struct eventqent *eqe = s->session->last_ev;
4564
4567
4568 ao2_lock(s->session);
4569 astman_send_response(s, m, "Success", "Waiting for Event completed.");
4570 while ((eqe = advance_event(eqe))) {
4571 if (((s->session->readperm & eqe->category) == eqe->category)
4572 && ((s->session->send_events & eqe->category) == eqe->category)
4573 && match_filter(s, eqe->eventdata)) {
4574 astman_append(s, "%s", eqe->eventdata);
4575 }
4576 s->session->last_ev = eqe;
4577 }
4578 astman_append(s,
4579 "Event: WaitEventComplete\r\n"
4580 "%s"
4581 "\r\n", idText);
4582 ao2_unlock(s->session);
4583 } else {
4585 ast_debug(1, "Abandoning event request!\n");
4586 }
4587
4588 return 0;
4589}
4590
4591static int action_listcommands(struct mansession *s, const struct message *m)
4592{
4593 struct manager_action *cur;
4595
4596 astman_start_ack(s, m);
4598 AST_RWLIST_TRAVERSE(&actions, cur, list) {
4599 if ((s->session->writeperm & cur->authority) || cur->authority == 0) {
4600 astman_append(s, "%s: %s (Priv: %s)\r\n",
4601 cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
4602 }
4603 }
4605 astman_append(s, "\r\n");
4606
4607 return 0;
4608}
4609
4610static int action_events(struct mansession *s, const struct message *m)
4611{
4612 const char *mask = astman_get_header(m, "EventMask");
4613 int res, x;
4614 const char *id = astman_get_header(m, "ActionID");
4615 char id_text[256];
4616
4617 if (!ast_strlen_zero(id)) {
4618 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
4619 } else {
4620 id_text[0] = '\0';
4621 }
4622
4623 res = set_eventmask(s, mask);
4625 /* if this option is set we should not return a response on
4626 * error, or when all events are set */
4627
4628 if (res > 0) {
4629 for (x = 0; x < ARRAY_LEN(perms); x++) {
4630 if (!strcasecmp(perms[x].label, "all") && res == perms[x].num) {
4631 return 0;
4632 }
4633 }
4634 astman_append(s, "Response: Success\r\n%s"
4635 "Events: On\r\n\r\n", id_text);
4636 } else if (res == 0)
4637 astman_append(s, "Response: Success\r\n%s"
4638 "Events: Off\r\n\r\n", id_text);
4639 return 0;
4640 }
4641
4642 if (res > 0)
4643 astman_append(s, "Response: Success\r\n%s"
4644 "Events: On\r\n\r\n", id_text);
4645 else if (res == 0)
4646 astman_append(s, "Response: Success\r\n%s"
4647 "Events: Off\r\n\r\n", id_text);
4648 else
4649 astman_send_error(s, m, "Invalid event mask");
4650
4651 return 0;
4652}
4653
4654static int action_logoff(struct mansession *s, const struct message *m)
4655{
4656 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
4657 return -1;
4658}
4659
4660static int action_login(struct mansession *s, const struct message *m)
4661{
4662
4663 /* still authenticated - don't process again */
4664 if (s->session->authenticated) {
4665 astman_send_ack(s, m, "Already authenticated");
4666 return 0;
4667 }
4668
4669 if (authenticate(s, m)) {
4670 sleep(1);
4671 astman_send_error(s, m, "Authentication failed");
4672 return -1;
4673 }
4674 s->session->authenticated = 1;
4677 ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_sockaddr_stringify_addr(&s->session->addr));
4678 }
4679 astman_send_ack(s, m, "Authentication accepted");
4684 const char *cat_str = authority_to_str(EVENT_FLAG_SYSTEM, &auth);
4685 long uptime = 0;
4686 long lastreloaded = 0;
4687 struct timeval tmp;
4688 struct timeval curtime = ast_tvnow();
4689
4690 if (ast_startuptime.tv_sec) {
4691 tmp = ast_tvsub(curtime, ast_startuptime);
4692 uptime = tmp.tv_sec;
4693 }
4694
4695 if (ast_lastreloadtime.tv_sec) {
4696 tmp = ast_tvsub(curtime, ast_lastreloadtime);
4697 lastreloaded = tmp.tv_sec;
4698 }
4699
4700 astman_append(s, "Event: FullyBooted\r\n"
4701 "Privilege: %s\r\n"
4702 "Uptime: %ld\r\n"
4703 "LastReload: %ld\r\n"
4704 "Status: Fully Booted\r\n\r\n", cat_str, uptime, lastreloaded);
4705 }
4706 return 0;
4707}
4708
4709static int action_challenge(struct mansession *s, const struct message *m)
4710{
4711 const char *authtype = astman_get_header(m, "AuthType");
4712
4713 if (!strcasecmp(authtype, "MD5")) {
4715 snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
4716 }
4717 mansession_lock(s);
4718 astman_start_ack(s, m);
4719 astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
4721 } else {
4722 astman_send_error(s, m, "Must specify AuthType");
4723 }
4724 return 0;
4725}
4726
4728 const struct message *m, manager_hangup_handler_t hangup_handler,
4729 manager_hangup_cause_validator_t cause_validator)
4730{
4731 struct ast_channel *c = NULL;
4732 int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
4733 const char *id = astman_get_header(m, "ActionID");
4734 const char *name_or_regex = astman_get_header(m, "Channel");
4735 const char *cause = astman_get_header(m, "Cause");
4736 char idText[256];
4737 regex_t regexbuf;
4738 struct ast_channel_iterator *iter = NULL;
4739 struct ast_str *regex_string;
4740 int channels_matched = 0;
4741
4742 if (ast_strlen_zero(name_or_regex)) {
4743 astman_send_error(s, m, "No channel specified");
4744 return 0;
4745 }
4746
4747 if (!ast_strlen_zero(id)) {
4748 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
4749 } else {
4750 idText[0] = '\0';
4751 }
4752
4753 if (cause_validator) {
4754 causecode = cause_validator(name_or_regex, cause);
4755 } else if (!ast_strlen_zero(cause)) {
4756 char *endptr;
4757 causecode = strtol(cause, &endptr, 10);
4758 if (causecode < 0 || causecode > 127 || *endptr != '\0') {
4759 ast_log(LOG_NOTICE, "Invalid 'Cause: %s' in manager action Hangup\n", cause);
4760 /* keep going, better to hangup without cause than to not hang up at all */
4761 causecode = 0; /* do not set channel's hangupcause */
4762 }
4763 }
4764
4765 /************************************************/
4766 /* Regular explicit match channel byname hangup */
4767
4768 if (name_or_regex[0] != '/') {
4769 if (!(c = ast_channel_get_by_name(name_or_regex))) {
4770 ast_log(LOG_NOTICE, "Request to hangup non-existent channel: %s\n",
4771 name_or_regex);
4772 astman_send_error(s, m, "No such channel");
4773 return 0;
4774 }
4775
4776 ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
4777 (s->session->managerid ? "HTTP " : ""),
4778 s->session->username,
4781
4782 hangup_handler(c, causecode);
4784
4785 astman_send_ack(s, m, "Channel Hungup");
4786
4787 return 0;
4788 }
4789
4790 /***********************************************/
4791 /* find and hangup any channels matching regex */
4792
4793 regex_string = ast_str_create(strlen(name_or_regex));
4794 if (!regex_string) {
4795 astman_send_error(s, m, "Memory Allocation Failure");
4796 return 0;
4797 }
4798
4799 /* Make "/regex/" into "regex" */
4800 if (ast_regex_string_to_regex_pattern(name_or_regex, &regex_string) != 0) {
4801 astman_send_error(s, m, "Regex format invalid, Channel param should be /regex/");
4802 ast_free(regex_string);
4803 return 0;
4804 }
4805
4806 /* if regex compilation fails, hangup fails */
4807 if (regcomp(&regexbuf, ast_str_buffer(regex_string), REG_EXTENDED | REG_NOSUB)) {
4808 astman_send_error_va(s, m, "Regex compile failed on: %s", name_or_regex);
4809 ast_free(regex_string);
4810 return 0;
4811 }
4812
4813 astman_send_listack(s, m, "Channels hung up will follow", "start");
4814
4816 if (iter) {
4817 for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
4818 if (regexec(&regexbuf, ast_channel_name(c), 0, NULL, 0)) {
4819 continue;
4820 }
4821
4822 ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
4823 (s->session->managerid ? "HTTP " : ""),
4824 s->session->username,
4827
4828 hangup_handler(c, causecode);
4829 channels_matched++;
4830
4831 astman_append(s,
4832 "Event: ChannelHungup\r\n"
4833 "Channel: %s\r\n"
4834 "%s"
4835 "\r\n", ast_channel_name(c), idText);
4836 }
4838 }
4839
4840 regfree(&regexbuf);
4841 ast_free(regex_string);
4842
4843 astman_send_list_complete(s, m, "ChannelsHungupListComplete", channels_matched);
4844
4845 return 0;
4846}
4847
4848static int action_hangup(struct mansession *s, const struct message *m)
4849{
4850 return ast_manager_hangup_helper(s, m,
4852}
4853
4854static int action_setvar(struct mansession *s, const struct message *m)
4855{
4856 struct ast_channel *c = NULL;
4857 const char *name = astman_get_header(m, "Channel");
4858 const char *varname = astman_get_header(m, "Variable");
4859 const char *varval = astman_get_header(m, "Value");
4860 int res = 0;
4861
4862 if (ast_strlen_zero(varname)) {
4863 astman_send_error(s, m, "No variable specified");
4864 return 0;
4865 }
4866
4867 if (!ast_strlen_zero(name)) {
4868 if (!(c = ast_channel_get_by_name(name))) {
4869 astman_send_error(s, m, "No such channel");
4870 return 0;
4871 }
4872 }
4873
4874 res = pbx_builtin_setvar_helper(c, varname, S_OR(varval, ""));
4875
4876 if (c) {
4878 }
4879 if (res == 0) {
4880 astman_send_ack(s, m, "Variable Set");
4881 } else {
4882 astman_send_error(s, m, "Variable not set");
4883 }
4884 return 0;
4885}
4886
4887static int action_getvar(struct mansession *s, const struct message *m)
4888{
4889 struct ast_channel *c = NULL;
4890 const char *name = astman_get_header(m, "Channel");
4891 const char *varname = astman_get_header(m, "Variable");
4892 char *varval;
4893 char workspace[1024];
4894
4895 if (ast_strlen_zero(varname)) {
4896 astman_send_error(s, m, "No variable specified");
4897 return 0;
4898 }
4899
4900 /* We don't want users with insufficient permissions using certain functions. */
4902 astman_send_error(s, m, "GetVar Access Forbidden: Variable");
4903 return 0;
4904 }
4905
4906 if (!ast_strlen_zero(name)) {
4907 if (!(c = ast_channel_get_by_name(name))) {
4908 astman_send_error(s, m, "No such channel");
4909 return 0;
4910 }
4911 }
4912
4913 workspace[0] = '\0';
4914 if (varname[strlen(varname) - 1] == ')') {
4915 if (!c) {
4917 if (c) {
4918 ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
4919 } else
4920 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
4921 } else {
4922 ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
4923 }
4924 varval = workspace;
4925 } else {
4926 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
4927 }
4928
4929 if (c) {
4931 }
4932
4933 astman_start_ack(s, m);
4934 astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, S_OR(varval, ""));
4935
4936 return 0;
4937}
4938
4939static void generate_status(struct mansession *s, struct ast_channel *chan, char **vars, int varc, int all_variables, char *id_text, int *count)
4940{
4941 struct timeval now;
4942 long elapsed_seconds;
4943 struct ast_bridge *bridge;
4944 RAII_VAR(struct ast_str *, variable_str, NULL, ast_free);
4945 struct ast_str *write_transpath = ast_str_alloca(256);
4946 struct ast_str *read_transpath = ast_str_alloca(256);
4947 struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
4948 struct ast_party_id effective_id;
4949 int i;
4950 RAII_VAR(struct ast_channel_snapshot *, snapshot,
4952 ao2_cleanup);
4953 RAII_VAR(struct ast_str *, snapshot_str, NULL, ast_free);
4954
4955 if (!snapshot) {
4956 return;
4957 }
4958
4959 snapshot_str = ast_manager_build_channel_state_string(snapshot);
4960 if (!snapshot_str) {
4961 return;
4962 }
4963
4964 if (all_variables) {
4965 variable_str = ast_str_create(2048);
4966 } else {
4967 variable_str = ast_str_create(1024);
4968 }
4969 if (!variable_str) {
4970 return;
4971 }
4972
4973 now = ast_tvnow();
4974 elapsed_seconds = ast_tvdiff_sec(now, ast_channel_creationtime(chan));
4975
4976 /* Even if all_variables has been specified, explicitly requested variables
4977 * may be global variables or dialplan functions */
4978 for (i = 0; i < varc; i++) {
4979 char valbuf[512], *ret = NULL;
4980
4981 if (vars[i][strlen(vars[i]) - 1] == ')') {
4982 if (ast_func_read(chan, vars[i], valbuf, sizeof(valbuf)) < 0) {
4983 valbuf[0] = '\0';
4984 }
4985 ret = valbuf;
4986 } else {
4987 pbx_retrieve_variable(chan, vars[i], &ret, valbuf, sizeof(valbuf), NULL);
4988 }
4989
4990 ast_str_append(&variable_str, 0, "Variable: %s=%s\r\n", vars[i], ret);
4991 }
4992
4993 /* Walk all channel variables and add them */
4994 if (all_variables) {
4995 struct ast_var_t *variables;
4996
4997 AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
4998 ast_str_append(&variable_str, 0, "Variable: %s=%s\r\n",
4999 ast_var_name(variables), ast_var_value(variables));
5000 }
5001 }
5002
5003 bridge = ast_channel_get_bridge(chan);
5004 effective_id = ast_channel_connected_effective_id(chan);
5005
5006 astman_append(s,
5007 "Event: Status\r\n"
5008 "Privilege: Call\r\n"
5009 "%s"
5010 "Type: %s\r\n"
5011 "DNID: %s\r\n"
5012 "EffectiveConnectedLineNum: %s\r\n"
5013 "EffectiveConnectedLineName: %s\r\n"
5014 "TimeToHangup: %ld\r\n"
5015 "BridgeID: %s\r\n"
5016 "Application: %s\r\n"
5017 "Data: %s\r\n"
5018 "Nativeformats: %s\r\n"
5019 "Readformat: %s\r\n"
5020 "Readtrans: %s\r\n"
5021 "Writeformat: %s\r\n"
5022 "Writetrans: %s\r\n"
5023 "Callgroup: %llu\r\n"
5024 "Pickupgroup: %llu\r\n"
5025 "Seconds: %ld\r\n"
5026 "%s"
5027 "%s"
5028 "\r\n",
5029 ast_str_buffer(snapshot_str),
5030 ast_channel_tech(chan)->type,
5031 S_OR(ast_channel_dialed(chan)->number.str, ""),
5032 S_COR(effective_id.number.valid, effective_id.number.str, "<unknown>"),
5033 S_COR(effective_id.name.valid, effective_id.name.str, "<unknown>"),
5034 (long)ast_channel_whentohangup(chan)->tv_sec,
5035 bridge ? bridge->uniqueid : "",
5036 ast_channel_appl(chan),
5037 ast_channel_data(chan),
5040 ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath),
5042 ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath),
5045 (long)elapsed_seconds,
5046 ast_str_buffer(variable_str),
5047 id_text);
5048 ++*count;
5049
5050 ao2_cleanup(bridge);
5051}
5052
5053/*! \brief Manager "status" command to show channels */
5054static int action_status(struct mansession *s, const struct message *m)
5055{
5056 const char *name = astman_get_header(m, "Channel");
5057 const char *chan_variables = astman_get_header(m, "Variables");
5058 const char *all_chan_variables = astman_get_header(m, "AllVariables");
5059 int all_variables = 0;
5060 const char *id = astman_get_header(m, "ActionID");
5061 char *variables = ast_strdupa(S_OR(chan_variables, ""));
5062 struct ast_channel *chan;
5063 int channels = 0;
5064 int all = ast_strlen_zero(name); /* set if we want all channels */
5065 char id_text[256];
5066 struct ast_channel_iterator *it_chans = NULL;
5068 AST_APP_ARG(name)[100];
5069 );
5070
5071 if (!ast_strlen_zero(all_chan_variables)) {
5072 all_variables = ast_true(all_chan_variables);
5073 }
5074
5076 astman_send_error(s, m, "Status Access Forbidden: Variables");
5077 return 0;
5078 }
5079
5080 if (all) {
5081 if (!(it_chans = ast_channel_iterator_all_new())) {
5082 astman_send_error(s, m, "Memory Allocation Failure");
5083 return 1;
5084 }
5085 chan = ast_channel_iterator_next(it_chans);
5086 } else {
5088 if (!chan) {
5089 astman_send_error(s, m, "No such channel");
5090 return 0;
5091 }
5092 }
5093
5094 astman_send_listack(s, m, "Channel status will follow", "start");
5095
5096 if (!ast_strlen_zero(id)) {
5097 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
5098 } else {
5099 id_text[0] = '\0';
5100 }
5101
5102 if (!ast_strlen_zero(chan_variables)) {
5103 AST_STANDARD_APP_ARGS(vars, variables);
5104 }
5105
5106 /* if we look by name, we break after the first iteration */
5107 for (; chan; all ? chan = ast_channel_iterator_next(it_chans) : 0) {
5108 ast_channel_lock(chan);
5109
5110 generate_status(s, chan, vars.name, vars.argc, all_variables, id_text, &channels);
5111
5112 ast_channel_unlock(chan);
5113 chan = ast_channel_unref(chan);
5114 }
5115
5116 if (it_chans) {
5118 }
5119
5120 astman_send_list_complete_start(s, m, "StatusComplete", channels);
5121 astman_append(s, "Items: %d\r\n", channels);
5123
5124 return 0;
5125}
5126
5127/*!
5128 * \brief Queue a given read action containing a payload onto a channel
5129 *
5130 * This queues a READ_ACTION control frame that contains a given "payload", or
5131 * data to be triggered and handled on the channel's read side. This ensures
5132 * the "action" is handled by the channel's media reading thread.
5133 *
5134 * \param chan The channel to queue the action on
5135 * \param payload The read action's payload
5136 * \param payload_size The size of the given payload
5137 * \param action The type of read action to queue
5138 *
5139 * \retval -1 on error
5140 * \retval 0 on success
5141 */
5142static int queue_read_action_payload(struct ast_channel *chan, const unsigned char *payload,
5143 size_t payload_size, enum ast_frame_read_action action)
5144{
5146 size_t obj_size;
5147 int res;
5148
5149 obj_size = payload_size + sizeof(*obj);
5150
5151 obj = ast_malloc(obj_size);
5152 if (!obj) {
5153 return -1;
5154 }
5155
5156 obj->action = action;
5157 obj->payload_size = payload_size;
5158 memcpy(obj->payload, payload, payload_size);
5159
5160 res = ast_queue_control_data(chan, AST_CONTROL_READ_ACTION, obj, obj_size);
5161
5162 ast_free(obj);
5163 return res;
5164}
5165
5166/*!
5167 * \brief Queue a read action to send a text message
5168 *
5169 * \param chan The channel to queue the action on
5170 * \param body The body of the message
5171 *
5172 * \retval -1 on error
5173 * \retval 0 on success
5174 */
5175static int queue_sendtext(struct ast_channel *chan, const char *body)
5176{
5177 return queue_read_action_payload(chan, (const unsigned char *)body,
5178 strlen(body) + 1, AST_FRAME_READ_ACTION_SEND_TEXT);
5179}
5180
5181/*!
5182 * \brief Queue a read action to send a text data message
5183 *
5184 * \param chan The channel to queue the action on
5185 * \param body The body of the message
5186 * \param content_type The message's content type
5187 *
5188 * \retval -1 on error
5189 * \retval 0 on success
5190 */
5191static int queue_sendtext_data(struct ast_channel *chan, const char *body,
5192 const char *content_type)
5193{
5194 int res;
5195 struct ast_msg_data *obj;
5196
5198 NULL, NULL, content_type, body);
5199 if (!obj) {
5200 return -1;
5201 }
5202
5203 res = queue_read_action_payload(chan, (const unsigned char *)obj,
5205
5206 ast_free(obj);
5207 return res;
5208}
5209
5210static int action_sendtext(struct mansession *s, const struct message *m)
5211{
5212 struct ast_channel *c;
5213 const char *name = astman_get_header(m, "Channel");
5214 const char *textmsg = astman_get_header(m, "Message");
5215 const char *content_type = astman_get_header(m, "Content-Type");
5216 int res;
5217
5218 if (ast_strlen_zero(name)) {
5219 astman_send_error(s, m, "No channel specified");
5220 return 0;
5221 }
5222
5223 if (ast_strlen_zero(textmsg)) {
5224 astman_send_error(s, m, "No Message specified");
5225 return 0;
5226 }
5227
5229 if (!c) {
5230 astman_send_error(s, m, "No such channel");
5231 return 0;
5232 }
5233
5234 /*
5235 * If the "extra" data is not available, then send using "string" only.
5236 * Doing such maintains backward compatibilities.
5237 */
5238 res = ast_strlen_zero(content_type) ? queue_sendtext(c, textmsg) :
5239 queue_sendtext_data(c, textmsg, content_type);
5240
5242
5243 if (res >= 0) {
5244 astman_send_ack(s, m, "Success");
5245 } else {
5246 astman_send_error(s, m, "Failure");
5247 }
5248
5249 return 0;
5250}
5251
5252/*! \brief action_redirect: The redirect manager command */
5253static int action_redirect(struct mansession *s, const struct message *m)
5254{
5255 char buf[256];
5256 const char *name = astman_get_header(m, "Channel");
5257 const char *name2 = astman_get_header(m, "ExtraChannel");
5258 const char *exten = astman_get_header(m, "Exten");
5259 const char *exten2 = astman_get_header(m, "ExtraExten");
5260 const char *context = astman_get_header(m, "Context");
5261 const char *context2 = astman_get_header(m, "ExtraContext");
5262 const char *priority = astman_get_header(m, "Priority");
5263 const char *priority2 = astman_get_header(m, "ExtraPriority");
5264 struct ast_channel *chan;
5265 struct ast_channel *chan2;
5266 int pi = 0;
5267 int pi2 = 0;
5268 int res;
5269 int chan1_wait = 0;
5270 int chan2_wait = 0;
5271
5272 if (ast_strlen_zero(name)) {
5273 astman_send_error(s, m, "Channel not specified");
5274 return 0;
5275 }
5276
5277 if (ast_strlen_zero(context)) {
5278 astman_send_error(s, m, "Context not specified");
5279 return 0;
5280 }
5281 if (ast_strlen_zero(exten)) {
5282 astman_send_error(s, m, "Exten not specified");
5283 return 0;
5284 }
5286 astman_send_error(s, m, "Priority not specified");
5287 return 0;
5288 }
5289 if (sscanf(priority, "%30d", &pi) != 1) {
5291 }
5292 if (pi < 1) {
5293 astman_send_error(s, m, "Priority is invalid");
5294 return 0;
5295 }
5296
5297 if (!ast_strlen_zero(name2) && !ast_strlen_zero(context2)) {
5298 /* We have an ExtraChannel and an ExtraContext */
5299 if (ast_strlen_zero(exten2)) {
5300 astman_send_error(s, m, "ExtraExten not specified");
5301 return 0;
5302 }
5303 if (ast_strlen_zero(priority2)) {
5304 astman_send_error(s, m, "ExtraPriority not specified");
5305 return 0;
5306 }
5307 if (sscanf(priority2, "%30d", &pi2) != 1) {
5308 pi2 = ast_findlabel_extension(NULL, context2, exten2, priority2, NULL);
5309 }
5310 if (pi2 < 1) {
5311 astman_send_error(s, m, "ExtraPriority is invalid");
5312 return 0;
5313 }
5314 }
5315
5317 if (!chan) {
5318 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
5319 astman_send_error(s, m, buf);
5320 return 0;
5321 }
5322 if (ast_check_hangup_locked(chan)) {
5323 astman_send_error(s, m, "Redirect failed, channel not up.");
5324 chan = ast_channel_unref(chan);
5325 return 0;
5326 }
5327
5328 if (ast_strlen_zero(name2)) {
5329 /* Single channel redirect in progress. */
5330 res = ast_async_goto(chan, context, exten, pi);
5331 if (!res) {
5332 astman_send_ack(s, m, "Redirect successful");
5333 } else {
5334 astman_send_error(s, m, "Redirect failed");
5335 }
5336 chan = ast_channel_unref(chan);
5337 return 0;
5338 }
5339
5340 chan2 = ast_channel_get_by_name(name2);
5341 if (!chan2) {
5342 snprintf(buf, sizeof(buf), "ExtraChannel does not exist: %s", name2);
5343 astman_send_error(s, m, buf);
5344 chan = ast_channel_unref(chan);
5345 return 0;
5346 }
5347 if (ast_check_hangup_locked(chan2)) {
5348 astman_send_error(s, m, "Redirect failed, extra channel not up.");
5349 chan2 = ast_channel_unref(chan2);
5350 chan = ast_channel_unref(chan);
5351 return 0;
5352 }
5353
5354 /* Dual channel redirect in progress. */
5355 ast_channel_lock(chan);
5356 if (ast_channel_is_bridged(chan)) {
5358 chan1_wait = 1;
5359 }
5360 ast_channel_unlock(chan);
5361
5362 ast_channel_lock(chan2);
5363 if (ast_channel_is_bridged(chan2)) {
5365 chan2_wait = 1;
5366 }
5367 ast_channel_unlock(chan2);
5368
5369 res = ast_async_goto(chan, context, exten, pi);
5370 if (!res) {
5371 if (!ast_strlen_zero(context2)) {
5372 res = ast_async_goto(chan2, context2, exten2, pi2);
5373 } else {
5374 res = ast_async_goto(chan2, context, exten, pi);
5375 }
5376 if (!res) {
5377 astman_send_ack(s, m, "Dual Redirect successful");
5378 } else {
5379 astman_send_error(s, m, "Secondary redirect failed");
5380 }
5381 } else {
5382 astman_send_error(s, m, "Redirect failed");
5383 }
5384
5385 /* Release the bridge wait. */
5386 if (chan1_wait) {
5388 }
5389 if (chan2_wait) {
5391 }
5392
5393 chan2 = ast_channel_unref(chan2);
5394 chan = ast_channel_unref(chan);
5395 return 0;
5396}
5397
5398static int action_blind_transfer(struct mansession *s, const struct message *m)
5399{
5400 const char *name = astman_get_header(m, "Channel");
5401 const char *exten = astman_get_header(m, "Exten");
5402 const char *context = astman_get_header(m, "Context");
5403 struct ast_channel *chan;
5404
5405 if (ast_strlen_zero(name)) {
5406 astman_send_error(s, m, "No channel specified");
5407 return 0;
5408 }
5409
5410 if (ast_strlen_zero(exten)) {
5411 astman_send_error(s, m, "No extension specified");
5412 return 0;
5413 }
5414
5416 if (!chan) {
5417 astman_send_error(s, m, "Channel specified does not exist");
5418 return 0;
5419 }
5420
5421 if (ast_strlen_zero(context)) {
5423 }
5424
5425 switch (ast_bridge_transfer_blind(1, chan, exten, context, NULL, NULL)) {
5427 astman_send_error(s, m, "Transfer not permitted");
5428 break;
5430 astman_send_error(s, m, "Transfer invalid");
5431 break;
5433 astman_send_error(s, m, "Transfer failed");
5434 break;
5436 astman_send_ack(s, m, "Transfer succeeded");
5437 break;
5438 }
5439
5440 ast_channel_unref(chan);
5441 return 0;
5442}
5443
5444static int action_atxfer(struct mansession *s, const struct message *m)
5445{
5446 const char *name = astman_get_header(m, "Channel");
5447 const char *exten = astman_get_header(m, "Exten");
5448 const char *context = astman_get_header(m, "Context");
5449 struct ast_channel *chan = NULL;
5450 char feature_code[AST_FEATURE_MAX_LEN];
5451 const char *digit;
5452
5453 if (ast_strlen_zero(name)) {
5454 astman_send_error(s, m, "No channel specified");
5455 return 0;
5456 }
5457 if (ast_strlen_zero(exten)) {
5458 astman_send_error(s, m, "No extension specified");
5459 return 0;
5460 }
5461
5462 if (!(chan = ast_channel_get_by_name(name))) {
5463 astman_send_error(s, m, "Channel specified does not exist");
5464 return 0;
5465 }
5466
5467 ast_channel_lock(chan);
5468 if (ast_get_builtin_feature(chan, "atxfer", feature_code, sizeof(feature_code)) ||
5469 ast_strlen_zero(feature_code)) {
5470 ast_channel_unlock(chan);
5471 astman_send_error(s, m, "No attended transfer feature code found");
5472 ast_channel_unref(chan);
5473 return 0;
5474 }
5475 ast_channel_unlock(chan);
5476
5477 if (!ast_strlen_zero(context)) {
5478 pbx_builtin_setvar_helper(chan, "TRANSFER_CONTEXT", context);
5479 }
5480
5481 for (digit = feature_code; *digit; ++digit) {
5482 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
5483 ast_queue_frame(chan, &f);
5484 }
5485
5486 for (digit = exten; *digit; ++digit) {
5487 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
5488 ast_queue_frame(chan, &f);
5489 }
5490
5491 chan = ast_channel_unref(chan);
5492
5493 astman_send_ack(s, m, "Atxfer successfully queued");
5494
5495 return 0;
5496}
5497
5498static int action_cancel_atxfer(struct mansession *s, const struct message *m)
5499{
5500 const char *name = astman_get_header(m, "Channel");
5501 struct ast_channel *chan = NULL;
5502 char *feature_code;
5503 const char *digit;
5504
5505 if (ast_strlen_zero(name)) {
5506 astman_send_error(s, m, "No channel specified");
5507 return 0;
5508 }
5509
5510 if (!(chan = ast_channel_get_by_name(name))) {
5511 astman_send_error(s, m, "Channel specified does not exist");
5512 return 0;
5513 }
5514
5515 ast_channel_lock(chan);
5516 feature_code = ast_get_chan_features_atxferabort(chan);
5517 ast_channel_unlock(chan);
5518
5519 if (!feature_code) {
5520 astman_send_error(s, m, "No disconnect feature code found");
5521 ast_channel_unref(chan);
5522 return 0;
5523 }
5524
5525 for (digit = feature_code; *digit; ++digit) {
5526 struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
5527 ast_queue_frame(chan, &f);
5528 }
5529 ast_free(feature_code);
5530
5531 chan = ast_channel_unref(chan);
5532
5533 astman_send_ack(s, m, "CancelAtxfer successfully queued");
5534
5535 return 0;
5536}
5537
5538
5539static int check_blacklist(const char *cmd)
5540{
5541 char *cmd_copy, *cur_cmd;
5542 char *cmd_words[AST_MAX_CMD_LEN] = { NULL, };
5543 int i;
5544
5545 cmd_copy = ast_strdupa(cmd);
5546 for (i = 0; i < MAX_BLACKLIST_CMD_LEN && (cur_cmd = strsep(&cmd_copy, " ")); i++) {
5547 cur_cmd = ast_strip(cur_cmd);
5548 if (ast_strlen_zero(cur_cmd)) {
5549 i--;
5550 continue;
5551 }
5552
5553 cmd_words[i] = cur_cmd;
5554 }
5555
5556 for (i = 0; i < ARRAY_LEN(command_blacklist); i++) {
5557 int j, match = 1;
5558
5559 for (j = 0; command_blacklist[i].words[j]; j++) {
5560 if (ast_strlen_zero(cmd_words[j]) || strcasecmp(cmd_words[j], command_blacklist[i].words[j])) {
5561 match = 0;
5562 break;
5563 }
5564 }
5565
5566 if (match) {
5567 return 1;
5568 }
5569 }
5570
5571 return 0;
5572}
5573
5574/*! \brief Manager command "command" - execute CLI command */
5575static int action_command(struct mansession *s, const struct message *m)
5576{
5577 const char *cmd = astman_get_header(m, "Command");
5578 char *buf = NULL, *final_buf = NULL, *delim, *output;
5579 char template[] = "/tmp/ast-ami-XXXXXX"; /* template for temporary file */
5580 int fd, ret;
5581 off_t len;
5582
5583 if (ast_strlen_zero(cmd)) {
5584 astman_send_error(s, m, "No command provided");
5585 return 0;
5586 }
5587
5588 if (check_blacklist(cmd)) {
5589 astman_send_error(s, m, "Command blacklisted");
5590 return 0;
5591 }
5592
5593 if ((fd = mkstemp(template)) < 0) {
5594 astman_send_error_va(s, m, "Failed to create temporary file: %s", strerror(errno));
5595 return 0;
5596 }
5597
5598 ret = ast_cli_command(fd, cmd);
5599 astman_send_response_full(s, m, ret == RESULT_SUCCESS ? "Success" : "Error", MSG_MOREDATA, NULL);
5600
5601 /* Determine number of characters available */
5602 if ((len = lseek(fd, 0, SEEK_END)) < 0) {
5603 astman_append(s, "Message: Failed to determine number of characters: %s\r\n", strerror(errno));
5604 goto action_command_cleanup;
5605 }
5606
5607 /* This has a potential to overflow the stack. Hence, use the heap. */
5608 buf = ast_malloc(len + 1);
5609 final_buf = ast_malloc(len + 1);
5610
5611 if (!buf || !final_buf) {
5612 astman_append(s, "Message: Memory allocation failure\r\n");
5613 goto action_command_cleanup;
5614 }
5615
5616 if (lseek(fd, 0, SEEK_SET) < 0) {
5617 astman_append(s, "Message: Failed to set position on temporary file: %s\r\n", strerror(errno));
5618 goto action_command_cleanup;
5619 }
5620
5621 if (read(fd, buf, len) < 0) {
5622 astman_append(s, "Message: Failed to read from temporary file: %s\r\n", strerror(errno));
5623 goto action_command_cleanup;
5624 }
5625
5626 buf[len] = '\0';
5627 term_strip(final_buf, buf, len);
5628 final_buf[len] = '\0';
5629
5630 /* Trim trailing newline */
5631 if (len && final_buf[len - 1] == '\n') {
5632 final_buf[len - 1] = '\0';
5633 }
5634
5635 astman_append(s, "Message: Command output follows\r\n");
5636
5637 delim = final_buf;
5638 while ((output = strsep(&delim, "\n"))) {
5639 astman_append(s, "Output: %s\r\n", output);
5640 }
5641
5642action_command_cleanup:
5643 astman_append(s, "\r\n");
5644
5645 close(fd);
5646 unlink(template);
5647
5648 ast_free(buf);
5649 ast_free(final_buf);
5650
5651 return 0;
5652}
5653
5654/*! \brief helper function for originate */
5657 struct ast_format_cap *cap; /*!< Codecs used for a call */
5660 AST_STRING_FIELD(tech);
5661 /*! data can contain a channel name, extension number, username, password, etc. */
5662 AST_STRING_FIELD(data);
5664 AST_STRING_FIELD(appdata);
5665 AST_STRING_FIELD(cid_name);
5666 AST_STRING_FIELD(cid_num);
5668 AST_STRING_FIELD(exten);
5669 AST_STRING_FIELD(idtext);
5670 AST_STRING_FIELD(account);
5671 AST_STRING_FIELD(channelid);
5672 AST_STRING_FIELD(otherchannelid);
5676};
5677
5678/*!
5679 * \internal
5680 *
5681 * \param doomed Struct to destroy.
5682 */
5684{
5685 ao2_cleanup(doomed->cap);
5686 ast_variables_destroy(doomed->vars);
5688 ast_free(doomed);
5689}
5690
5691static void *fast_originate(void *data)
5692{
5693 struct fast_originate_helper *in = data;
5694 int res;
5695 int reason = 0;
5696 struct ast_channel *chan = NULL, *chans[1];
5697 char requested_channel[AST_CHANNEL_NAME];
5698 struct ast_assigned_ids assignedids = {
5699 .uniqueid = in->channelid,
5700 .uniqueid2 = in->otherchannelid
5701 };
5702
5703 if (!ast_strlen_zero(in->app)) {
5704 res = ast_pbx_outgoing_app(in->tech, in->cap, in->data,
5705 in->timeout, in->app, in->appdata, &reason,
5707 S_OR(in->cid_num, NULL),
5708 S_OR(in->cid_name, NULL),
5709 in->vars, in->account, &chan, &assignedids);
5710 } else {
5711 res = ast_pbx_outgoing_exten(in->tech, in->cap, in->data,
5712 in->timeout, in->context, in->exten, in->priority, &reason,
5714 S_OR(in->cid_num, NULL),
5715 S_OR(in->cid_name, NULL),
5716 in->vars, in->account, &chan, in->early_media, &assignedids);
5717 }
5718
5719 if (!chan) {
5720 snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
5721 }
5722 /* Tell the manager what happened with the channel */
5723 chans[0] = chan;
5724 if (!ast_strlen_zero(in->app)) {
5725 ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans,
5726 "%s"
5727 "Response: %s\r\n"
5728 "Channel: %s\r\n"
5729 "Application: %s\r\n"
5730 "Data: %s\r\n"
5731 "Reason: %d\r\n"
5732 "Uniqueid: %s\r\n"
5733 "CallerIDNum: %s\r\n"
5734 "CallerIDName: %s\r\n",
5735 in->idtext, res ? "Failure" : "Success",
5736 chan ? ast_channel_name(chan) : requested_channel,
5737 in->app, in->appdata, reason,
5738 chan ? ast_channel_uniqueid(chan) : S_OR(in->channelid, "<unknown>"),
5739 S_OR(in->cid_num, "<unknown>"),
5740 S_OR(in->cid_name, "<unknown>")
5741 );
5742 } else {
5743 ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans,
5744 "%s"
5745 "Response: %s\r\n"
5746 "Channel: %s\r\n"
5747 "Context: %s\r\n"
5748 "Exten: %s\r\n"
5749 "Reason: %d\r\n"
5750 "Uniqueid: %s\r\n"
5751 "CallerIDNum: %s\r\n"
5752 "CallerIDName: %s\r\n",
5753 in->idtext, res ? "Failure" : "Success",
5754 chan ? ast_channel_name(chan) : requested_channel,
5755 in->context, in->exten, reason,
5756 chan ? ast_channel_uniqueid(chan) : S_OR(in->channelid, "<unknown>"),
5757 S_OR(in->cid_num, "<unknown>"),
5758 S_OR(in->cid_name, "<unknown>")
5759 );
5760 }
5761
5762 /* Locked and ref'd by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
5763 if (chan) {
5764 ast_channel_unlock(chan);
5765 ast_channel_unref(chan);
5766 }
5768 return NULL;
5769}
5770
5771static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
5772{
5773 const char *unitamount;
5774 const char *unittype;
5775 struct ast_str *str = ast_str_alloca(32);
5776
5777 memset(entry, 0, sizeof(*entry));
5778
5779 ast_str_set(&str, 0, "UnitAmount(%u)", entry_num);
5780 unitamount = astman_get_header(m, ast_str_buffer(str));
5781
5782 ast_str_set(&str, 0, "UnitType(%u)", entry_num);
5783 unittype = astman_get_header(m, ast_str_buffer(str));
5784
5785 if (!ast_strlen_zero(unitamount) && (sscanf(unitamount, "%30u", &entry->amount) == 1)) {
5786 entry->valid_amount = 1;
5787 }
5788
5789 if (!ast_strlen_zero(unittype) && sscanf(unittype, "%30u", &entry->type) == 1) {
5790 entry->valid_type = 1;
5791 }
5792
5793 return 0;
5794}
5795
5796static struct ast_aoc_decoded *action_aoc_de_message(struct mansession *s, const struct message *m)
5797{
5798 const char *msgtype = astman_get_header(m, "MsgType");
5799 const char *chargetype = astman_get_header(m, "ChargeType");
5800 const char *currencyname = astman_get_header(m, "CurrencyName");
5801 const char *currencyamount = astman_get_header(m, "CurrencyAmount");
5802 const char *mult = astman_get_header(m, "CurrencyMultiplier");
5803 const char *totaltype = astman_get_header(m, "TotalType");
5804 const char *aocbillingid = astman_get_header(m, "AOCBillingId");
5805 const char *association_id= astman_get_header(m, "ChargingAssociationId");
5806 const char *association_num = astman_get_header(m, "ChargingAssociationNumber");
5807 const char *association_plan = astman_get_header(m, "ChargingAssociationPlan");
5808
5809 enum ast_aoc_type _msgtype;
5810 enum ast_aoc_charge_type _chargetype;
5812 enum ast_aoc_total_type _totaltype = AST_AOC_TOTAL;
5813 enum ast_aoc_billing_id _billingid = AST_AOC_BILLING_NA;
5814 unsigned int _currencyamount = 0;
5815 int _association_id = 0;
5816 unsigned int _association_plan = 0;
5817
5818 struct ast_aoc_decoded *decoded = NULL;
5819
5820 if (ast_strlen_zero(chargetype)) {
5821 astman_send_error(s, m, "ChargeType not specified");
5822 goto aocmessage_cleanup;
5823 }
5824
5825 _msgtype = strcasecmp(msgtype, "d") ? AST_AOC_E : AST_AOC_D;
5826
5827 if (!strcasecmp(chargetype, "NA")) {
5828 _chargetype = AST_AOC_CHARGE_NA;
5829 } else if (!strcasecmp(chargetype, "Free")) {
5830 _chargetype = AST_AOC_CHARGE_FREE;
5831 } else if (!strcasecmp(chargetype, "Currency")) {
5832 _chargetype = AST_AOC_CHARGE_CURRENCY;
5833 } else if (!strcasecmp(chargetype, "Unit")) {
5834 _chargetype = AST_AOC_CHARGE_UNIT;
5835 } else {
5836 astman_send_error(s, m, "Invalid ChargeType");
5837 goto aocmessage_cleanup;
5838 }
5839
5840 if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
5841
5842 if (ast_strlen_zero(currencyamount) || (sscanf(currencyamount, "%30u", &_currencyamount) != 1)) {
5843 astman_send_error(s, m, "Invalid CurrencyAmount, CurrencyAmount is a required when ChargeType is Currency");
5844 goto aocmessage_cleanup;
5845 }
5846
5847 if (ast_strlen_zero(mult)) {
5848 astman_send_error(s, m, "ChargeMultiplier unspecified, ChargeMultiplier is required when ChargeType is Currency.");
5849 goto aocmessage_cleanup;
5850 } else if (!strcasecmp(mult, "onethousandth")) {
5852 } else if (!strcasecmp(mult, "onehundredth")) {
5854 } else if (!strcasecmp(mult, "onetenth")) {
5855 _mult = AST_AOC_MULT_ONETENTH;
5856 } else if (!strcasecmp(mult, "one")) {
5857 _mult = AST_AOC_MULT_ONE;
5858 } else if (!strcasecmp(mult, "ten")) {
5859 _mult = AST_AOC_MULT_TEN;
5860 } else if (!strcasecmp(mult, "hundred")) {
5861 _mult = AST_AOC_MULT_HUNDRED;
5862 } else if (!strcasecmp(mult, "thousand")) {
5863 _mult = AST_AOC_MULT_THOUSAND;
5864 } else {
5865 astman_send_error(s, m, "Invalid ChargeMultiplier");
5866 goto aocmessage_cleanup;
5867 }
5868 }
5869
5870 /* create decoded object and start setting values */
5871 if (!(decoded = ast_aoc_create(_msgtype, _chargetype, 0))) {
5872 astman_send_error(s, m, "Message Creation Failed");
5873 goto aocmessage_cleanup;
5874 }
5875
5876 if (_msgtype == AST_AOC_D) {
5877 if (!ast_strlen_zero(totaltype) && !strcasecmp(totaltype, "subtotal")) {
5878 _totaltype = AST_AOC_SUBTOTAL;
5879 }
5880
5881 if (ast_strlen_zero(aocbillingid)) {
5882 /* ignore this is optional */
5883 } else if (!strcasecmp(aocbillingid, "Normal")) {
5884 _billingid = AST_AOC_BILLING_NORMAL;
5885 } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
5886 _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
5887 } else if (!strcasecmp(aocbillingid, "CreditCard")) {
5888 _billingid = AST_AOC_BILLING_CREDIT_CARD;
5889 } else {
5890 astman_send_error(s, m, "Invalid AOC-D AOCBillingId");
5891 goto aocmessage_cleanup;
5892 }
5893 } else {
5894 if (ast_strlen_zero(aocbillingid)) {
5895 /* ignore this is optional */
5896 } else if (!strcasecmp(aocbillingid, "Normal")) {
5897 _billingid = AST_AOC_BILLING_NORMAL;
5898 } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
5899 _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
5900 } else if (!strcasecmp(aocbillingid, "CreditCard")) {
5901 _billingid = AST_AOC_BILLING_CREDIT_CARD;
5902 } else if (!strcasecmp(aocbillingid, "CallFwdUnconditional")) {
5904 } else if (!strcasecmp(aocbillingid, "CallFwdBusy")) {
5905 _billingid = AST_AOC_BILLING_CALL_FWD_BUSY;
5906 } else if (!strcasecmp(aocbillingid, "CallFwdNoReply")) {
5908 } else if (!strcasecmp(aocbillingid, "CallDeflection")) {
5910 } else if (!strcasecmp(aocbillingid, "CallTransfer")) {
5911 _billingid = AST_AOC_BILLING_CALL_TRANSFER;
5912 } else {
5913 astman_send_error(s, m, "Invalid AOC-E AOCBillingId");
5914 goto aocmessage_cleanup;
5915 }
5916
5917 if (!ast_strlen_zero(association_id) && (sscanf(association_id, "%30d", &_association_id) != 1)) {
5918 astman_send_error(s, m, "Invalid ChargingAssociationId");
5919 goto aocmessage_cleanup;
5920 }
5921 if (!ast_strlen_zero(association_plan) && (sscanf(association_plan, "%30u", &_association_plan) != 1)) {
5922 astman_send_error(s, m, "Invalid ChargingAssociationPlan");
5923 goto aocmessage_cleanup;
5924 }
5925
5926 if (_association_id) {
5927 ast_aoc_set_association_id(decoded, _association_id);
5928 } else if (!ast_strlen_zero(association_num)) {
5929 ast_aoc_set_association_number(decoded, association_num, _association_plan);
5930 }
5931 }
5932
5933 if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
5934 ast_aoc_set_currency_info(decoded, _currencyamount, _mult, ast_strlen_zero(currencyname) ? NULL : currencyname);
5935 } else if (_chargetype == AST_AOC_CHARGE_UNIT) {
5937 int i;
5938
5939 /* multiple unit entries are possible, lets get them all */
5940 for (i = 0; i < 32; i++) {
5941 if (aocmessage_get_unit_entry(m, &entry, i)) {
5942 break; /* that's the end then */
5943 }
5944
5945 ast_aoc_add_unit_entry(decoded, entry.valid_amount, entry.amount, entry.valid_type, entry.type);
5946 }
5947
5948 /* at least one unit entry is required */
5949 if (!i) {
5950 astman_send_error(s, m, "Invalid UnitAmount(0), At least one valid unit entry is required when ChargeType is set to Unit");
5951 goto aocmessage_cleanup;
5952 }
5953
5954 }
5955
5956 ast_aoc_set_billing_id(decoded, _billingid);
5957 ast_aoc_set_total_type(decoded, _totaltype);
5958
5959 return decoded;
5960
5961aocmessage_cleanup:
5962
5963 ast_aoc_destroy_decoded(decoded);
5964 return NULL;
5965}
5966
5967static int action_aoc_s_submessage(struct mansession *s, const struct message *m,
5968 struct ast_aoc_decoded *decoded)
5969{
5970 const char *chargeditem = __astman_get_header(m, "ChargedItem", GET_HEADER_LAST_MATCH);
5971 const char *ratetype = __astman_get_header(m, "RateType", GET_HEADER_LAST_MATCH);
5972 const char *currencyname = __astman_get_header(m, "CurrencyName", GET_HEADER_LAST_MATCH);
5973 const char *currencyamount = __astman_get_header(m, "CurrencyAmount", GET_HEADER_LAST_MATCH);
5974 const char *mult = __astman_get_header(m, "CurrencyMultiplier", GET_HEADER_LAST_MATCH);
5975 const char *time = __astman_get_header(m, "Time", GET_HEADER_LAST_MATCH);
5976 const char *timescale = __astman_get_header(m, "TimeScale", GET_HEADER_LAST_MATCH);
5977 const char *granularity = __astman_get_header(m, "Granularity", GET_HEADER_LAST_MATCH);
5978 const char *granularitytimescale = __astman_get_header(m, "GranularityTimeScale", GET_HEADER_LAST_MATCH);
5979 const char *chargingtype = __astman_get_header(m, "ChargingType", GET_HEADER_LAST_MATCH);
5980 const char *volumeunit = __astman_get_header(m, "VolumeUnit", GET_HEADER_LAST_MATCH);
5981 const char *code = __astman_get_header(m, "Code", GET_HEADER_LAST_MATCH);
5982
5983 enum ast_aoc_s_charged_item _chargeditem;
5984 enum ast_aoc_s_rate_type _ratetype;
5986 unsigned int _currencyamount = 0;
5987 unsigned int _code;
5988 unsigned int _time = 0;
5989 enum ast_aoc_time_scale _scale = 0;
5990 unsigned int _granularity = 0;
5991 enum ast_aoc_time_scale _granularity_time_scale = AST_AOC_TIME_SCALE_MINUTE;
5992 int _step = 0;
5993 enum ast_aoc_volume_unit _volumeunit = 0;
5994
5995 if (ast_strlen_zero(chargeditem)) {
5996 astman_send_error(s, m, "ChargedItem not specified");
5997 goto aocmessage_cleanup;
5998 }
5999
6000 if (ast_strlen_zero(ratetype)) {
6001 astman_send_error(s, m, "RateType not specified");
6002 goto aocmessage_cleanup;
6003 }
6004
6005 if (!strcasecmp(chargeditem, "NA")) {
6006 _chargeditem = AST_AOC_CHARGED_ITEM_NA;
6007 } else if (!strcasecmp(chargeditem, "SpecialArrangement")) {
6009 } else if (!strcasecmp(chargeditem, "BasicCommunication")) {
6011 } else if (!strcasecmp(chargeditem, "CallAttempt")) {
6012 _chargeditem = AST_AOC_CHARGED_ITEM_CALL_ATTEMPT;
6013 } else if (!strcasecmp(chargeditem, "CallSetup")) {
6014 _chargeditem = AST_AOC_CHARGED_ITEM_CALL_SETUP;
6015 } else if (!strcasecmp(chargeditem, "UserUserInfo")) {
6017 } else if (!strcasecmp(chargeditem, "SupplementaryService")) {
6019 } else {
6020 astman_send_error(s, m, "Invalid ChargedItem");
6021 goto aocmessage_cleanup;
6022 }
6023
6024 if (!strcasecmp(ratetype, "NA")) {
6025 _ratetype = AST_AOC_RATE_TYPE_NA;
6026 } else if (!strcasecmp(ratetype, "Free")) {
6027 _ratetype = AST_AOC_RATE_TYPE_FREE;
6028 } else if (!strcasecmp(ratetype, "FreeFromBeginning")) {
6030 } else if (!strcasecmp(ratetype, "Duration")) {
6031 _ratetype = AST_AOC_RATE_TYPE_DURATION;
6032 } else if (!strcasecmp(ratetype, "Flat")) {
6033 _ratetype = AST_AOC_RATE_TYPE_FLAT;
6034 } else if (!strcasecmp(ratetype, "Volume")) {
6035 _ratetype = AST_AOC_RATE_TYPE_VOLUME;
6036 } else if (!strcasecmp(ratetype, "SpecialCode")) {
6038 } else {
6039 astman_send_error(s, m, "Invalid RateType");
6040 goto aocmessage_cleanup;
6041 }
6042
6043 if (_ratetype > AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING) {
6044 if (ast_strlen_zero(currencyamount) || (sscanf(currencyamount, "%30u",
6045 &_currencyamount) != 1)) {
6046 astman_send_error(s, m, "Invalid CurrencyAmount, CurrencyAmount is a required when RateType is non-free");
6047 goto aocmessage_cleanup;
6048 }
6049
6050 if (ast_strlen_zero(mult)) {
6051 astman_send_error(s, m, "ChargeMultiplier unspecified, ChargeMultiplier is required when ChargeType is Currency.");
6052 goto aocmessage_cleanup;
6053 } else if (!strcasecmp(mult, "onethousandth")) {
6055 } else if (!strcasecmp(mult, "onehundredth")) {
6057 } else if (!strcasecmp(mult, "onetenth")) {
6058 _mult = AST_AOC_MULT_ONETENTH;
6059 } else if (!strcasecmp(mult, "one")) {
6060 _mult = AST_AOC_MULT_ONE;
6061 } else if (!strcasecmp(mult, "ten")) {
6062 _mult = AST_AOC_MULT_TEN;
6063 } else if (!strcasecmp(mult, "hundred")) {
6064 _mult = AST_AOC_MULT_HUNDRED;
6065 } else if (!strcasecmp(mult, "thousand")) {
6066 _mult = AST_AOC_MULT_THOUSAND;
6067 } else {
6068 astman_send_error(s, m, "Invalid ChargeMultiplier");
6069 goto aocmessage_cleanup;
6070 }
6071 }
6072
6073 if (_ratetype == AST_AOC_RATE_TYPE_DURATION) {
6074 if (ast_strlen_zero(timescale)) {
6075 astman_send_error(s, m, "TimeScale unspecified, TimeScale is required when RateType is Duration.");
6076 goto aocmessage_cleanup;
6077 } else if (!strcasecmp(timescale, "onehundredthsecond")) {
6079 } else if (!strcasecmp(timescale, "onetenthsecond")) {
6081 } else if (!strcasecmp(timescale, "second")) {
6083 } else if (!strcasecmp(timescale, "tenseconds")) {
6085 } else if (!strcasecmp(timescale, "minute")) {
6087 } else if (!strcasecmp(timescale, "hour")) {
6088 _scale = AST_AOC_TIME_SCALE_HOUR;
6089 } else if (!strcasecmp(timescale, "day")) {
6090 _scale = AST_AOC_TIME_SCALE_DAY;
6091 } else {
6092 astman_send_error(s, m, "Invalid TimeScale");
6093 goto aocmessage_cleanup;
6094 }
6095
6096 if (ast_strlen_zero(time) || (sscanf(time, "%30u", &_time) != 1)) {
6097 astman_send_error(s, m, "Invalid Time, Time is a required when RateType is Duration");
6098 goto aocmessage_cleanup;
6099 }
6100
6101 if (!ast_strlen_zero(granularity)) {
6102 if ((sscanf(time, "%30u", &_granularity) != 1)) {
6103 astman_send_error(s, m, "Invalid Granularity");
6104 goto aocmessage_cleanup;
6105 }
6106
6107 if (ast_strlen_zero(granularitytimescale)) {
6108 astman_send_error(s, m, "Invalid GranularityTimeScale, GranularityTimeScale is a required when Granularity is specified");
6109 } else if (!strcasecmp(granularitytimescale, "onehundredthsecond")) {
6110 _granularity_time_scale = AST_AOC_TIME_SCALE_HUNDREDTH_SECOND;
6111 } else if (!strcasecmp(granularitytimescale, "onetenthsecond")) {
6112 _granularity_time_scale = AST_AOC_TIME_SCALE_TENTH_SECOND;
6113 } else if (!strcasecmp(granularitytimescale, "second")) {
6114 _granularity_time_scale = AST_AOC_TIME_SCALE_SECOND;
6115 } else if (!strcasecmp(granularitytimescale, "tenseconds")) {
6116 _granularity_time_scale = AST_AOC_TIME_SCALE_TEN_SECOND;
6117 } else if (!strcasecmp(granularitytimescale, "minute")) {
6118 _granularity_time_scale = AST_AOC_TIME_SCALE_MINUTE;
6119 } else if (!strcasecmp(granularitytimescale, "hour")) {
6120 _granularity_time_scale = AST_AOC_TIME_SCALE_HOUR;
6121 } else if (!strcasecmp(granularitytimescale, "day")) {
6122 _granularity_time_scale = AST_AOC_TIME_SCALE_DAY;
6123 } else {
6124 astman_send_error(s, m, "Invalid GranularityTimeScale");
6125 goto aocmessage_cleanup;
6126 }
6127 }
6128
6129 if (ast_strlen_zero(chargingtype) || strcasecmp(chargingtype, "continuouscharging") == 0) {
6130 _step = 0;
6131 } else if (strcasecmp(chargingtype, "stepfunction") == 0 ) {
6132 _step = 1;
6133 } else {
6134 astman_send_error(s, m, "Invalid ChargingType");
6135 goto aocmessage_cleanup;
6136 }
6137 }
6138
6139 if (_ratetype == AST_AOC_RATE_TYPE_VOLUME) {
6140 if (ast_strlen_zero(volumeunit)) {
6141 astman_send_error(s, m, "VolumeUnit unspecified, VolumeUnit is required when RateType is Volume.");
6142 goto aocmessage_cleanup;
6143 } else if (!strcasecmp(timescale, "octet")) {
6144 _volumeunit = AST_AOC_VOLUME_UNIT_OCTET;
6145 } else if (!strcasecmp(timescale, "segment")) {
6146 _volumeunit = AST_AOC_VOLUME_UNIT_SEGMENT;
6147 } else if (!strcasecmp(timescale, "message")) {
6148 _volumeunit = AST_AOC_VOLUME_UNIT_MESSAGE;
6149 }else {
6150 astman_send_error(s, m, "Invalid VolumeUnit");
6151 goto aocmessage_cleanup;
6152 }
6153 }
6154
6156 || _ratetype == AST_AOC_RATE_TYPE_SPECIAL_CODE) {
6157 if (ast_strlen_zero(code) || (sscanf(code, "%30u", &_code) != 1)) {
6158 astman_send_error(s, m, "Invalid Code, Code is a required when ChargedItem is SpecialArrangement and when RateType is SpecialCode");
6159 goto aocmessage_cleanup;
6160 }
6161 }
6162
6163 if (_chargeditem == AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT) {
6164 ast_aoc_s_add_special_arrangement(decoded, _code);
6165 } else if (_ratetype == AST_AOC_RATE_TYPE_DURATION) {
6166 ast_aoc_s_add_rate_duration(decoded, _chargeditem, _currencyamount, _mult,
6167 currencyname, _time, _scale, _granularity, _granularity_time_scale, _step);
6168 } else if (_ratetype == AST_AOC_RATE_TYPE_FLAT) {
6169 ast_aoc_s_add_rate_flat(decoded, _chargeditem, _currencyamount, _mult,
6170 currencyname);
6171 } else if (_ratetype == AST_AOC_RATE_TYPE_VOLUME) {
6172 ast_aoc_s_add_rate_volume(decoded, _chargeditem, _volumeunit, _currencyamount,
6173 _mult, currencyname);
6174 } else if (_ratetype == AST_AOC_RATE_TYPE_SPECIAL_CODE) {
6175 ast_aoc_s_add_rate_special_charge_code(decoded, _chargeditem, _code);
6176 } else if (_ratetype == AST_AOC_RATE_TYPE_FREE) {
6177 ast_aoc_s_add_rate_free(decoded, _chargeditem, 0);
6178 } else if (_ratetype == AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING) {
6179 ast_aoc_s_add_rate_free(decoded, _chargeditem, 1);
6180 } else if (_ratetype == AST_AOC_RATE_TYPE_NA) {
6181 ast_aoc_s_add_rate_na(decoded, _chargeditem);
6182 }
6183
6184 return 0;
6185
6186aocmessage_cleanup:
6187
6188 return -1;
6189}
6190
6192 const struct message *m)
6193{
6194 struct ast_aoc_decoded *decoded = NULL;
6195 int hdrlen;
6196 int x;
6197 static const char hdr[] = "ChargedItem:";
6198 struct message sm = { 0 };
6199 int rates = 0;
6200
6201 if (!(decoded = ast_aoc_create(AST_AOC_S, 0, 0))) {
6202 astman_send_error(s, m, "Message Creation Failed");
6203 goto aocmessage_cleanup;
6204 }
6205
6206 hdrlen = strlen(hdr);
6207 for (x = 0; x < m->hdrcount; x++) {
6208 if (strncasecmp(hdr, m->headers[x], hdrlen) == 0) {
6209 if (rates > ast_aoc_s_get_count(decoded)) {
6210 if (action_aoc_s_submessage(s, &sm, decoded) == -1) {
6211 goto aocmessage_cleanup;
6212 }
6213 }
6214 ++rates;
6215 }
6216
6217 sm.headers[sm.hdrcount] = m->headers[x];
6218 ++sm.hdrcount;
6219 }
6220 if (rates > ast_aoc_s_get_count(decoded)) {
6221 if (action_aoc_s_submessage(s, &sm, decoded) == -1) {
6222 goto aocmessage_cleanup;
6223 }
6224 }
6225
6226 return decoded;
6227
6228aocmessage_cleanup:
6229
6230 ast_aoc_destroy_decoded(decoded);
6231 return NULL;
6232}
6233
6234static int action_aocmessage(struct mansession *s, const struct message *m)
6235{
6236 const char *msgtype = astman_get_header(m, "MsgType");
6237 const char *channel = astman_get_header(m, "Channel");
6238 const char *pchannel = astman_get_header(m, "ChannelPrefix");
6239
6240 struct ast_channel *chan = NULL;
6241
6242 struct ast_aoc_decoded *decoded = NULL;
6243 struct ast_aoc_encoded *encoded = NULL;
6244 size_t encoded_size = 0;
6245
6246 if (ast_strlen_zero(channel) && ast_strlen_zero(pchannel)) {
6247 astman_send_error(s, m, "Channel and PartialChannel are not specified. Specify at least one of these.");
6248 goto aocmessage_cleanup;
6249 }
6250
6251 if (!(chan = ast_channel_get_by_name(channel)) && !ast_strlen_zero(pchannel)) {
6252 chan = ast_channel_get_by_name_prefix(pchannel, strlen(pchannel));
6253 }
6254
6255 if (!chan) {
6256 astman_send_error(s, m, "No such channel");
6257 goto aocmessage_cleanup;
6258 }
6259
6260 if (strcasecmp(msgtype, "d") == 0 || strcasecmp(msgtype, "e") == 0) {
6261 decoded = action_aoc_de_message(s, m);
6262 }
6263 else if (strcasecmp(msgtype, "s") == 0) {
6264 decoded = action_aoc_s_message(s, m);
6265 }
6266 else {
6267 astman_send_error(s, m, "Invalid MsgType");
6268 goto aocmessage_cleanup;
6269 }
6270
6271 if (!decoded) {
6272 goto aocmessage_cleanup;
6273 }
6274
6275 if ((encoded = ast_aoc_encode(decoded, &encoded_size, chan))
6276 && !ast_indicate_data(chan, AST_CONTROL_AOC, encoded, encoded_size)) {
6277 astman_send_ack(s, m, "AOC Message successfully queued on channel");
6278 } else {
6279 astman_send_error(s, m, "Error encoding AOC message, could not queue onto channel");
6280 }
6281
6282aocmessage_cleanup:
6283
6284 ast_aoc_destroy_decoded(decoded);
6285 ast_aoc_destroy_encoded(encoded);
6286
6287 if (chan) {
6288 chan = ast_channel_unref(chan);
6289 }
6290 return 0;
6291}
6292
6293static int action_originate(struct mansession *s, const struct message *m)
6294{
6295 const char *name = astman_get_header(m, "Channel");
6296 const char *exten = astman_get_header(m, "Exten");
6297 const char *context = astman_get_header(m, "Context");
6298 const char *priority = astman_get_header(m, "Priority");
6299 const char *timeout = astman_get_header(m, "Timeout");
6300 const char *callerid = astman_get_header(m, "CallerID");
6301 const char *account = astman_get_header(m, "Account");
6302 const char *app = astman_get_header(m, "Application");
6303 const char *appdata = astman_get_header(m, "Data");
6304 const char *async = astman_get_header(m, "Async");
6305 const char *id = astman_get_header(m, "ActionID");
6306 const char *codecs = astman_get_header(m, "Codecs");
6307 const char *early_media = astman_get_header(m, "Earlymedia");
6308 struct ast_assigned_ids assignedids = {
6309 .uniqueid = astman_get_header(m, "ChannelId"),
6310 .uniqueid2 = astman_get_header(m, "OtherChannelId"),
6311 };
6312 const char *gosub = astman_get_header(m, "PreDialGoSub");
6313
6314 struct ast_variable *vars = NULL;
6315 char *tech, *data;
6316 char *l = NULL, *n = NULL;
6317 int pi = 0;
6318 int res;
6319 int to = 30000;
6320 int reason = 0;
6321 char tmp[256];
6322 char tmp2[256];
6324 pthread_t th;
6325 int bridge_early = 0;
6326
6327 if (!cap) {
6328 astman_send_error(s, m, "Internal Error. Memory allocation failure.");
6329 return 0;
6330 }
6332
6333 if ((assignedids.uniqueid && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid))
6334 || (assignedids.uniqueid2 && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid2))) {
6335 astman_send_error_va(s, m, "Uniqueid length exceeds maximum of %d\n",
6337 res = 0;
6338 goto fast_orig_cleanup;
6339 }
6340
6341 if (ast_strlen_zero(name)) {
6342 astman_send_error(s, m, "Channel not specified");
6343 res = 0;
6344 goto fast_orig_cleanup;
6345 }
6346 if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
6347 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
6348 astman_send_error(s, m, "Invalid priority");
6349 res = 0;
6350 goto fast_orig_cleanup;
6351 }
6352 }
6353 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%30d", &to) != 1)) {
6354 astman_send_error(s, m, "Invalid timeout");
6355 res = 0;
6356 goto fast_orig_cleanup;
6357 }
6358 ast_copy_string(tmp, name, sizeof(tmp));
6359 tech = tmp;
6360 data = strchr(tmp, '/');
6361 if (!data) {
6362 astman_send_error(s, m, "Invalid channel");
6363 res = 0;
6364 goto fast_orig_cleanup;
6365 }
6366 *data++ = '\0';
6367 ast_copy_string(tmp2, callerid, sizeof(tmp2));
6368 ast_callerid_parse(tmp2, &n, &l);
6369 if (n) {
6370 if (ast_strlen_zero(n)) {
6371 n = NULL;
6372 }
6373 }
6374 if (l) {
6376 if (ast_strlen_zero(l)) {
6377 l = NULL;
6378 }
6379 }
6380 if (!ast_strlen_zero(codecs)) {
6383 }
6384
6385 if (!ast_strlen_zero(app) && s->session) {
6386 int bad_appdata = 0;
6387 /* To run the System application (or anything else that goes to
6388 * shell), you must have the additional System privilege */
6390 && (
6391 strcasestr(app, "system") || /* System(rm -rf /)
6392 TrySystem(rm -rf /) */
6393 strcasestr(app, "exec") || /* Exec(System(rm -rf /))
6394 TryExec(System(rm -rf /)) */
6395 strcasestr(app, "agi") || /* AGI(/bin/rm,-rf /)
6396 EAGI(/bin/rm,-rf /) */
6397 strcasestr(app, "mixmonitor") || /* MixMonitor(blah,,rm -rf) */
6398 strcasestr(app, "externalivr") || /* ExternalIVR(rm -rf) */
6399 strcasestr(app, "originate") || /* Originate(Local/1234,app,System,rm -rf) */
6400 (strstr(appdata, "SHELL") && (bad_appdata = 1)) || /* NoOp(${SHELL(rm -rf /)}) */
6401 (strstr(appdata, "EVAL") && (bad_appdata = 1)) /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
6402 )) {
6403 char error_buf[64];
6404 snprintf(error_buf, sizeof(error_buf), "Originate Access Forbidden: %s", bad_appdata ? "Data" : "Application");
6405 astman_send_error(s, m, error_buf);
6406 res = 0;
6407 goto fast_orig_cleanup;
6408 }
6409 }
6410
6411 /* Check early if the extension exists. If not, we need to bail out here. */
6412 if (exten && context && pi) {
6413 if (! ast_exists_extension(NULL, context, exten, pi, l)) {
6414 /* The extension does not exist. */
6415 astman_send_error(s, m, "Extension does not exist.");
6416 res = 0;
6417 goto fast_orig_cleanup;
6418 }
6419 }
6420
6421 /* Allocate requested channel variables */
6422 vars = astman_get_variables(m);
6423 if (s->session && s->session->chanvars) {
6424 struct ast_variable *v, *old;
6425 old = vars;
6426 vars = NULL;
6427
6428 /* The variables in the AMI originate action are appended at the end of the list, to override any user variables that apply */
6429
6431 if (old) {
6432 for (v = vars; v->next; v = v->next );
6433 v->next = old; /* Append originate variables at end of list */
6434 }
6435 }
6436
6437 /* For originate async - we can bridge in early media stage */
6438 bridge_early = ast_true(early_media);
6439
6440 if (ast_true(async)) {
6441 struct fast_originate_helper *fast;
6442
6443 fast = ast_calloc(1, sizeof(*fast));
6444 if (!fast || ast_string_field_init(fast, 252)) {
6445 ast_free(fast);
6447 res = -1;
6448 } else {
6449 if (!ast_strlen_zero(id)) {
6450 ast_string_field_build(fast, idtext, "ActionID: %s\r\n", id);
6451 }
6452 ast_string_field_set(fast, tech, tech);
6453 ast_string_field_set(fast, data, data);
6455 ast_string_field_set(fast, appdata, appdata);
6456 ast_string_field_set(fast, cid_num, l);
6457 ast_string_field_set(fast, cid_name, n);
6459 ast_string_field_set(fast, exten, exten);
6460 ast_string_field_set(fast, account, account);
6461 ast_string_field_set(fast, channelid, assignedids.uniqueid);
6462 ast_string_field_set(fast, otherchannelid, assignedids.uniqueid2);
6463 fast->vars = vars;
6464 fast->cap = cap;
6465 cap = NULL; /* transfered originate helper the capabilities structure. It is now responsible for freeing it. */
6466 fast->timeout = to;
6467 fast->early_media = bridge_early;
6468 fast->priority = pi;
6471 res = -1;
6472 } else {
6473 res = 0;
6474 }
6475 }
6476 } else if (!ast_strlen_zero(app)) {
6477 res = ast_pbx_outgoing_app(tech, cap, data, to, app, appdata, &reason,
6478 AST_OUTGOING_WAIT, l, n, vars, account, NULL,
6479 assignedids.uniqueid ? &assignedids : NULL);
6481 } else {
6482 if (exten && context && pi) {
6483 res = ast_pbx_outgoing_exten_predial(tech, cap, data, to,
6484 context, exten, pi, &reason, AST_OUTGOING_WAIT,
6485 l, n, vars, account, NULL, bridge_early,
6486 assignedids.uniqueid ? &assignedids : NULL , gosub);
6488 } else {
6489 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
6491 res = 0;
6492 goto fast_orig_cleanup;
6493 }
6494 }
6495 if (!res) {
6496 astman_send_ack(s, m, "Originate successfully queued");
6497 } else {
6498 astman_send_error(s, m, "Originate failed");
6499 }
6500
6501fast_orig_cleanup:
6502 ao2_cleanup(cap);
6503 return 0;
6504}
6505
6506static int action_mailboxstatus(struct mansession *s, const struct message *m)
6507{
6508 const char *mailbox = astman_get_header(m, "Mailbox");
6509 int ret;
6510
6511 if (ast_strlen_zero(mailbox)) {
6512 astman_send_error(s, m, "Mailbox not specified");
6513 return 0;
6514 }
6516 astman_start_ack(s, m);
6517 astman_append(s, "Message: Mailbox Status\r\n"
6518 "Mailbox: %s\r\n"
6519 "Waiting: %d\r\n\r\n", mailbox, ret);
6520 return 0;
6521}
6522
6523static int action_mailboxcount(struct mansession *s, const struct message *m)
6524{
6525 const char *mailbox = astman_get_header(m, "Mailbox");
6526 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;;
6527
6528 if (ast_strlen_zero(mailbox)) {
6529 astman_send_error(s, m, "Mailbox not specified");
6530 return 0;
6531 }
6532 ast_app_inboxcount2(mailbox, &urgentmsgs, &newmsgs, &oldmsgs);
6533 astman_start_ack(s, m);
6534 astman_append(s, "Message: Mailbox Message Count\r\n"
6535 "Mailbox: %s\r\n"
6536 "UrgMessages: %d\r\n"
6537 "NewMessages: %d\r\n"
6538 "OldMessages: %d\r\n"
6539 "\r\n",
6540 mailbox, urgentmsgs, newmsgs, oldmsgs);
6541 return 0;
6542}
6543
6544static int action_extensionstate(struct mansession *s, const struct message *m)
6545{
6546 const char *exten = astman_get_header(m, "Exten");
6547 const char *context = astman_get_header(m, "Context");
6548 char hint[256];
6549 int status;
6550
6551 if (ast_strlen_zero(exten)) {
6552 astman_send_error(s, m, "Extension not specified");
6553 return 0;
6554 }
6555 if (ast_strlen_zero(context)) {
6556 context = "default";
6557 }
6559 hint[0] = '\0';
6560 ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten);
6561 astman_start_ack(s, m);
6562 astman_append(s, "Message: Extension Status\r\n"
6563 "Exten: %s\r\n"
6564 "Context: %s\r\n"
6565 "Hint: %s\r\n"
6566 "Status: %d\r\n"
6567 "StatusText: %s\r\n"
6568 "\r\n",
6569 exten, context, hint, status,
6571 return 0;
6572}
6573
6574static int action_presencestate(struct mansession *s, const struct message *m)
6575{
6576 const char *provider = astman_get_header(m, "Provider");
6578 char *subtype;
6579 char *message;
6580
6582 astman_send_error(s, m, "No provider specified");
6583 return 0;
6584 }
6585
6587 if (state == AST_PRESENCE_INVALID) {
6588 astman_send_error_va(s, m, "Invalid provider %s or provider in invalid state", provider);
6589 return 0;
6590 }
6591
6592 astman_start_ack(s, m);
6593 astman_append(s, "Message: Presence State\r\n"
6594 "State: %s\r\n", ast_presence_state2str(state));
6595
6596 if (!ast_strlen_zero(subtype)) {
6597 astman_append(s, "Subtype: %s\r\n", subtype);
6598 }
6599
6600 if (!ast_strlen_zero(message)) {
6601 /* XXX The Message header here is deprecated as it
6602 * duplicates the action response header 'Message'.
6603 * Remove it in the next major revision of AMI.
6604 */
6605 astman_append(s, "Message: %s\r\n"
6606 "PresenceMessage: %s\r\n",
6607 message, message);
6608 }
6609 astman_append(s, "\r\n");
6610
6611 return 0;
6612}
6613
6614static int action_timeout(struct mansession *s, const struct message *m)
6615{
6616 struct ast_channel *c;
6617 const char *name = astman_get_header(m, "Channel");
6618 double timeout = atof(astman_get_header(m, "Timeout"));
6619 struct timeval when = { timeout, 0 };
6620
6621 if (ast_strlen_zero(name)) {
6622 astman_send_error(s, m, "No channel specified");
6623 return 0;
6624 }
6625
6626 if (!timeout || timeout < 0) {
6627 astman_send_error(s, m, "No timeout specified");
6628 return 0;
6629 }
6630
6631 if (!(c = ast_channel_get_by_name(name))) {
6632 astman_send_error(s, m, "No such channel");
6633 return 0;
6634 }
6635
6636 when.tv_usec = (timeout - when.tv_sec) * 1000000.0;
6637
6642
6643 astman_send_ack(s, m, "Timeout Set");
6644
6645 return 0;
6646}
6647
6648static int whitefilter_cmp_fn(void *obj, void *arg, void *data, int flags)
6649{
6650 regex_t *regex_filter = obj;
6651 const char *eventdata = arg;
6652 int *result = data;
6653
6654 if (!regexec(regex_filter, eventdata, 0, NULL, 0)) {
6655 *result = 1;
6656 return (CMP_MATCH | CMP_STOP);
6657 }
6658
6659 return 0;
6660}
6661
6662static int blackfilter_cmp_fn(void *obj, void *arg, void *data, int flags)
6663{
6664 regex_t *regex_filter = obj;
6665 const char *eventdata = arg;
6666 int *result = data;
6667
6668 if (!regexec(regex_filter, eventdata, 0, NULL, 0)) {
6669 *result = 0;
6670 return (CMP_MATCH | CMP_STOP);
6671 }
6672
6673 *result = 1;
6674 return 0;
6675}
6676
6677/*!
6678 * \brief Manager command to add an event filter to a manager session
6679 * \see For more details look at manager_add_filter
6680 */
6681static int action_filter(struct mansession *s, const struct message *m)
6682{
6683 const char *filter = astman_get_header(m, "Filter");
6684 const char *operation = astman_get_header(m, "Operation");
6685 int res;
6686
6687 if (!strcasecmp(operation, "Add")) {
6689
6690 if (res != FILTER_SUCCESS) {
6691 if (res == FILTER_ALLOC_FAILED) {
6692 astman_send_error(s, m, "Internal Error. Failed to allocate regex for filter");
6693 return 0;
6694 } else if (res == FILTER_COMPILE_FAIL) {
6695 astman_send_error(s, m, "Filter did not compile. Check the syntax of the filter given.");
6696 return 0;
6697 } else {
6698 astman_send_error(s, m, "Internal Error. Failed adding filter.");
6699 return 0;
6700 }
6701 }
6702
6703 astman_send_ack(s, m, "Success");
6704 return 0;
6705 }
6706
6707 astman_send_error(s, m, "Unknown operation");
6708 return 0;
6709}
6710
6711/*!
6712 * \brief Add an event filter to a manager session
6713 *
6714 * \param filter_pattern Filter syntax to add, see below for syntax
6715 * \param whitefilters, blackfilters
6716 *
6717 * \return FILTER_ALLOC_FAILED Memory allocation failure
6718 * \return FILTER_COMPILE_FAIL If the filter did not compile
6719 * \return FILTER_SUCCESS Success
6720 *
6721 * Filter will be used to match against each line of a manager event
6722 * Filter can be any valid regular expression
6723 * Filter can be a valid regular expression prefixed with !, which will add the filter as a black filter
6724 *
6725 * Examples:
6726 * \code
6727 * filter_pattern = "Event: Newchannel"
6728 * filter_pattern = "Event: New.*"
6729 * filter_pattern = "!Channel: DAHDI.*"
6730 * \endcode
6731 *
6732 */
6733static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters) {
6734 regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
6735 int is_blackfilter;
6736
6737 if (!new_filter) {
6738 return FILTER_ALLOC_FAILED;
6739 }
6740
6741 if (filter_pattern[0] == '!') {
6742 is_blackfilter = 1;
6743 filter_pattern++;
6744 } else {
6745 is_blackfilter = 0;
6746 }
6747
6748 if (regcomp(new_filter, filter_pattern, REG_EXTENDED | REG_NOSUB)) {
6749 ao2_t_ref(new_filter, -1, "failed to make regex");
6750 return FILTER_COMPILE_FAIL;
6751 }
6752
6753 if (is_blackfilter) {
6754 ao2_t_link(blackfilters, new_filter, "link new filter into black user container");
6755 } else {
6756 ao2_t_link(whitefilters, new_filter, "link new filter into white user container");
6757 }
6758
6759 ao2_ref(new_filter, -1);
6760
6761 return FILTER_SUCCESS;
6762}
6763
6764static int match_filter(struct mansession *s, char *eventdata)
6765{
6766 int result = 0;
6767
6768 if (manager_debug) {
6769 ast_verbose("<-- Examining AMI event: -->\n%s\n", eventdata);
6770 } else {
6771 ast_debug(4, "Examining AMI event:\n%s\n", eventdata);
6772 }
6774 return 1; /* no filtering means match all */
6776 /* white filters only: implied black all filter processed first, then white filters */
6777 ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
6779 /* black filters only: implied white all filter processed first, then black filters */
6780 ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
6781 } else {
6782 /* white and black filters: implied black all filter processed first, then white filters, and lastly black filters */
6783 ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
6784 if (result) {
6785 result = 0;
6786 ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
6787 }
6788 }
6789
6790 return result;
6791}
6792
6793/*!
6794 * Send any applicable events to the client listening on this socket.
6795 * Wait only for a finite time on each event, and drop all events whether
6796 * they are successfully sent or not.
6797 */
6798static int process_events(struct mansession *s)
6799{
6800 int ret = 0;
6801
6802 ao2_lock(s->session);
6803 if (s->session->stream != NULL) {
6804 struct eventqent *eqe = s->session->last_ev;
6805
6806 while ((eqe = advance_event(eqe))) {
6807 if (eqe->category == EVENT_FLAG_SHUTDOWN) {
6808 ast_debug(3, "Received CloseSession event\n");
6809 ret = -1;
6810 }
6811 if (!ret && s->session->authenticated &&
6812 (s->session->readperm & eqe->category) == eqe->category &&
6813 (s->session->send_events & eqe->category) == eqe->category) {
6814 if (match_filter(s, eqe->eventdata)) {
6815 if (send_string(s, eqe->eventdata) < 0 || s->write_error)
6816 ret = -1; /* don't send more */
6817 }
6818 }
6819 s->session->last_ev = eqe;
6820 }
6821 }
6822 ao2_unlock(s->session);
6823 return ret;
6824}
6825
6826static int action_userevent(struct mansession *s, const struct message *m)
6827{
6828 const char *event = astman_get_header(m, "UserEvent");
6829 struct ast_str *body = ast_str_thread_get(&userevent_buf, 16);
6830 int x;
6831
6832 ast_str_reset(body);
6833
6834 for (x = 0; x < m->hdrcount; x++) {
6835 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:")) &&
6836 strncasecmp("Action:", m->headers[x], strlen("Action:"))) {
6837 ast_str_append(&body, 0, "%s\r\n", m->headers[x]);
6838 }
6839 }
6840
6841 astman_send_ack(s, m, "Event Sent");
6842 manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, ast_str_buffer(body));
6843 return 0;
6844}
6845
6846/*! \brief Show PBX core settings information */
6847static int action_coresettings(struct mansession *s, const struct message *m)
6848{
6849 const char *actionid = astman_get_header(m, "ActionID");
6850 char idText[150];
6851
6852 if (!ast_strlen_zero(actionid)) {
6853 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
6854 } else {
6855 idText[0] = '\0';
6856 }
6857
6858 astman_append(s, "Response: Success\r\n"
6859 "%s"
6860 "AMIversion: %s\r\n"
6861 "AsteriskVersion: %s\r\n"
6862 "SystemName: %s\r\n"
6863 "CoreMaxCalls: %d\r\n"
6864 "CoreMaxLoadAvg: %f\r\n"
6865 "CoreRunUser: %s\r\n"
6866 "CoreRunGroup: %s\r\n"
6867 "CoreMaxFilehandles: %d\r\n"
6868 "CoreRealTimeEnabled: %s\r\n"
6869 "CoreCDRenabled: %s\r\n"
6870 "CoreHTTPenabled: %s\r\n"
6871 "SoundsSearchCustomDir: %s\r\n"
6872 "\r\n",
6873 idText,
6886 );
6887 return 0;
6888}
6889
6890/*! \brief Show PBX core status information */
6891static int action_corestatus(struct mansession *s, const struct message *m)
6892{
6893 const char *actionid = astman_get_header(m, "ActionID");
6894 char idText[150];
6895 char startuptime[150], startupdate[150];
6896 char reloadtime[150], reloaddate[150];
6897 struct ast_tm tm;
6898
6899 if (!ast_strlen_zero(actionid)) {
6900 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
6901 } else {
6902 idText[0] = '\0';
6903 }
6904
6906 ast_strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
6907 ast_strftime(startupdate, sizeof(startupdate), "%Y-%m-%d", &tm);
6909 ast_strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
6910 ast_strftime(reloaddate, sizeof(reloaddate), "%Y-%m-%d", &tm);
6911
6912 astman_append(s, "Response: Success\r\n"
6913 "%s"
6914 "CoreStartupDate: %s\r\n"
6915 "CoreStartupTime: %s\r\n"
6916 "CoreReloadDate: %s\r\n"
6917 "CoreReloadTime: %s\r\n"
6918 "CoreCurrentCalls: %d\r\n"
6919 "\r\n",
6920 idText,
6921 startupdate,
6922 startuptime,
6923 reloaddate,
6924 reloadtime,
6926 );
6927 return 0;
6928}
6929
6930/*! \brief Send a reload event */
6931static int action_reload(struct mansession *s, const struct message *m)
6932{
6933 const char *module = astman_get_header(m, "Module");
6935
6936 switch (res) {
6938 astman_send_error(s, m, "No such module");
6939 break;
6941 astman_send_error(s, m, "Module does not support reload");
6942 break;
6944 astman_send_error(s, m, "An unknown error occurred");
6945 break;
6947 astman_send_error(s, m, "A reload is in progress");
6948 break;
6950 astman_send_error(s, m, "Module not initialized");
6951 break;
6954 /* Treat a queued request as success */
6955 astman_send_ack(s, m, "Module Reloaded");
6956 break;
6957 }
6958 return 0;
6959}
6960
6961/*! \brief Manager command "CoreShowChannels" - List currently defined channels
6962 * and some information about them. */
6963static int action_coreshowchannels(struct mansession *s, const struct message *m)
6964{
6965 const char *actionid = astman_get_header(m, "ActionID");
6966 char idText[256];
6967 int numchans = 0;
6968 struct ao2_container *channels;
6969 struct ao2_iterator it_chans;
6970 struct ast_channel_snapshot *cs;
6971
6972 if (!ast_strlen_zero(actionid)) {
6973 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
6974 } else {
6975 idText[0] = '\0';
6976 }
6977
6979
6980 astman_send_listack(s, m, "Channels will follow", "start");
6981
6982 it_chans = ao2_iterator_init(channels, 0);
6983 for (; (cs = ao2_iterator_next(&it_chans)); ao2_ref(cs, -1)) {
6985 char durbuf[16] = "";
6986
6987 if (!built) {
6988 continue;
6989 }
6990
6991 if (!ast_tvzero(cs->base->creationtime)) {
6992 int duration, durh, durm, durs;
6993
6994 duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->base->creationtime) / 1000);
6995 durh = duration / 3600;
6996 durm = (duration % 3600) / 60;
6997 durs = duration % 60;
6998 snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
6999 }
7000
7001 astman_append(s,
7002 "Event: CoreShowChannel\r\n"
7003 "%s"
7004 "%s"
7005 "Application: %s\r\n"
7006 "ApplicationData: %s\r\n"
7007 "Duration: %s\r\n"
7008 "BridgeId: %s\r\n"
7009 "\r\n",
7010 idText,
7011 ast_str_buffer(built),
7012 cs->dialplan->appl,
7013 cs->dialplan->data,
7014 durbuf,
7015 cs->bridge->id);
7016
7017 numchans++;
7018
7019 ast_free(built);
7020 }
7021 ao2_iterator_destroy(&it_chans);
7022
7023 astman_send_list_complete(s, m, "CoreShowChannelsComplete", numchans);
7024
7025 ao2_ref(channels, -1);
7026 return 0;
7027}
7028
7029/*! \brief Helper function to add a channel name to the vector */
7030static int coreshowchannelmap_add_to_map(struct ao2_container *c, const char *s)
7031{
7032 char *str;
7033
7034 str = ast_strdup(s);
7035 if (!str) {
7036 ast_log(LOG_ERROR, "Unable to append channel to channel map\n");
7037 return 1;
7038 }
7039
7040 /* If this is a duplicate, it will be ignored */
7042
7043 return 0;
7044}
7045
7046/*! \brief Recursive function to get all channels in a bridge. Follow local channels as well */
7048 struct ast_channel_snapshot *channel_snapshot, struct ast_bridge_snapshot *bridge_snapshot)
7049{
7050 int res = 0;
7051 struct ao2_iterator iter;
7052 char *current_channel_uid;
7053
7054 iter = ao2_iterator_init(bridge_snapshot->channels, 0);
7055 while ((current_channel_uid = ao2_iterator_next(&iter))) {
7056 struct ast_channel_snapshot *current_channel_snapshot;
7057 int add_channel_res;
7058
7059 /* Don't add the original channel to the list - it's either already in there,
7060 * or it's the channel we want the map for */
7061 if (!strcmp(current_channel_uid, channel_snapshot->base->uniqueid)) {
7062 ao2_ref(current_channel_uid, -1);
7063 continue;
7064 }
7065
7066 current_channel_snapshot = ast_channel_snapshot_get_latest(current_channel_uid);
7067 if (!current_channel_snapshot) {
7068 ast_debug(5, "Unable to get channel snapshot\n");
7069 ao2_ref(current_channel_uid, -1);
7070 continue;
7071 }
7072
7073 add_channel_res = coreshowchannelmap_add_to_map(channel_map, current_channel_snapshot->base->name);
7074 if (add_channel_res) {
7075 res = 1;
7076 ao2_ref(current_channel_snapshot, -1);
7077 ao2_ref(current_channel_uid, -1);
7078 break;
7079 }
7080
7081 /* If this is a local channel that we haven't seen yet, let's go ahead and find out what else is connected to it */
7082 if (ast_begins_with(current_channel_snapshot->base->name, "Local")) {
7083 struct ast_channel_snapshot *other_local_snapshot;
7084 struct ast_bridge_snapshot *other_bridge_snapshot;
7085 int size = strlen(current_channel_snapshot->base->name);
7086 char other_local[size + 1];
7087
7088 /* Don't copy the trailing number - set it to 1 or 2, whichever one it currently is not */
7089 ast_copy_string(other_local, current_channel_snapshot->base->name, size);
7090 other_local[size - 1] = ast_ends_with(current_channel_snapshot->base->name, "1") ? '2' : '1';
7091 other_local[size] = '\0';
7092
7093 other_local_snapshot = ast_channel_snapshot_get_latest_by_name(other_local);
7094 if (!other_local_snapshot) {
7095 ast_debug(5, "Unable to get other local channel snapshot\n");
7096 ao2_ref(current_channel_snapshot, -1);
7097 ao2_ref(current_channel_uid, -1);
7098 continue;
7099 }
7100
7101 if (coreshowchannelmap_add_to_map(channel_map, other_local_snapshot->base->name)) {
7102 res = 1;
7103 ao2_ref(current_channel_snapshot, -1);
7104 ao2_ref(current_channel_uid, -1);
7105 ao2_ref(other_local_snapshot, -1);
7106 break;
7107 }
7108
7109 other_bridge_snapshot = ast_bridge_get_snapshot_by_uniqueid(other_local_snapshot->bridge->id);
7110 if (other_bridge_snapshot) {
7111 res = coreshowchannelmap_add_connected_channels(channel_map, other_local_snapshot, other_bridge_snapshot);
7112 }
7113
7114 ao2_ref(current_channel_snapshot, -1);
7115 ao2_ref(current_channel_uid, -1);
7116 ao2_ref(other_local_snapshot, -1);
7117 ao2_ref(other_bridge_snapshot, -1);
7118
7119 if (res) {
7120 break;
7121 }
7122 }
7123 }
7124 ao2_iterator_destroy(&iter);
7125
7126 return res;
7127}
7128
7129/*! \brief Manager command "CoreShowChannelMap" - Lists all channels connected to
7130 * the specified channel. */
7131static int action_coreshowchannelmap(struct mansession *s, const struct message *m)
7132{
7133 const char *actionid = astman_get_header(m, "ActionID");
7134 const char *channel_name = astman_get_header(m, "Channel");
7135 char *current_channel_name;
7136 char id_text[256];
7137 int total = 0;
7138 struct ao2_container *channel_map;
7139 struct ao2_iterator i;
7140 RAII_VAR(struct ast_bridge_snapshot *, bridge_snapshot, NULL, ao2_cleanup);
7141 RAII_VAR(struct ast_channel_snapshot *, channel_snapshot, NULL, ao2_cleanup);
7142
7143 if (!ast_strlen_zero(actionid)) {
7144 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", actionid);
7145 } else {
7146 id_text[0] = '\0';
7147 }
7148
7149 if (ast_strlen_zero(channel_name)) {
7150 astman_send_error(s, m, "CoreShowChannelMap requires a channel.\n");
7151 return 0;
7152 }
7153
7154 channel_snapshot = ast_channel_snapshot_get_latest_by_name(channel_name);
7155 if (!channel_snapshot) {
7156 astman_send_error(s, m, "Could not get channel snapshot\n");
7157 return 0;
7158 }
7159
7160 bridge_snapshot = ast_bridge_get_snapshot_by_uniqueid(channel_snapshot->bridge->id);
7161 if (!bridge_snapshot) {
7162 astman_send_listack(s, m, "Channel map will follow", "start");
7163 astman_send_list_complete_start(s, m, "CoreShowChannelMapComplete", 0);
7165 return 0;
7166 }
7167
7169 if (!channel_map) {
7170 astman_send_error(s, m, "Could not create channel map\n");
7171 return 0;
7172 }
7173
7174 astman_send_listack(s, m, "Channel map will follow", "start");
7175
7176 if (coreshowchannelmap_add_connected_channels(channel_map, channel_snapshot, bridge_snapshot)) {
7177 astman_send_error(s, m, "Could not complete channel map\n");
7178 ao2_ref(channel_map, -1);
7179 return 0;
7180 }
7181
7182 i = ao2_iterator_init(channel_map, 0);
7183 while ((current_channel_name = ao2_iterator_next(&i))) {
7184 astman_append(s,
7185 "Event: CoreShowChannelMap\r\n"
7186 "%s"
7187 "Channel: %s\r\n"
7188 "ConnectedChannel: %s\r\n\n",
7189 id_text,
7190 channel_name,
7191 current_channel_name);
7192 total++;
7193 }
7195
7196 ao2_ref(channel_map, -1);
7197 astman_send_list_complete_start(s, m, "CoreShowChannelMapComplete", total);
7199
7200 return 0;
7201}
7202
7203/*! \brief Manager command "LoggerRotate" - reloads and rotates the logger in
7204 * the same manner as the CLI command 'logger rotate'. */
7205static int action_loggerrotate(struct mansession *s, const struct message *m)
7206{
7207 if (ast_logger_rotate()) {
7208 astman_send_error(s, m, "Failed to reload the logger and rotate log files");
7209 return 0;
7210 }
7211
7212 astman_send_ack(s, m, "Reloaded the logger and rotated log files");
7213 return 0;
7214}
7215
7216/*! \brief Manager function to check if module is loaded */
7217static int manager_modulecheck(struct mansession *s, const struct message *m)
7218{
7219 const char *module = astman_get_header(m, "Module");
7220 const char *id = astman_get_header(m, "ActionID");
7221
7222 ast_debug(1, "**** ModuleCheck .so file %s\n", module);
7223 if (!ast_module_check(module)) {
7224 astman_send_error(s, m, "Module not loaded");
7225 return 0;
7226 }
7227
7228 astman_append(s, "Response: Success\r\n");
7229
7230 if (!ast_strlen_zero(id)) {
7231 astman_append(s, "ActionID: %s\r\n", id);
7232 }
7233
7234#if !defined(LOW_MEMORY)
7235 /* When we switched from subversion to git we lost the ability to
7236 * retrieve the 'ASTERISK_FILE_VERSION' from that file, but we retain
7237 * the response header here for backwards compatibility. */
7238 astman_append(s, "Version: \r\n");
7239#endif
7240
7241 astman_append(s, "\r\n");
7242
7243 return 0;
7244}
7245
7246static int manager_moduleload(struct mansession *s, const struct message *m)
7247{
7248 int res;
7249 const char *module = astman_get_header(m, "Module");
7250 const char *loadtype = astman_get_header(m, "LoadType");
7251
7252 if (!loadtype || strlen(loadtype) == 0) {
7253 astman_send_error(s, m, "Incomplete ModuleLoad action.");
7254 }
7255 if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0) {
7256 astman_send_error(s, m, "Need module name");
7257 }
7258
7259 if (!strcasecmp(loadtype, "load")) {
7260 res = ast_load_resource(module);
7261 if (res) {
7262 astman_send_error(s, m, "Could not load module.");
7263 } else {
7264 astman_send_ack(s, m, "Module loaded.");
7265 }
7266 } else if (!strcasecmp(loadtype, "unload")) {
7267 res = ast_unload_resource(module, AST_FORCE_SOFT);
7268 if (res) {
7269 astman_send_error(s, m, "Could not unload module.");
7270 } else {
7271 astman_send_ack(s, m, "Module unloaded.");
7272 }
7273 } else if (!strcasecmp(loadtype, "reload")) {
7274 /* TODO: Unify the ack/error messages here with action_reload */
7275 if (!ast_strlen_zero(module)) {
7276 enum ast_module_reload_result reload_res = ast_module_reload(module);
7277
7278 switch (reload_res) {
7280 astman_send_error(s, m, "No such module.");
7281 break;
7283 astman_send_error(s, m, "Module does not support reload action.");
7284 break;
7286 astman_send_error(s, m, "An unknown error occurred");
7287 break;
7289 astman_send_error(s, m, "A reload is in progress");
7290 break;
7292 astman_send_error(s, m, "Module not initialized");
7293 break;
7296 /* Treat a queued request as success */
7297 astman_send_ack(s, m, "Module reloaded.");
7298 break;
7299 }
7300 } else {
7301 ast_module_reload(NULL); /* Reload all modules */
7302 astman_send_ack(s, m, "All modules reloaded");
7303 }
7304 } else
7305 astman_send_error(s, m, "Incomplete ModuleLoad action.");
7306 return 0;
7307}
7308
7309static void log_action(const struct message *m, const char *action)
7310{
7311 struct ast_str *buf;
7312 int x;
7313
7314 if (!manager_debug) {
7315 return;
7316 }
7317
7318 buf = ast_str_create(256);
7319 if (!buf) {
7320 return;
7321 }
7322
7323 for (x = 0; x < m->hdrcount; ++x) {
7324 if (!strncasecmp(m->headers[x], "Secret", 6)) {
7325 ast_str_append(&buf, 0, "Secret: <redacted from logging>\n");
7326 } else {
7327 ast_str_append(&buf, 0, "%s\n", m->headers[x]);
7328 }
7329 }
7330
7331 ast_verbose("<--- Examining AMI action: -->\n%s\n", ast_str_buffer(buf));
7332 ast_free(buf);
7333}
7334
7335/*
7336 * Done with the action handlers here, we start with the code in charge
7337 * of accepting connections and serving them.
7338 * accept_thread() forks a new thread for each connection, session_do(),
7339 * which in turn calls get_input() repeatedly until a full message has
7340 * been accumulated, and then invokes process_message() to pass it to
7341 * the appropriate handler.
7342 */
7343
7344/*! \brief
7345 * Process an AMI message, performing desired action.
7346 * Return 0 on success, -1 on error that require the session to be destroyed.
7347 */
7348static int process_message(struct mansession *s, const struct message *m)
7349{
7350 int ret = 0;
7351 struct manager_action *act_found;
7352 struct ast_manager_user *user = NULL;
7353 const char *username;
7354 const char *action;
7355
7356 action = __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY);
7357 if (ast_strlen_zero(action)) {
7358 report_req_bad_format(s, "NONE");
7359 mansession_lock(s);
7360 astman_send_error(s, m, "Missing action in request");
7362 return 0;
7363 }
7364
7365 log_action(m, action);
7366
7367 if (ast_shutting_down()) {
7368 ast_log(LOG_ERROR, "Unable to process manager action '%s'. Asterisk is shutting down.\n", action);
7369 mansession_lock(s);
7370 astman_send_error(s, m, "Asterisk is shutting down");
7372 return 0;
7373 }
7374
7375 if (!s->session->authenticated
7376 && strcasecmp(action, "Login")
7377 && strcasecmp(action, "Logoff")
7378 && strcasecmp(action, "Challenge")) {
7379 if (!s->session->authenticated) {
7380 report_req_not_allowed(s, action);
7381 }
7382 mansession_lock(s);
7383 astman_send_error(s, m, "Permission denied");
7385 return 0;
7386 }
7387
7388 if (!s->session->authenticated
7389 && (!strcasecmp(action, "Login")
7390 || !strcasecmp(action, "Challenge"))) {
7391 username = astman_get_header(m, "Username");
7392
7393 if (!ast_strlen_zero(username) && check_manager_session_inuse(username)) {
7395 user = get_manager_by_name_locked(username);
7396 if (user && !user->allowmultiplelogin) {
7399 sleep(1);
7400 mansession_lock(s);
7401 astman_send_error(s, m, "Login Already In Use");
7403 return -1;
7404 }
7406 }
7407 }
7408
7409 act_found = action_find(action);
7410 if (act_found) {
7411 /* Found the requested AMI action. */
7412 int acted = 0;
7413
7414 if ((s->session->writeperm & act_found->authority)
7415 || act_found->authority == 0) {
7416 /* We have the authority to execute the action. */
7417 ret = -1;
7418 ao2_lock(act_found);
7419 if (act_found->registered && act_found->func) {
7420 struct ast_module *mod_ref = ast_module_running_ref(act_found->module);
7421
7422 ao2_unlock(act_found);
7423 if (mod_ref || !act_found->module) {
7424 ast_debug(1, "Running action '%s'\n", act_found->action);
7425 ret = act_found->func(s, m);
7426 acted = 1;
7427 ast_module_unref(mod_ref);
7428 }
7429 } else {
7430 ao2_unlock(act_found);
7431 }
7432 }
7433 if (!acted) {
7434 /*
7435 * We did not execute the action because access was denied, it
7436 * was no longer registered, or no action was really registered.
7437 * Complain about it and leave.
7438 */
7439 report_req_not_allowed(s, action);
7440 mansession_lock(s);
7441 astman_send_error(s, m, "Permission denied");
7443 }
7444 ao2_t_ref(act_found, -1, "done with found action object");
7445 } else {
7446 char buf[512];
7447
7448 report_req_bad_format(s, action);
7449 snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
7450 mansession_lock(s);
7451 astman_send_error(s, m, buf);
7453 }
7454 if (ret) {
7455 return ret;
7456 }
7457 /* Once done with our message, deliver any pending events unless the
7458 requester doesn't want them as part of this response.
7459 */
7460 if (ast_strlen_zero(astman_get_header(m, "SuppressEvents"))) {
7461 return process_events(s);
7462 } else {
7463 return ret;
7464 }
7465}
7466
7467/*!
7468 * Read one full line (including crlf) from the manager socket.
7469 * \note \verbatim
7470 * \r\n is the only valid terminator for the line.
7471 * (Note that, later, '\0' will be considered as the end-of-line marker,
7472 * so everything between the '\0' and the '\r\n' will not be used).
7473 * Also note that we assume output to have at least "maxlen" space.
7474 * \endverbatim
7475 */
7476static int get_input(struct mansession *s, char *output)
7477{
7478 int res, x;
7479 int maxlen = sizeof(s->session->inbuf) - 1;
7480 char *src = s->session->inbuf;
7481 int timeout = -1;
7482 time_t now;
7483
7484 /*
7485 * Look for \r\n within the buffer. If found, copy to the output
7486 * buffer and return, trimming the \r\n (not used afterwards).
7487 */
7488 for (x = 0; x < s->session->inlen; x++) {
7489 int cr; /* set if we have \r */
7490 if (src[x] == '\r' && x+1 < s->session->inlen && src[x + 1] == '\n') {
7491 cr = 2; /* Found. Update length to include \r\n */
7492 } else if (src[x] == '\n') {
7493 cr = 1; /* also accept \n only */
7494 } else {
7495 continue;
7496 }
7497 memmove(output, src, x); /*... but trim \r\n */
7498 output[x] = '\0'; /* terminate the string */
7499 x += cr; /* number of bytes used */
7500 s->session->inlen -= x; /* remaining size */
7501 memmove(src, src + x, s->session->inlen); /* remove used bytes */
7502 return 1;
7503 }
7504 if (s->session->inlen >= maxlen) {
7505 /* no crlf found, and buffer full - sorry, too long for us
7506 * keep the last character in case we are in the middle of a CRLF. */
7507 ast_log(LOG_WARNING, "Discarding message from %s. Line too long: %.25s...\n", ast_sockaddr_stringify_addr(&s->session->addr), src);
7508 src[0] = src[s->session->inlen - 1];
7509 s->session->inlen = 1;
7511 }
7512 res = 0;
7513 while (res == 0) {
7514 /* calculate a timeout if we are not authenticated */
7515 if (!s->session->authenticated) {
7516 if(time(&now) == -1) {
7517 ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
7518 return -1;
7519 }
7520
7521 timeout = (authtimeout - (now - s->session->authstart)) * 1000;
7522 if (timeout < 0) {
7523 /* we have timed out */
7524 return 0;
7525 }
7526 }
7527
7529 if (s->session->pending_event) {
7530 s->session->pending_event = 0;
7532 return 0;
7533 }
7534 s->session->waiting_thread = pthread_self();
7536
7538
7542 }
7543 if (res < 0) {
7544 if (s->session->kicked) {
7545 ast_debug(1, "Manager session has been kicked\n");
7546 return -1;
7547 }
7548 /* If we get a signal from some other thread (typically because
7549 * there are new events queued), return 0 to notify the caller.
7550 */
7551 if (errno == EINTR || errno == EAGAIN) {
7552 return 0;
7553 }
7554 ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
7555 return -1;
7556 }
7557
7558 ao2_lock(s->session);
7559 res = ast_iostream_read(s->session->stream, src + s->session->inlen, maxlen - s->session->inlen);
7560 if (res < 1) {
7561 res = -1; /* error return */
7562 } else {
7563 s->session->inlen += res;
7564 src[s->session->inlen] = '\0';
7565 res = 0;
7566 }
7567 ao2_unlock(s->session);
7568 return res;
7569}
7570
7571/*!
7572 * \internal
7573 * \brief Error handling for sending parse errors. This function handles locking, and clearing the
7574 * parse error flag.
7575 *
7576 * \param s AMI session to process action request.
7577 * \param m Message that's in error.
7578 * \param error Error message to send.
7579 */
7580static void handle_parse_error(struct mansession *s, struct message *m, char *error)
7581{
7582 mansession_lock(s);
7583 astman_send_error(s, m, error);
7584 s->parsing = MESSAGE_OKAY;
7586}
7587
7588/*!
7589 * \internal
7590 * \brief Read and process an AMI action request.
7591 *
7592 * \param s AMI session to process action request.
7593 *
7594 * \retval 0 Retain AMI connection for next command.
7595 * \retval -1 Drop AMI connection due to logoff or connection error.
7596 */
7597static int do_message(struct mansession *s)
7598{
7599 struct message m = { 0 };
7600 char header_buf[sizeof(s->session->inbuf)] = { '\0' };
7601 int res;
7602 int hdr_loss;
7603 time_t now;
7604
7605 hdr_loss = 0;
7606 for (;;) {
7607 /* Check if any events are pending and do them if needed */
7608 if (process_events(s)) {
7609 res = -1;
7610 break;
7611 }
7612 res = get_input(s, header_buf);
7613 if (res == 0) {
7614 /* No input line received. */
7615 if (!s->session->authenticated) {
7616 if (time(&now) == -1) {
7617 ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
7618 res = -1;
7619 break;
7620 }
7621
7622 if (now - s->session->authstart > authtimeout) {
7623 if (displayconnects) {
7624 ast_verb(2, "Client from %s, failed to authenticate in %d seconds\n", ast_sockaddr_stringify_addr(&s->session->addr), authtimeout);
7625 }
7626 res = -1;
7627 break;
7628 }
7629 }
7630 continue;
7631 } else if (res > 0) {
7632 /* Input line received. */
7633 if (ast_strlen_zero(header_buf)) {
7634 if (hdr_loss) {
7635 mansession_lock(s);
7636 astman_send_error(s, &m, "Too many lines in message or allocation failure");
7638 res = 0;
7639 } else {
7640 switch (s->parsing) {
7641 case MESSAGE_OKAY:
7642 res = process_message(s, &m) ? -1 : 0;
7643 break;
7645 handle_parse_error(s, &m, "Failed to parse message: line too long");
7646 res = 0;
7647 break;
7648 }
7649 }
7650 break;
7651 } else if (m.hdrcount < ARRAY_LEN(m.headers)) {
7652 m.headers[m.hdrcount] = ast_strdup(header_buf);
7653 if (!m.headers[m.hdrcount]) {
7654 /* Allocation failure. */
7655 hdr_loss = 1;
7656 } else {
7657 ++m.hdrcount;
7658 }
7659 } else {
7660 /* Too many lines in message. */
7661 hdr_loss = 1;
7662 }
7663 } else {
7664 /* Input error. */
7665 break;
7666 }
7667 }
7668
7670
7671 return res;
7672}
7673
7674/*! \brief The body of the individual manager session.
7675 * Call get_input() to read one line at a time
7676 * (or be woken up on new events), collect the lines in a
7677 * message until found an empty line, and execute the request.
7678 * In any case, deliver events asynchronously through process_events()
7679 * (called from here if no line is available, or at the end of
7680 * process_message(). )
7681 */
7682static void *session_do(void *data)
7683{
7684 struct ast_tcptls_session_instance *ser = data;
7686 struct mansession s = {
7687 .tcptls_session = data,
7688 };
7689 int res;
7690 int arg = 1;
7691 struct ast_sockaddr ser_remote_address_tmp;
7692
7695 goto done;
7696 }
7697
7698 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
7699 session = build_mansession(&ser_remote_address_tmp);
7700
7701 if (session == NULL) {
7703 goto done;
7704 }
7705
7706 /* here we set TCP_NODELAY on the socket to disable Nagle's algorithm.
7707 * This is necessary to prevent delays (caused by buffering) as we
7708 * write to the socket in bits and pieces. */
7709 if (setsockopt(ast_iostream_get_fd(ser->stream), IPPROTO_TCP, TCP_NODELAY, (char *) &arg, sizeof(arg)) < 0) {
7710 ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on manager connection: %s\n", strerror(errno));
7711 }
7713
7715 /* Hook to the tail of the event queue */
7716 session->last_ev = grab_last();
7717
7718 ast_mutex_init(&s.lock);
7719
7720 /* these fields duplicate those in the 'ser' structure */
7721 session->stream = s.stream = ser->stream;
7722 ast_sockaddr_copy(&session->addr, &ser_remote_address_tmp);
7723 s.session = session;
7724
7725 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
7726
7727 if(time(&session->authstart) == -1) {
7728 ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
7732 goto done;
7733 }
7735
7736 /*
7737 * We cannot let the stream exclusively wait for data to arrive.
7738 * We have to wake up the task to send async events.
7739 */
7741
7743 ast_tvnow(), authtimeout * 1000);
7744
7745 astman_append(&s, "Asterisk Call Manager/%s\r\n", AMI_VERSION); /* welcome prompt */
7746 for (;;) {
7747 if ((res = do_message(&s)) < 0 || s.write_error || session->kicked) {
7748 break;
7749 }
7750 if (session->authenticated) {
7752 }
7753 }
7754 /* session is over, explain why and terminate */
7755 if (session->authenticated) {
7757 ast_verb(2, "Manager '%s' %s from %s\n", session->username, session->kicked ? "kicked" : "logged off", ast_sockaddr_stringify_addr(&session->addr));
7758 }
7759 } else {
7761 if (displayconnects) {
7762 ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_sockaddr_stringify_addr(&session->addr));
7763 }
7764 }
7765
7767
7769done:
7770 ao2_ref(ser, -1);
7771 ser = NULL;
7772 return NULL;
7773}
7774
7775/*! \brief remove at most n_max stale session from the list. */
7776static int purge_sessions(int n_max)
7777{
7778 struct ao2_container *sessions;
7780 time_t now = time(NULL);
7781 struct ao2_iterator i;
7782 int purged = 0;
7783
7784 sessions = ao2_global_obj_ref(mgr_sessions);
7785 if (!sessions) {
7786 return 0;
7787 }
7789 ao2_ref(sessions, -1);
7790 while ((session = ao2_iterator_next(&i)) && n_max > 0) {
7792 if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
7793 if (session->authenticated
7794 && VERBOSITY_ATLEAST(2)
7796 ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
7797 session->username, ast_sockaddr_stringify_addr(&session->addr));
7798 }
7801 n_max--;
7802 purged++;
7803 } else {
7806 }
7807 }
7809 return purged;
7810}
7811
7812/*! \brief
7813 * events are appended to a queue from where they
7814 * can be dispatched to clients.
7815 */
7816static int append_event(const char *str, int category)
7817{
7818 struct eventqent *tmp = ast_malloc(sizeof(*tmp) + strlen(str));
7819 static int seq; /* sequence number */
7820
7821 if (!tmp) {
7822 return -1;
7823 }
7824
7825 /* need to init all fields, because ast_malloc() does not */
7826 tmp->usecount = 0;
7827 tmp->category = category;
7828 tmp->seq = ast_atomic_fetchadd_int(&seq, 1);
7829 tmp->tv = ast_tvnow();
7830 AST_RWLIST_NEXT(tmp, eq_next) = NULL;
7831 strcpy(tmp->eventdata, str);
7832
7836
7837 return 0;
7838}
7839
7840static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
7841{
7842 struct varshead *vars;
7843 struct ast_var_t *var;
7844
7845 vars = ast_channel_get_manager_vars(chan);
7846 if (!vars) {
7847 return;
7848 }
7849
7850 AST_LIST_TRAVERSE(vars, var, entries) {
7851 ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", ast_channel_name(chan), var->name, var->value);
7852 }
7853 ao2_ref(vars, -1);
7854}
7855
7856/* XXX see if can be moved inside the function */
7858#define MANAGER_EVENT_BUF_INITSIZE 256
7859
7860static int __attribute__((format(printf, 9, 0))) __manager_event_sessions_va(
7861 struct ao2_container *sessions,
7862 int category,
7863 const char *event,
7864 int chancount,
7865 struct ast_channel **chans,
7866 const char *file,
7867 int line,
7868 const char *func,
7869 const char *fmt,
7870 va_list ap)
7871{
7873 const char *cat_str;
7874 struct timeval now;
7875 struct ast_str *buf;
7876 int i;
7877
7880 ast_debug(3, "AMI Event '%s' is globally disabled, skipping\n", event);
7881 /* Event is globally disabled */
7882 return -1;
7883 }
7884 }
7885
7887 if (!buf) {
7888 return -1;
7889 }
7890
7891 cat_str = authority_to_str(category, &auth);
7892 ast_str_set(&buf, 0,
7893 "Event: %s\r\n"
7894 "Privilege: %s\r\n",
7895 event, cat_str);
7896
7897 if (timestampevents) {
7898 now = ast_tvnow();
7899 ast_str_append(&buf, 0,
7900 "Timestamp: %ld.%06lu\r\n",
7901 (long)now.tv_sec, (unsigned long) now.tv_usec);
7902 }
7903 if (manager_debug) {
7904 static int seq;
7905
7906 ast_str_append(&buf, 0,
7907 "SequenceNumber: %d\r\n",
7909 ast_str_append(&buf, 0,
7910 "File: %s\r\n"
7911 "Line: %d\r\n"
7912 "Func: %s\r\n",
7913 file, line, func);
7914 }
7916 ast_str_append(&buf, 0,
7917 "SystemName: %s\r\n",
7919 }
7920
7921 ast_str_append_va(&buf, 0, fmt, ap);
7922 for (i = 0; i < chancount; i++) {
7924 }
7925
7926 ast_str_append(&buf, 0, "\r\n");
7927
7928 append_event(ast_str_buffer(buf), category);
7929
7930 /* Wake up any sleeping sessions */
7931 if (sessions) {
7932 struct ao2_iterator iter;
7934
7935 iter = ao2_iterator_init(sessions, 0);
7936 while ((session = ao2_iterator_next(&iter))) {
7937 ast_mutex_lock(&session->notify_lock);
7938 if (session->waiting_thread != AST_PTHREADT_NULL) {
7939 pthread_kill(session->waiting_thread, SIGURG);
7940 } else {
7941 /* We have an event to process, but the mansession is
7942 * not waiting for it. We still need to indicate that there
7943 * is an event waiting so that get_input processes the pending
7944 * event instead of polling.
7945 */
7946 session->pending_event = 1;
7947 }
7948 ast_mutex_unlock(&session->notify_lock);
7950 }
7951 ao2_iterator_destroy(&iter);
7952 }
7953
7954 if (category != EVENT_FLAG_SHUTDOWN && !AST_RWLIST_EMPTY(&manager_hooks)) {
7955 struct manager_custom_hook *hook;
7956
7958 AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
7959 hook->helper(category, event, ast_str_buffer(buf));
7960 }
7962 }
7963
7964 return 0;
7965}
7966
7967static int __attribute__((format(printf, 9, 0))) __manager_event_sessions(
7968 struct ao2_container *sessions,
7969 int category,
7970 const char *event,
7971 int chancount,
7972 struct ast_channel **chans,
7973 const char *file,
7974 int line,
7975 const char *func,
7976 const char *fmt,
7977 ...)
7978{
7979 va_list ap;
7980 int res;
7981
7982 va_start(ap, fmt);
7984 file, line, func, fmt, ap);
7985 va_end(ap);
7986 return res;
7987}
7988
7989int __ast_manager_event_multichan(int category, const char *event, int chancount,
7990 struct ast_channel **chans, const char *file, int line, const char *func,
7991 const char *fmt, ...)
7992{
7993 struct ao2_container *sessions = ao2_global_obj_ref(mgr_sessions);
7994 va_list ap;
7995 int res;
7996
7998 /* Nobody is listening */
8000 return 0;
8001 }
8002
8003 va_start(ap, fmt);
8005 file, line, func, fmt, ap);
8006 va_end(ap);
8008 return res;
8009}
8010
8011/*! \brief
8012 * support functions to register/unregister AMI action handlers,
8013 */
8014int ast_manager_unregister(const char *action)
8015{
8016 struct manager_action *cur;
8017
8020 if (!strcasecmp(action, cur->action)) {
8022 break;
8023 }
8024 }
8027
8028 if (cur) {
8029 /*
8030 * We have removed the action object from the container so we
8031 * are no longer in a hurry.
8032 */
8033 ao2_lock(cur);
8034 cur->registered = 0;
8035 ao2_unlock(cur);
8036
8037 ao2_t_ref(cur, -1, "action object removed from list");
8038 ast_verb(5, "Manager unregistered action %s\n", action);
8039 }
8040
8041 return 0;
8042}
8043
8044static int manager_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
8045{
8046 /* Notify managers of change */
8047 char hint[512];
8048
8049 hint[0] = '\0';
8050 ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten);
8051
8052 switch(info->reason) {
8054 manager_event(EVENT_FLAG_CALL, "ExtensionStatus",
8055 "Exten: %s\r\n"
8056 "Context: %s\r\n"
8057 "Hint: %s\r\n"
8058 "Status: %d\r\n"
8059 "StatusText: %s\r\n",
8060 exten,
8061 context,
8062 hint,
8063 info->exten_state,
8064 ast_extension_state2str(info->exten_state));
8065 break;
8067 manager_event(EVENT_FLAG_CALL, "PresenceStatus",
8068 "Exten: %s\r\n"
8069 "Context: %s\r\n"
8070 "Hint: %s\r\n"
8071 "Status: %s\r\n"
8072 "Subtype: %s\r\n"
8073 "Message: %s\r\n",
8074 exten,
8075 context,
8076 hint,
8077 ast_presence_state2str(info->presence_state),
8078 info->presence_subtype,
8079 info->presence_message);
8080 break;
8081 }
8082 return 0;
8083}
8084
8086{
8087 struct manager_action *cur, *prev = NULL;
8088
8090 AST_RWLIST_TRAVERSE(&actions, cur, list) {
8091 int ret;
8092
8093 ret = strcasecmp(cur->action, act->action);
8094 if (ret == 0) {
8095 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
8097 return -1;
8098 }
8099 if (ret > 0) { /* Insert these alphabetically */
8100 break;
8101 }
8102 prev = cur;
8103 }
8104
8105 ao2_t_ref(act, +1, "action object added to list");
8106 act->registered = 1;
8107 if (prev) {
8108 AST_RWLIST_INSERT_AFTER(&actions, prev, act, list);
8109 } else {
8110 AST_RWLIST_INSERT_HEAD(&actions, act, list);
8111 }
8112
8113 ast_verb(5, "Manager registered action %s\n", act->action);
8114
8116
8117 return 0;
8118}
8119
8120/*!
8121 * \internal
8122 * \brief Destroy the registered AMI action object.
8123 *
8124 * \param obj Object to destroy.
8125 */
8126static void action_destroy(void *obj)
8127{
8128 struct manager_action *doomed = obj;
8129
8130 if (doomed->synopsis) {
8131 /* The string fields were initialized. */
8133 }
8134 ao2_cleanup(doomed->final_response);
8135 ao2_cleanup(doomed->list_responses);
8136}
8137
8138/*! \brief register a new command with manager, including online help. This is
8139 the preferred way to register a manager command */
8140int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), struct ast_module *module, const char *synopsis, const char *description)
8141{
8142 struct manager_action *cur;
8143
8144 cur = ao2_t_alloc(sizeof(*cur), action_destroy, action);
8145 if (!cur) {
8146 return -1;
8147 }
8148 if (ast_string_field_init(cur, 128)) {
8149 ao2_t_ref(cur, -1, "action object creation failed");
8150 return -1;
8151 }
8152
8153 cur->action = action;
8154 cur->authority = auth;
8155 cur->func = func;
8156 cur->module = module;
8157#ifdef AST_XML_DOCS
8158 if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
8159 char *tmpxml;
8160
8161 tmpxml = ast_xmldoc_build_synopsis("manager", action, NULL);
8162 ast_string_field_set(cur, synopsis, tmpxml);
8163 ast_free(tmpxml);
8164
8165 tmpxml = ast_xmldoc_build_syntax("manager", action, NULL);
8166 ast_string_field_set(cur, syntax, tmpxml);
8167 ast_free(tmpxml);
8168
8169 tmpxml = ast_xmldoc_build_description("manager", action, NULL);
8170 ast_string_field_set(cur, description, tmpxml);
8171 ast_free(tmpxml);
8172
8173 tmpxml = ast_xmldoc_build_seealso("manager", action, NULL);
8174 ast_string_field_set(cur, seealso, tmpxml);
8175 ast_free(tmpxml);
8176
8177 tmpxml = ast_xmldoc_build_arguments("manager", action, NULL);
8178 ast_string_field_set(cur, arguments, tmpxml);
8179 ast_free(tmpxml);
8180
8181 cur->final_response = ast_xmldoc_build_final_response("manager", action, NULL);
8182 cur->list_responses = ast_xmldoc_build_list_responses("manager", action, NULL);
8183
8184 cur->docsrc = AST_XML_DOC;
8185 } else
8186#endif
8187 {
8189 ast_string_field_set(cur, description, description);
8190#ifdef AST_XML_DOCS
8191 cur->docsrc = AST_STATIC_DOC;
8192#endif
8193 }
8194 if (ast_manager_register_struct(cur)) {
8195 ao2_t_ref(cur, -1, "action object registration failed");
8196 return -1;
8197 }
8198
8199 ao2_t_ref(cur, -1, "action object registration successful");
8200 return 0;
8201}
8202/*! @}
8203 END Doxygen group */
8204
8205/*
8206 * The following are support functions for AMI-over-http.
8207 * The common entry point is generic_http_callback(),
8208 * which extracts HTTP header and URI fields and reformats
8209 * them into AMI messages, locates a proper session
8210 * (using the mansession_id Cookie or GET variable),
8211 * and calls process_message() as for regular AMI clients.
8212 * When done, the output (which goes to a temporary file)
8213 * is read back into a buffer and reformatted as desired,
8214 * then fed back to the client over the original socket.
8215 */
8216
8221};
8222
8223static const char * const contenttype[] = {
8224 [FORMAT_RAW] = "plain",
8225 [FORMAT_HTML] = "html",
8226 [FORMAT_XML] = "xml",
8227};
8228
8229/*!
8230 * locate an http session in the list. The search key (ident) is
8231 * the value of the mansession_id cookie (0 is not valid and means
8232 * a session on the AMI socket).
8233 */
8234static struct mansession_session *find_session(uint32_t ident, int incinuse)
8235{
8236 struct ao2_container *sessions;
8238 struct ao2_iterator i;
8239
8240 if (ident == 0) {
8241 return NULL;
8242 }
8243
8244 sessions = ao2_global_obj_ref(mgr_sessions);
8245 if (!sessions) {
8246 return NULL;
8247 }
8249 ao2_ref(sessions, -1);
8250 while ((session = ao2_iterator_next(&i))) {
8252 if (session->managerid == ident && !session->needdestroy) {
8253 ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
8254 break;
8255 }
8258 }
8260
8261 return session;
8262}
8263
8264/*!
8265 * locate an http session in the list.
8266 * The search keys (nonce) and (username) is value from received
8267 * "Authorization" http header.
8268 * As well as in find_session() function, the value of the nonce can't be zero.
8269 * (0 meansi, that the session used for AMI socket connection).
8270 * Flag (stale) is set, if client used valid, but old, nonce value.
8271 *
8272 */
8273static struct mansession_session *find_session_by_nonce(const char *username, unsigned long nonce, int *stale)
8274{
8276 struct ao2_container *sessions;
8277 struct ao2_iterator i;
8278
8279 if (nonce == 0 || username == NULL || stale == NULL) {
8280 return NULL;
8281 }
8282
8283 sessions = ao2_global_obj_ref(mgr_sessions);
8284 if (!sessions) {
8285 return NULL;
8286 }
8288 ao2_ref(sessions, -1);
8289 while ((session = ao2_iterator_next(&i))) {
8291 if (!strcasecmp(session->username, username) && session->managerid == nonce) {
8292 *stale = 0;
8293 break;
8294 } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
8295 *stale = 1;
8296 break;
8297 }
8300 }
8302
8303 return session;
8304}
8305
8306int astman_is_authed(uint32_t ident)
8307{
8308 int authed;
8310
8311 if (!(session = find_session(ident, 0)))
8312 return 0;
8313
8314 authed = (session->authenticated != 0);
8315
8318
8319 return authed;
8320}
8321
8322int astman_verify_session_readpermissions(uint32_t ident, int perm)
8323{
8324 int result = 0;
8326 struct ao2_container *sessions;
8327 struct ao2_iterator i;
8328
8329 if (ident == 0) {
8330 return 0;
8331 }
8332
8333 sessions = ao2_global_obj_ref(mgr_sessions);
8334 if (!sessions) {
8335 return 0;
8336 }
8338 ao2_ref(sessions, -1);
8339 while ((session = ao2_iterator_next(&i))) {
8341 if ((session->managerid == ident) && (session->readperm & perm)) {
8342 result = 1;
8345 break;
8346 }
8349 }
8351
8352 return result;
8353}
8354
8355int astman_verify_session_writepermissions(uint32_t ident, int perm)
8356{
8357 int result = 0;
8359 struct ao2_container *sessions;
8360 struct ao2_iterator i;
8361
8362 if (ident == 0) {
8363 return 0;
8364 }
8365
8366 sessions = ao2_global_obj_ref(mgr_sessions);
8367 if (!sessions) {
8368 return 0;
8369 }
8371 ao2_ref(sessions, -1);
8372 while ((session = ao2_iterator_next(&i))) {
8374 if ((session->managerid == ident) && (session->writeperm & perm)) {
8375 result = 1;
8378 break;
8379 }
8382 }
8384
8385 return result;
8386}
8387
8388/*
8389 * convert to xml with various conversion:
8390 * mode & 1 -> lowercase;
8391 * mode & 2 -> replace non-alphanumeric chars with underscore
8392 */
8393static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
8394{
8395 /* store in a local buffer to avoid calling ast_str_append too often */
8396 char buf[256];
8397 char *dst = buf;
8398 const char *save = src;
8399 int space = sizeof(buf);
8400 /* repeat until done and nothing to flush */
8401 for ( ; *src || dst != buf ; src++) {
8402 if (*src == '\0' || space < 10) { /* flush */
8403 *dst++ = '\0';
8404 ast_str_append(out, 0, "%s", buf);
8405 dst = buf;
8406 space = sizeof(buf);
8407 if (*src == '\0') {
8408 break;
8409 }
8410 }
8411
8412 if (mode & 2) {
8413 if (save == src && isdigit(*src)) {
8414 /* The first character of an XML attribute cannot be a digit */
8415 *dst++ = '_';
8416 *dst++ = *src;
8417 space -= 2;
8418 continue;
8419 } else if (!isalnum(*src)) {
8420 /* Replace non-alphanumeric with an underscore */
8421 *dst++ = '_';
8422 space--;
8423 continue;
8424 }
8425 }
8426 switch (*src) {
8427 case '<':
8428 strcpy(dst, "&lt;");
8429 dst += 4;
8430 space -= 4;
8431 break;
8432 case '>':
8433 strcpy(dst, "&gt;");
8434 dst += 4;
8435 space -= 4;
8436 break;
8437 case '\"':
8438 strcpy(dst, "&quot;");
8439 dst += 6;
8440 space -= 6;
8441 break;
8442 case '\'':
8443 strcpy(dst, "&apos;");
8444 dst += 6;
8445 space -= 6;
8446 break;
8447 case '&':
8448 strcpy(dst, "&amp;");
8449 dst += 5;
8450 space -= 5;
8451 break;
8452
8453 default:
8454 *dst++ = mode ? tolower(*src) : *src;
8455 space--;
8456 }
8457 }
8458}
8459
8461 char *varname;
8463};
8464
8465static int variable_count_hash_fn(const void *vvc, const int flags)
8466{
8467 const struct variable_count *vc = vvc;
8468
8469 return ast_str_hash(vc->varname);
8470}
8471
8472static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
8473{
8474 /* Due to the simplicity of struct variable_count, it makes no difference
8475 * if you pass in objects or strings, the same operation applies. This is
8476 * due to the fact that the hash occurs on the first element, which means
8477 * the address of both the struct and the string are exactly the same. */
8478 struct variable_count *vc = obj;
8479 char *str = vstr;
8480 return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
8481}
8482
8483/*! \brief Convert the input into XML or HTML.
8484 * The input is supposed to be a sequence of lines of the form
8485 * Name: value
8486 * optionally followed by a blob of unformatted text.
8487 * A blank line is a section separator. Basically, this is a
8488 * mixture of the format of Manager Interface and CLI commands.
8489 * The unformatted text is considered as a single value of a field
8490 * named 'Opaque-data'.
8491 *
8492 * At the moment the output format is the following (but it may
8493 * change depending on future requirements so don't count too
8494 * much on it when writing applications):
8495 *
8496 * General: the unformatted text is used as a value of
8497 * XML output: to be completed
8498 *
8499 * \verbatim
8500 * Each section is within <response type="object" id="xxx">
8501 * where xxx is taken from ajaxdest variable or defaults to unknown
8502 * Each row is reported as an attribute Name="value" of an XML
8503 * entity named from the variable ajaxobjtype, default to "generic"
8504 * \endverbatim
8505 *
8506 * HTML output:
8507 * each Name-value pair is output as a single row of a two-column table.
8508 * Sections (blank lines in the input) are separated by a <HR>
8509 *
8510 */
8511static void xml_translate(struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
8512{
8513 struct ast_variable *v;
8514 const char *dest = NULL;
8515 char *var, *val;
8516 const char *objtype = NULL;
8517 int in_data = 0; /* parsing data */
8518 int inobj = 0;
8519 int xml = (format == FORMAT_XML);
8520 struct variable_count *vc = NULL;
8521 struct ao2_container *vco = NULL;
8522
8523 if (xml) {
8524 /* dest and objtype need only for XML format */
8525 for (v = get_vars; v; v = v->next) {
8526 if (!strcasecmp(v->name, "ajaxdest")) {
8527 dest = v->value;
8528 } else if (!strcasecmp(v->name, "ajaxobjtype")) {
8529 objtype = v->value;
8530 }
8531 }
8532 if (ast_strlen_zero(dest)) {
8533 dest = "unknown";
8534 }
8535 if (ast_strlen_zero(objtype)) {
8536 objtype = "generic";
8537 }
8538 }
8539
8540 /* we want to stop when we find an empty line */
8541 while (in && *in) {
8542 val = strsep(&in, "\r\n"); /* mark start and end of line */
8543 if (in && *in == '\n') { /* remove trailing \n if any */
8544 in++;
8545 }
8547 ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
8548 if (ast_strlen_zero(val)) {
8549 /* empty line */
8550 if (in_data) {
8551 /* close data in Opaque mode */
8552 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
8553 in_data = 0;
8554 }
8555
8556 if (inobj) {
8557 /* close block */
8558 ast_str_append(out, 0, xml ? " /></response>\n" :
8559 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
8560 inobj = 0;
8561 ao2_ref(vco, -1);
8562 vco = NULL;
8563 }
8564 continue;
8565 }
8566
8567 if (!inobj) {
8568 /* start new block */
8569 if (xml) {
8570 ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
8571 }
8574 inobj = 1;
8575 }
8576
8577 if (in_data) {
8578 /* Process data field in Opaque mode. This is a
8579 * followup, so we re-add line feeds. */
8580 ast_str_append(out, 0, xml ? "\n" : "<br>\n");
8581 xml_copy_escape(out, val, 0); /* data field */
8582 continue;
8583 }
8584
8585 /* We expect "Name: value" line here */
8586 var = strsep(&val, ":");
8587 if (val) {
8588 /* found the field name */
8591 } else {
8592 /* field name not found, switch to opaque mode */
8593 val = var;
8594 var = "Opaque-data";
8595 in_data = 1;
8596 }
8597
8598
8599 ast_str_append(out, 0, xml ? " " : "<tr><td>");
8600 if ((vc = ao2_find(vco, var, 0))) {
8601 vc->count++;
8602 } else {
8603 /* Create a new entry for this one */
8604 vc = ao2_alloc(sizeof(*vc), NULL);
8605 vc->varname = var;
8606 vc->count = 1;
8607 ao2_link(vco, vc);
8608 }
8609
8610 xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
8611 if (vc->count > 1) {
8612 ast_str_append(out, 0, "-%d", vc->count);
8613 }
8614 ao2_ref(vc, -1);
8615 ast_str_append(out, 0, xml ? "='" : "</td><td>");
8616 xml_copy_escape(out, val, 0); /* data field */
8617 if (!in_data || !*in) {
8618 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
8619 }
8620 }
8621
8622 if (inobj) {
8623 ast_str_append(out, 0, xml ? " /></response>\n" :
8624 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
8625 ao2_ref(vco, -1);
8626 }
8627}
8628
8629static void close_mansession_file(struct mansession *s)
8630{
8631 if (s->stream) {
8633 s->stream = NULL;
8634 } else {
8635 ast_log(LOG_ERROR, "Attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n");
8636 }
8637}
8638
8639static void process_output(struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
8640{
8641 char *buf;
8642 off_t l;
8643 int fd;
8644
8645 if (!s->stream)
8646 return;
8647
8648 /* Ensure buffer is NULL-terminated */
8649 ast_iostream_write(s->stream, "", 1);
8650
8651 fd = ast_iostream_get_fd(s->stream);
8652
8653 l = lseek(fd, 0, SEEK_CUR);
8654 if (l > 0) {
8655 if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0))) {
8656 ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n");
8657 } else {
8658 if (format == FORMAT_XML || format == FORMAT_HTML) {
8659 xml_translate(out, buf, params, format);
8660 } else {
8661 ast_str_append(out, 0, "%s", buf);
8662 }
8663 munmap(buf, l);
8664 }
8665 } else if (format == FORMAT_XML || format == FORMAT_HTML) {
8666 xml_translate(out, "", params, format);
8667 }
8668
8670}
8671
8674 enum output_format format,
8675 const struct ast_sockaddr *remote_address, const char *uri,
8676 struct ast_variable *get_params,
8677 struct ast_variable *headers)
8678{
8679 struct mansession s = { .session = NULL, .tcptls_session = ser };
8681 uint32_t ident;
8682 int fd;
8683 int blastaway = 0;
8684 struct ast_variable *params = get_params;
8685 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
8686 struct ast_str *http_header = NULL, *out = NULL;
8687 struct message m = { 0 };
8688
8690 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
8691 return 0;
8692 }
8693
8694 ident = ast_http_manid_from_vars(headers);
8695
8696 if (!(session = find_session(ident, 1))) {
8697
8698 /**/
8699 /* Create new session.
8700 * While it is not in the list we don't need any locking
8701 */
8702 if (!(session = build_mansession(remote_address))) {
8704 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
8705 return 0;
8706 }
8708 session->send_events = 0;
8709 session->inuse = 1;
8710 /*!
8711 * \note There is approximately a 1 in 1.8E19 chance that the following
8712 * calculation will produce 0, which is an invalid ID, but due to the
8713 * properties of the rand() function (and the constancy of s), that
8714 * won't happen twice in a row.
8715 */
8716 while ((session->managerid = ast_random() ^ (unsigned long) session) == 0) {
8717 }
8718 session->last_ev = grab_last();
8719 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
8720 }
8722
8723 http_header = ast_str_create(128);
8724 out = ast_str_create(2048);
8725
8726 ast_mutex_init(&s.lock);
8727
8728 if (http_header == NULL || out == NULL) {
8730 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)");
8731 goto generic_callback_out;
8732 }
8733
8734 s.session = session;
8735 fd = mkstemp(template); /* create a temporary file for command output */
8736 unlink(template);
8737 if (fd <= -1) {
8738 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)");
8739 goto generic_callback_out;
8740 }
8742 if (!s.stream) {
8743 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
8744 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)");
8745 close(fd);
8746 goto generic_callback_out;
8747 }
8748
8749 if (method == AST_HTTP_POST) {
8750 params = ast_http_get_post_vars(ser, headers);
8751 if (!params) {
8752 switch (errno) {
8753 case EFBIG:
8754 ast_http_error(ser, 413, "Request Entity Too Large", "Body too large");
8756 goto generic_callback_out;
8757 case ENOMEM:
8759 ast_http_error(ser, 500, "Server Error", "Out of memory");
8761 goto generic_callback_out;
8762 case EIO:
8763 ast_http_error(ser, 400, "Bad Request", "Error parsing request body");
8765 goto generic_callback_out;
8766 }
8767 }
8768 }
8769
8770 astman_append_headers(&m, params);
8771
8772 if (process_message(&s, &m)) {
8773 if (session->authenticated) {
8775 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
8776 }
8777 } else {
8778 if (displayconnects) {
8779 ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_sockaddr_stringify_addr(&session->addr));
8780 }
8781 }
8782 session->needdestroy = 1;
8783 }
8784
8786
8787 ast_str_append(&http_header, 0,
8788 "Content-type: text/%s\r\n"
8789 "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
8790 "Pragma: SuppressEvents\r\n",
8791 contenttype[format],
8792 session->managerid, httptimeout);
8793
8794 if (format == FORMAT_XML) {
8795 ast_str_append(&out, 0, "<ajax-response>\n");
8796 } else if (format == FORMAT_HTML) {
8797 /*
8798 * When handling AMI-over-HTTP in HTML format, we provide a simple form for
8799 * debugging purposes. This HTML code should not be here, we
8800 * should read from some config file...
8801 */
8802
8803#define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
8804#define TEST_STRING \
8805 "<form action=\"manager\" method=\"post\">\n\
8806 Action: <select name=\"action\">\n\
8807 <option value=\"\">-----&gt;</option>\n\
8808 <option value=\"login\">login</option>\n\
8809 <option value=\"command\">Command</option>\n\
8810 <option value=\"waitevent\">waitevent</option>\n\
8811 <option value=\"listcommands\">listcommands</option>\n\
8812 </select>\n\
8813 or <input name=\"action\"><br/>\n\
8814 CLI Command <input name=\"command\"><br>\n\
8815 user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
8816 <input type=\"submit\">\n</form>\n"
8817
8818 ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
8819 ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
8820 ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
8822 }
8823
8824 process_output(&s, &out, params, format);
8825
8826 if (format == FORMAT_XML) {
8827 ast_str_append(&out, 0, "</ajax-response>\n");
8828 } else if (format == FORMAT_HTML) {
8829 ast_str_append(&out, 0, "</table></body>\r\n");
8830 }
8831
8833 /* Reset HTTP timeout. If we're not authenticated, keep it extremely short */
8834 session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
8835
8836 if (session->needdestroy) {
8837 if (session->inuse == 1) {
8838 ast_debug(1, "Need destroy, doing it now!\n");
8839 blastaway = 1;
8840 } else {
8841 ast_debug(1, "Need destroy, but can't do it yet!\n");
8842 ast_mutex_lock(&session->notify_lock);
8843 if (session->waiting_thread != AST_PTHREADT_NULL) {
8844 pthread_kill(session->waiting_thread, SIGURG);
8845 }
8846 ast_mutex_unlock(&session->notify_lock);
8847 session->inuse--;
8848 }
8849 } else {
8850 session->inuse--;
8851 }
8853
8854 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
8855 http_header = NULL;
8856 out = NULL;
8857
8858generic_callback_out:
8860
8861 /* Clear resource */
8862
8863 if (method == AST_HTTP_POST && params) {
8864 ast_variables_destroy(params);
8865 }
8866 ast_free(http_header);
8867 ast_free(out);
8868
8869 if (session) {
8870 if (blastaway) {
8872 } else {
8873 if (session->stream) {
8874 ast_iostream_close(session->stream);
8875 session->stream = NULL;
8876 }
8878 }
8879 }
8880
8881 return 0;
8882}
8883
8886 enum output_format format,
8887 const struct ast_sockaddr *remote_address, const char *uri,
8888 struct ast_variable *get_params,
8889 struct ast_variable *headers)
8890{
8892 struct mansession s = { .session = NULL, .tcptls_session = ser };
8893 struct ast_variable *v, *params = get_params;
8894 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
8895 struct ast_str *http_header = NULL, *out = NULL;
8896 size_t result_size;
8897 struct message m = { 0 };
8898 int fd;
8899
8900 time_t time_now = time(NULL);
8901 unsigned long nonce = 0, nc;
8902 struct ast_http_digest d = { NULL, };
8903 struct ast_manager_user *user = NULL;
8904 int stale = 0;
8905 char resp_hash[256]="";
8906 /* Cache for user data */
8907 char u_username[80];
8908 int u_readperm;
8909 int u_writeperm;
8910 int u_writetimeout;
8911 int u_displayconnects;
8912
8914 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
8915 return 0;
8916 }
8917
8918 /* Find "Authorization: " header */
8919 for (v = headers; v; v = v->next) {
8920 if (!strcasecmp(v->name, "Authorization")) {
8921 break;
8922 }
8923 }
8924
8925 if (!v || ast_strlen_zero(v->value)) {
8926 goto out_401; /* Authorization Header not present - send auth request */
8927 }
8928
8929 /* Digest found - parse */
8930 if (ast_string_field_init(&d, 128)) {
8932 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
8933 return 0;
8934 }
8935
8936 if (ast_parse_digest(v->value, &d, 0, 1)) {
8937 /* Error in Digest - send new one */
8938 nonce = 0;
8939 goto out_401;
8940 }
8941 if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
8942 ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
8943 nonce = 0;
8944 goto out_401;
8945 }
8946
8948 user = get_manager_by_name_locked(d.username);
8949 if(!user) {
8951 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
8952 nonce = 0;
8953 goto out_401;
8954 }
8955
8956 /* --- We have User for this auth, now check ACL */
8957 if (user->acl && !ast_apply_acl(user->acl, remote_address, "Manager User ACL:")) {
8959 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
8961 ast_http_error(ser, 403, "Permission denied", "Permission denied");
8962 return 0;
8963 }
8964
8965 /* --- We have auth, so check it */
8966
8967 /* compute the expected response to compare with what we received */
8968 {
8969 char *a2;
8970 /* ast_md5_hash outputs 32 characters plus NULL terminator. */
8971 char a2_hash[33];
8972 char resp[256];
8973
8974 /* XXX Now request method are hardcoded in A2 */
8975 if (ast_asprintf(&a2, "%s:%s", ast_get_http_method(method), d.uri) < 0) {
8978 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
8979 return 0;
8980 }
8981
8982 ast_md5_hash(a2_hash, a2);
8983 ast_free(a2);
8984
8985 if (d.qop) {
8986 /* RFC 2617 */
8987 snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
8988 } else {
8989 /* RFC 2069 */
8990 snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
8991 }
8992 ast_md5_hash(resp_hash, resp);
8993 }
8994
8995 if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
8996 /* Something was wrong, so give the client to try with a new challenge */
8998 nonce = 0;
8999 goto out_401;
9000 }
9001
9002 /*
9003 * User are pass Digest authentication.
9004 * Now, cache the user data and unlock user list.
9005 */
9006 ast_copy_string(u_username, user->username, sizeof(u_username));
9007 u_readperm = user->readperm;
9008 u_writeperm = user->writeperm;
9009 u_displayconnects = user->displayconnects;
9010 u_writetimeout = user->writetimeout;
9012
9013 if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
9014 /*
9015 * Create new session.
9016 * While it is not in the list we don't need any locking
9017 */
9018 if (!(session = build_mansession(remote_address))) {
9020 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
9021 return 0;
9022 }
9024
9025 ast_copy_string(session->username, u_username, sizeof(session->username));
9026 session->managerid = nonce;
9027 session->last_ev = grab_last();
9028 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
9029
9030 session->readperm = u_readperm;
9031 session->writeperm = u_writeperm;
9032 session->writetimeout = u_writetimeout;
9033
9034 if (u_displayconnects) {
9035 ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
9036 }
9037 session->noncetime = session->sessionstart = time_now;
9038 session->authenticated = 1;
9039 } else if (stale) {
9040 /*
9041 * Session found, but nonce is stale.
9042 *
9043 * This could be because an old request (w/old nonce) arrived.
9044 *
9045 * This may be as the result of http proxy usage (separate delay or
9046 * multipath) or in a situation where a page was refreshed too quickly
9047 * (seen in Firefox).
9048 *
9049 * In this situation, we repeat the 401 auth with the current nonce
9050 * value.
9051 */
9052 nonce = session->managerid;
9054 stale = 1;
9055 goto out_401;
9056 } else {
9057 sscanf(d.nc, "%30lx", &nc);
9058 if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
9059 /*
9060 * Nonce time expired (> 2 minutes) or something wrong with nonce
9061 * counter.
9062 *
9063 * Create new nonce key and resend Digest auth request. Old nonce
9064 * is saved for stale checking...
9065 */
9066 session->nc = 0; /* Reset nonce counter */
9067 session->oldnonce = session->managerid;
9068 nonce = session->managerid = ast_random();
9069 session->noncetime = time_now;
9071 stale = 1;
9072 goto out_401;
9073 } else {
9074 session->nc = nc; /* All OK, save nonce counter */
9075 }
9076 }
9077
9078
9079 /* Reset session timeout. */
9080 session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
9082
9083 ast_mutex_init(&s.lock);
9084 s.session = session;
9085 fd = mkstemp(template); /* create a temporary file for command output */
9086 unlink(template);
9087 if (fd <= -1) {
9088 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)");
9089 goto auth_callback_out;
9090 }
9092 if (!s.stream) {
9093 ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
9094 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)");
9095 close(fd);
9096 goto auth_callback_out;
9097 }
9098
9099 if (method == AST_HTTP_POST) {
9100 params = ast_http_get_post_vars(ser, headers);
9101 if (!params) {
9102 switch (errno) {
9103 case EFBIG:
9104 ast_http_error(ser, 413, "Request Entity Too Large", "Body too large");
9106 goto auth_callback_out;
9107 case ENOMEM:
9109 ast_http_error(ser, 500, "Server Error", "Out of memory");
9111 goto auth_callback_out;
9112 case EIO:
9113 ast_http_error(ser, 400, "Bad Request", "Error parsing request body");
9115 goto auth_callback_out;
9116 }
9117 }
9118 }
9119
9120 astman_append_headers(&m, params);
9121
9122 if (process_message(&s, &m)) {
9123 if (u_displayconnects) {
9124 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
9125 }
9126
9127 session->needdestroy = 1;
9128 }
9129
9131
9132 result_size = lseek(ast_iostream_get_fd(s.stream), 0, SEEK_CUR); /* Calculate approx. size of result */
9133
9134 http_header = ast_str_create(80);
9135 out = ast_str_create(result_size * 2 + 512);
9136 if (http_header == NULL || out == NULL) {
9138 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)");
9140 goto auth_callback_out;
9141 }
9142
9143 ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]);
9144
9145 if (format == FORMAT_XML) {
9146 ast_str_append(&out, 0, "<ajax-response>\n");
9147 } else if (format == FORMAT_HTML) {
9148 ast_str_append(&out, 0,
9149 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
9150 "<html><head>\r\n"
9151 "<title>Asterisk&trade; Manager Interface</title>\r\n"
9152 "</head><body style=\"background-color: #ffffff;\">\r\n"
9153 "<form method=\"POST\">\r\n"
9154 "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
9155 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
9156 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
9157 "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
9158 }
9159
9160 process_output(&s, &out, params, format);
9161
9162 if (format == FORMAT_XML) {
9163 ast_str_append(&out, 0, "</ajax-response>\n");
9164 } else if (format == FORMAT_HTML) {
9165 ast_str_append(&out, 0, "</table></form></body></html>\r\n");
9166 }
9167
9168 ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
9169 http_header = NULL;
9170 out = NULL;
9171
9172auth_callback_out:
9174
9175 /* Clear resources and unlock manager session */
9176 if (method == AST_HTTP_POST && params) {
9177 ast_variables_destroy(params);
9178 }
9179
9180 ast_free(http_header);
9181 ast_free(out);
9182
9184 if (session->stream) {
9185 ast_iostream_close(session->stream);
9186 session->stream = NULL;
9187 }
9189
9190 if (session->needdestroy) {
9191 ast_debug(1, "Need destroy, doing it now!\n");
9193 }
9195 return 0;
9196
9197out_401:
9198 if (!nonce) {
9199 nonce = ast_random();
9200 }
9201
9202 ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
9204 return 0;
9205}
9206
9207static int manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
9208{
9209 int retval;
9210 struct ast_sockaddr ser_remote_address_tmp;
9211
9212 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
9213 retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
9214 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
9215 return retval;
9216}
9217
9218static int mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
9219{
9220 int retval;
9221 struct ast_sockaddr ser_remote_address_tmp;
9222
9223 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
9224 retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
9225 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
9226 return retval;
9227}
9228
9229static int rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
9230{
9231 int retval;
9232 struct ast_sockaddr ser_remote_address_tmp;
9233
9234 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
9235 retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
9236 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
9237 return retval;
9238}
9239
9240static struct ast_http_uri rawmanuri = {
9241 .description = "Raw HTTP Manager Event Interface",
9242 .uri = "rawman",
9243 .callback = rawman_http_callback,
9244 .data = NULL,
9245 .key = __FILE__,
9246};
9247
9248static struct ast_http_uri manageruri = {
9249 .description = "HTML Manager Event Interface",
9250 .uri = "manager",
9251 .callback = manager_http_callback,
9252 .data = NULL,
9253 .key = __FILE__,
9254};
9255
9257 .description = "XML Manager Event Interface",
9258 .uri = "mxml",
9259 .callback = mxml_http_callback,
9260 .data = NULL,
9261 .key = __FILE__,
9262};
9263
9264
9265/* Callback with Digest authentication */
9266static int auth_manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
9267{
9268 int retval;
9269 struct ast_sockaddr ser_remote_address_tmp;
9270
9271 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
9272 retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
9273 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
9274 return retval;
9275}
9276
9277static int auth_mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
9278{
9279 int retval;
9280 struct ast_sockaddr ser_remote_address_tmp;
9281
9282 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
9283 retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
9284 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
9285 return retval;
9286}
9287
9288static int auth_rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
9289{
9290 int retval;
9291 struct ast_sockaddr ser_remote_address_tmp;
9292
9293 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
9294 retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
9295 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
9296 return retval;
9297}
9298
9299static struct ast_http_uri arawmanuri = {
9300 .description = "Raw HTTP Manager Event Interface w/Digest authentication",
9301 .uri = "arawman",
9302 .has_subtree = 0,
9303 .callback = auth_rawman_http_callback,
9304 .data = NULL,
9305 .key = __FILE__,
9306};
9307
9308static struct ast_http_uri amanageruri = {
9309 .description = "HTML Manager Event Interface w/Digest authentication",
9310 .uri = "amanager",
9311 .has_subtree = 0,
9312 .callback = auth_manager_http_callback,
9313 .data = NULL,
9314 .key = __FILE__,
9315};
9316
9318 .description = "XML Manager Event Interface w/Digest authentication",
9319 .uri = "amxml",
9320 .has_subtree = 0,
9321 .callback = auth_mxml_http_callback,
9322 .data = NULL,
9323 .key = __FILE__,
9324};
9325
9326/*! \brief Get number of logged in sessions for a login name */
9327static int get_manager_sessions_cb(void *obj, void *arg, void *data, int flags)
9328{
9329 struct mansession_session *session = obj;
9330 const char *login = (char *)arg;
9331 int *no_sessions = data;
9332
9333 if (strcasecmp(session->username, login) == 0) {
9334 (*no_sessions)++;
9335 }
9336
9337 return 0;
9338}
9339
9340
9341/*! \brief ${AMI_CLIENT()} Dialplan function - reads manager client data */
9342static int function_amiclient(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9343{
9344 struct ast_manager_user *user = NULL;
9345
9348 AST_APP_ARG(param);
9349 );
9350
9351
9352 if (ast_strlen_zero(data) ) {
9353 ast_log(LOG_WARNING, "AMI_CLIENT() requires two arguments: AMI_CLIENT(<name>[,<arg>])\n");
9354 return -1;
9355 }
9357 args.name = ast_strip(args.name);
9358 args.param = ast_strip(args.param);
9359
9361 if (!(user = get_manager_by_name_locked(args.name))) {
9363 ast_log(LOG_ERROR, "There's no manager user called : \"%s\"\n", args.name);
9364 return -1;
9365 }
9367
9368 if (!strcasecmp(args.param, "sessions")) {
9369 int no_sessions = 0;
9370 struct ao2_container *sessions;
9371
9372 sessions = ao2_global_obj_ref(mgr_sessions);
9373 if (sessions) {
9374 ao2_callback_data(sessions, 0, get_manager_sessions_cb, /*login name*/ data, &no_sessions);
9375 ao2_ref(sessions, -1);
9376 }
9377 snprintf(buf, len, "%d", no_sessions);
9378 } else {
9379 ast_log(LOG_ERROR, "Invalid arguments provided to function AMI_CLIENT: %s\n", args.param);
9380 return -1;
9381
9382 }
9383
9384 return 0;
9385}
9386
9387
9388/*! \brief description of AMI_CLIENT dialplan function */
9390 .name = "AMI_CLIENT",
9391 .read = function_amiclient,
9392 .read_max = 12,
9393};
9394
9395static int webregged = 0;
9396
9397/*! \brief cleanup code called at each iteration of server_root,
9398 * guaranteed to happen every 5 seconds at most
9399 */
9400static void purge_old_stuff(void *data)
9401{
9402 struct ast_tcptls_session_args *ser = data;
9403 /* purge_sessions will return the number of sessions actually purged,
9404 * up to a maximum of it's arguments, purge one at a time, keeping a
9405 * purge interval of 1ms as long as we purged a session, otherwise
9406 * revert to a purge check every 5s
9407 */
9408 if (purge_sessions(1) == 1) {
9409 ser->poll_timeout = 1;
9410 } else {
9411 ser->poll_timeout = 5000;
9412 }
9413 purge_events();
9414}
9415
9418 .accept_fd = -1,
9419 .master = AST_PTHREADT_NULL,
9420 .tls_cfg = NULL,
9421 .poll_timeout = 5000, /* wake up every 5 seconds */
9422 .periodic_fn = purge_old_stuff,
9423 .name = "AMI server",
9424 .accept_fn = ast_tcptls_server_root, /* thread doing the accept() */
9425 .worker_fn = session_do, /* thread handling the session */
9426};
9427
9429 .accept_fd = -1,
9430 .master = AST_PTHREADT_NULL,
9431 .tls_cfg = &ami_tls_cfg,
9432 .poll_timeout = -1, /* the other does the periodic cleanup */
9433 .name = "AMI TLS server",
9434 .accept_fn = ast_tcptls_server_root, /* thread doing the accept() */
9435 .worker_fn = session_do, /* thread handling the session */
9436};
9437
9438/*! \brief CLI command manager show settings */
9439static char *handle_manager_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9440{
9441 switch (cmd) {
9442 case CLI_INIT:
9443 e->command = "manager show settings";
9444 e->usage =
9445 "Usage: manager show settings\n"
9446 " Provides detailed list of the configuration of the Manager.\n";
9447 return NULL;
9448 case CLI_GENERATE:
9449 return NULL;
9450 }
9451#define FORMAT " %-25.25s %-15.55s\n"
9452#define FORMAT2 " %-25.25s %-15d\n"
9453#define FORMAT3 " %-25.25s %s\n"
9454 if (a->argc != 3) {
9455 return CLI_SHOWUSAGE;
9456 }
9457 ast_cli(a->fd, "\nGlobal Settings:\n");
9458 ast_cli(a->fd, "----------------\n");
9459 ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
9460 ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
9461 ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
9462 ast_cli(a->fd, FORMAT2, "HTTP Timeout (seconds):", httptimeout);
9463 ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
9464 ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
9465 ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
9466 ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
9467 ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
9468 ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
9469 ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
9470 ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
9471 ast_cli(a->fd, FORMAT3, "Channel vars:", S_OR(manager_channelvars, ""));
9472 ast_cli(a->fd, FORMAT3, "Disabled events:", S_OR(manager_disabledevents, ""));
9473 ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
9474#undef FORMAT
9475#undef FORMAT2
9476#undef FORMAT3
9477
9478 return CLI_SUCCESS;
9479}
9480
9481#ifdef AST_XML_DOCS
9482
9483static int ast_xml_doc_item_cmp_fn(const void *a, const void *b)
9484{
9485 struct ast_xml_doc_item **item_a = (struct ast_xml_doc_item **)a;
9486 struct ast_xml_doc_item **item_b = (struct ast_xml_doc_item **)b;
9487 return strcmp((*item_a)->name, (*item_b)->name);
9488}
9489
9490static char *handle_manager_show_events(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9491{
9492 struct ao2_container *events;
9493 struct ao2_iterator *it_events;
9494 struct ast_xml_doc_item *item;
9495 struct ast_xml_doc_item **items;
9496 struct ast_str *buffer;
9497 int i = 0, totalitems = 0;
9498
9499 switch (cmd) {
9500 case CLI_INIT:
9501 e->command = "manager show events";
9502 e->usage =
9503 "Usage: manager show events\n"
9504 " Prints a listing of the available Asterisk manager interface events.\n";
9505 return NULL;
9506 case CLI_GENERATE:
9507 return NULL;
9508 }
9509 if (a->argc != 3) {
9510 return CLI_SHOWUSAGE;
9511 }
9512
9513 buffer = ast_str_create(128);
9514 if (!buffer) {
9515 return CLI_SUCCESS;
9516 }
9517
9518 events = ao2_global_obj_ref(event_docs);
9519 if (!events) {
9520 ast_cli(a->fd, "No manager event documentation loaded\n");
9521 ast_free(buffer);
9522 return CLI_SUCCESS;
9523 }
9524
9526 if (!(it_events = ao2_callback(events, OBJ_MULTIPLE | OBJ_NOLOCK, NULL, NULL))) {
9528 ast_log(AST_LOG_ERROR, "Unable to create iterator for events container\n");
9529 ast_free(buffer);
9530 ao2_ref(events, -1);
9531 return CLI_SUCCESS;
9532 }
9533 if (!(items = ast_calloc(sizeof(struct ast_xml_doc_item *), ao2_container_count(events)))) {
9535 ast_log(AST_LOG_ERROR, "Unable to create temporary sorting array for events\n");
9536 ao2_iterator_destroy(it_events);
9537 ast_free(buffer);
9538 ao2_ref(events, -1);
9539 return CLI_SUCCESS;
9540 }
9542
9543 while ((item = ao2_iterator_next(it_events))) {
9544 items[totalitems++] = item;
9545 ao2_ref(item, -1);
9546 }
9547
9548 qsort(items, totalitems, sizeof(struct ast_xml_doc_item *), ast_xml_doc_item_cmp_fn);
9549
9550 ast_cli(a->fd, "Events:\n");
9551 ast_cli(a->fd, " -------------------- -------------------- -------------------- \n");
9552 for (i = 0; i < totalitems; i++) {
9553 ast_str_append(&buffer, 0, " %-20.20s", items[i]->name);
9554 if ((i + 1) % 3 == 0) {
9555 ast_cli(a->fd, "%s\n", ast_str_buffer(buffer));
9556 ast_str_set(&buffer, 0, "%s", "");
9557 }
9558 }
9559 if ((i + 1) % 3 != 0) {
9560 ast_cli(a->fd, "%s\n", ast_str_buffer(buffer));
9561 }
9562
9563 ao2_iterator_destroy(it_events);
9564 ast_free(items);
9565 ao2_ref(events, -1);
9566 ast_free(buffer);
9567
9568 return CLI_SUCCESS;
9569}
9570
9571static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance)
9572{
9573 char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
9574
9575 term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
9576 term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
9577 term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
9578 term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
9579 term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
9580
9581 if (!ast_strlen_zero(ast_str_buffer(instance->synopsis))) {
9583 ast_cli(a->fd, "%s%s\n\n", synopsis_title, synopsis);
9585 }
9586 if (!ast_strlen_zero(ast_str_buffer(instance->syntax))) {
9587 char *syntax = ast_xmldoc_printable(ast_str_buffer(instance->syntax), 1);
9588 ast_cli(a->fd, "%s%s\n\n", syntax_title, syntax);
9589 ast_free(syntax);
9590 }
9591 if (!ast_strlen_zero(ast_str_buffer(instance->description))) {
9592 char *description = ast_xmldoc_printable(ast_str_buffer(instance->description), 1);
9593 ast_cli(a->fd, "%s%s\n\n", description_title, description);
9594 ast_free(description);
9595 }
9596 if (!ast_strlen_zero(ast_str_buffer(instance->arguments))) {
9597 char *arguments = ast_xmldoc_printable(ast_str_buffer(instance->arguments), 1);
9598 ast_cli(a->fd, "%s%s\n\n", arguments_title, arguments);
9599 ast_free(arguments);
9600 }
9601 if (!ast_strlen_zero(ast_str_buffer(instance->seealso))) {
9602 char *seealso = ast_xmldoc_printable(ast_str_buffer(instance->seealso), 1);
9603 ast_cli(a->fd, "%s%s\n\n", seealso_title, seealso);
9604 ast_free(seealso);
9605 }
9606}
9607
9608static char *handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9609{
9611 struct ao2_iterator it_events;
9612 struct ast_xml_doc_item *item, *temp;
9613 int length;
9614
9615 if (cmd == CLI_INIT) {
9616 e->command = "manager show event";
9617 e->usage =
9618 "Usage: manager show event <eventname>\n"
9619 " Provides a detailed description a Manager interface event.\n";
9620 return NULL;
9621 }
9622
9623 events = ao2_global_obj_ref(event_docs);
9624 if (!events) {
9625 ast_cli(a->fd, "No manager event documentation loaded\n");
9626 return CLI_SUCCESS;
9627 }
9628
9629 if (cmd == CLI_GENERATE) {
9630 if (a->pos != 3) {
9631 return NULL;
9632 }
9633
9634 length = strlen(a->word);
9635 it_events = ao2_iterator_init(events, 0);
9636 while ((item = ao2_iterator_next(&it_events))) {
9637 if (!strncasecmp(a->word, item->name, length)) {
9639 ao2_ref(item, -1);
9640 break;
9641 }
9642 }
9643 ao2_ref(item, -1);
9644 }
9645 ao2_iterator_destroy(&it_events);
9646
9647 return NULL;
9648 }
9649
9650 if (a->argc != 4) {
9651 return CLI_SHOWUSAGE;
9652 }
9653
9654 if (!(item = ao2_find(events, a->argv[3], OBJ_KEY))) {
9655 ast_cli(a->fd, "Could not find event '%s'\n", a->argv[3]);
9656 return CLI_SUCCESS;
9657 }
9658
9659 ast_cli(a->fd, "Event: %s\n", a->argv[3]);
9660 for (temp = item; temp; temp = AST_LIST_NEXT(temp, next)) {
9661 print_event_instance(a, temp);
9662 }
9663
9664 ao2_ref(item, -1);
9665 return CLI_SUCCESS;
9666}
9667
9668#endif
9669
9670static struct ast_cli_entry cli_manager[] = {
9671 AST_CLI_DEFINE(handle_showmancmd, "Show a manager interface command"),
9672 AST_CLI_DEFINE(handle_showmancmds, "List manager interface commands"),
9673 AST_CLI_DEFINE(handle_showmanconn, "List connected manager interface users"),
9674 AST_CLI_DEFINE(handle_kickmanconn, "Kick a connected manager interface connection"),
9675 AST_CLI_DEFINE(handle_showmaneventq, "List manager interface queued events"),
9676 AST_CLI_DEFINE(handle_showmanagers, "List configured manager users"),
9677 AST_CLI_DEFINE(handle_showmanager, "Display information on a specific manager user"),
9678 AST_CLI_DEFINE(handle_mandebug, "Show, enable, disable debugging of the manager code"),
9679 AST_CLI_DEFINE(handle_manager_reload, "Reload manager configurations"),
9680 AST_CLI_DEFINE(handle_manager_show_settings, "Show manager global settings"),
9681#ifdef AST_XML_DOCS
9682 AST_CLI_DEFINE(handle_manager_show_events, "List manager interface events"),
9683 AST_CLI_DEFINE(handle_manager_show_event, "Show a manager interface event"),
9684#endif
9685};
9686
9687/*!
9688 * \internal
9689 * \brief Load the config channelvars variable.
9690 *
9691 * \param var Config variable to load.
9692 */
9694{
9695 char *parse = NULL;
9697 AST_APP_ARG(vars)[MAX_VARS];
9698 );
9699
9702
9703 /* parse the setting */
9706
9708}
9709
9710/*!
9711 * \internal
9712 * \brief Load the config disabledevents variable.
9713 *
9714 * \param var Config variable to load.
9715 */
9717{
9720}
9721
9722/*!
9723 * \internal
9724 * \brief Free a user record. Should already be removed from the list
9725 */
9727{
9728 ast_free(user->a1_hash);
9729 ast_free(user->secret);
9730 if (user->whitefilters) {
9731 ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
9732 }
9733 if (user->blackfilters) {
9734 ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
9735 }
9736 user->acl = ast_free_acl_list(user->acl);
9737 ast_variables_destroy(user->chanvars);
9738 ast_free(user);
9739}
9740
9741/*!
9742 * \internal
9743 * \brief Clean up resources on Asterisk shutdown
9744 */
9745static void manager_shutdown(void)
9746{
9747 struct ast_manager_user *user;
9748
9749 /* This event is not actually transmitted, but causes all TCP sessions to be closed */
9750 manager_event(EVENT_FLAG_SHUTDOWN, "CloseSession", "CloseSession: true\r\n");
9751
9752 ast_manager_unregister("Ping");
9753 ast_manager_unregister("Events");
9754 ast_manager_unregister("Logoff");
9755 ast_manager_unregister("Login");
9756 ast_manager_unregister("Challenge");
9757 ast_manager_unregister("Hangup");
9758 ast_manager_unregister("Status");
9759 ast_manager_unregister("Setvar");
9760 ast_manager_unregister("Getvar");
9761 ast_manager_unregister("GetConfig");
9762 ast_manager_unregister("GetConfigJSON");
9763 ast_manager_unregister("UpdateConfig");
9764 ast_manager_unregister("CreateConfig");
9765 ast_manager_unregister("ListCategories");
9766 ast_manager_unregister("Redirect");
9767 ast_manager_unregister("Atxfer");
9768 ast_manager_unregister("CancelAtxfer");
9769 ast_manager_unregister("Originate");
9770 ast_manager_unregister("Command");
9771 ast_manager_unregister("ExtensionState");
9772 ast_manager_unregister("PresenceState");
9773 ast_manager_unregister("AbsoluteTimeout");
9774 ast_manager_unregister("MailboxStatus");
9775 ast_manager_unregister("MailboxCount");
9776 ast_manager_unregister("ListCommands");
9777 ast_manager_unregister("SendText");
9778 ast_manager_unregister("UserEvent");
9779 ast_manager_unregister("WaitEvent");
9780 ast_manager_unregister("CoreSettings");
9781 ast_manager_unregister("CoreStatus");
9782 ast_manager_unregister("Reload");
9783 ast_manager_unregister("LoggerRotate");
9784 ast_manager_unregister("CoreShowChannels");
9785 ast_manager_unregister("CoreShowChannelMap");
9786 ast_manager_unregister("ModuleLoad");
9787 ast_manager_unregister("ModuleCheck");
9788 ast_manager_unregister("AOCMessage");
9789 ast_manager_unregister("Filter");
9790 ast_manager_unregister("BlindTransfer");
9793
9794#ifdef AST_XML_DOCS
9795 ao2_t_global_obj_release(event_docs, "Dispose of event_docs");
9796#endif
9797
9798#ifdef TEST_FRAMEWORK
9799 stasis_forward_cancel(test_suite_forwarder);
9800 test_suite_forwarder = NULL;
9801#endif
9802
9803 if (stasis_router) {
9806 }
9814
9817
9828
9829 ao2_global_obj_release(mgr_sessions);
9830
9831 while ((user = AST_LIST_REMOVE_HEAD(&users, list))) {
9833 }
9835
9838}
9839
9840
9841/*! \brief Initialize all \ref stasis topics and routers used by the various
9842 * sub-components of AMI
9843 */
9845{
9846 int res = 0;
9847
9849 if (!rtp_topic_forwarder) {
9850 return -1;
9851 }
9852
9855 return -1;
9856 }
9857
9859 if (!stasis_router) {
9860 return -1;
9861 }
9864
9867
9870
9871 if (res != 0) {
9872 return -1;
9873 }
9874 return 0;
9875}
9876
9877static int subscribe_all(void)
9878{
9880 ast_log(AST_LOG_ERROR, "Failed to initialize manager subscriptions\n");
9881 return -1;
9882 }
9883 if (manager_system_init()) {
9884 ast_log(AST_LOG_ERROR, "Failed to initialize manager system handling\n");
9885 return -1;
9886 }
9887 if (manager_channels_init()) {
9888 ast_log(AST_LOG_ERROR, "Failed to initialize manager channel handling\n");
9889 return -1;
9890 }
9891 if (manager_mwi_init()) {
9892 ast_log(AST_LOG_ERROR, "Failed to initialize manager MWI handling\n");
9893 return -1;
9894 }
9895 if (manager_bridging_init()) {
9896 return -1;
9897 }
9898 if (manager_endpoints_init()) {
9899 ast_log(AST_LOG_ERROR, "Failed to initialize manager endpoints handling\n");
9900 return -1;
9901 }
9902
9903 subscribed = 1;
9904 return 0;
9905}
9906
9907static void manager_set_defaults(void)
9908{
9909 manager_enabled = 0;
9910 displayconnects = 1;
9912 authtimeout = 30;
9913 authlimit = 50;
9914 manager_debug = 0; /* Debug disabled by default */
9915
9916 /* default values */
9918 sizeof(global_realm));
9921
9922 ami_tls_cfg.enabled = 0;
9933}
9934
9935static int __init_manager(int reload, int by_external_config)
9936{
9937 struct ast_config *ucfg = NULL, *cfg = NULL;
9938 const char *val;
9939 char *cat = NULL;
9940 int newhttptimeout = 60;
9941 struct ast_manager_user *user = NULL;
9942 struct ast_variable *var;
9943 struct ast_flags config_flags = { (reload && !by_external_config) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9944 char a1[256];
9945 char a1_hash[256];
9946 struct ast_sockaddr ami_desc_local_address_tmp;
9947 struct ast_sockaddr amis_desc_local_address_tmp;
9948 int tls_was_enabled = 0;
9949 int acl_subscription_flag = 0;
9950
9951 if (!reload) {
9952 struct ao2_container *sessions;
9953#ifdef AST_XML_DOCS
9954 struct ao2_container *temp_event_docs;
9955#endif
9956 int res;
9957
9959 if (res != 0) {
9960 return -1;
9961 }
9962 manager_topic = stasis_topic_create("manager:core");
9963 if (!manager_topic) {
9964 return -1;
9965 }
9966
9967 /* Register default actions */
10007
10008#ifdef TEST_FRAMEWORK
10009 test_suite_forwarder = stasis_forward_all(ast_test_suite_topic(), manager_topic);
10010#endif
10011
10015
10016 /* Append placeholder event so master_eventq never runs dry */
10017 if (append_event("Event: Placeholder\r\n\r\n", 0)) {
10018 return -1;
10019 }
10020
10021#ifdef AST_XML_DOCS
10022 temp_event_docs = ast_xmldoc_build_documentation("managerEvent");
10023 if (temp_event_docs) {
10024 ao2_t_global_obj_replace_unref(event_docs, temp_event_docs, "Toss old event docs");
10025 ao2_t_ref(temp_event_docs, -1, "Remove creation ref - container holds only ref now");
10026 }
10027#endif
10028
10029 /* If you have a NULL hash fn, you only need a single bucket */
10031 if (!sessions) {
10032 return -1;
10033 }
10035 ao2_ref(sessions, -1);
10036
10037 /* Initialize all settings before first configuration load. */
10039 }
10040
10041 cfg = ast_config_load2("manager.conf", "manager", config_flags);
10042 if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
10043 return 0;
10044 } else if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
10045 ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid.\n");
10046 return 0;
10047 }
10048
10049 /* If this wasn't performed due to a forced reload (because those can be created by ACL change events, we need to unsubscribe to ACL change events. */
10050 if (!by_external_config) {
10052 }
10053
10054 if (reload) {
10055 /* Reset all settings before reloading configuration */
10056 tls_was_enabled = ami_tls_cfg.enabled;
10058 }
10059
10060 ast_sockaddr_parse(&ami_desc_local_address_tmp, "[::]", 0);
10061 ast_sockaddr_set_port(&ami_desc_local_address_tmp, DEFAULT_MANAGER_PORT);
10062
10063 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
10064 val = var->value;
10065
10066 /* read tls config options while preventing unsupported options from being set */
10067 if (strcasecmp(var->name, "tlscafile")
10068 && strcasecmp(var->name, "tlscapath")
10069 && strcasecmp(var->name, "tlscadir")
10070 && strcasecmp(var->name, "tlsverifyclient")
10071 && strcasecmp(var->name, "tlsdontverifyserver")
10072 && strcasecmp(var->name, "tlsclientmethod")
10073 && strcasecmp(var->name, "sslclientmethod")
10074 && !ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
10075 continue;
10076 }
10077
10078 if (!strcasecmp(var->name, "enabled")) {
10080 } else if (!strcasecmp(var->name, "webenabled")) {
10082 } else if (!strcasecmp(var->name, "port")) {
10083 int bindport;
10084 if (ast_parse_arg(val, PARSE_UINT32|PARSE_IN_RANGE, &bindport, 1024, 65535)) {
10085 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
10086 }
10087 ast_sockaddr_set_port(&ami_desc_local_address_tmp, bindport);
10088 } else if (!strcasecmp(var->name, "bindaddr")) {
10089 /* remember port if it has already been set */
10090 int setport = ast_sockaddr_port(&ami_desc_local_address_tmp);
10091
10093 ast_log(LOG_WARNING, "Invalid address '%s' specified, default '%s' will be used\n", val,
10094 ast_sockaddr_stringify_addr(&ami_desc_local_address_tmp));
10095 } else {
10096 ast_sockaddr_parse(&ami_desc_local_address_tmp, val, PARSE_PORT_IGNORE);
10097 }
10098
10099 if (setport) {
10100 ast_sockaddr_set_port(&ami_desc_local_address_tmp, setport);
10101 }
10102
10103 } else if (!strcasecmp(var->name, "brokeneventsaction")) {
10105 } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
10107 } else if (!strcasecmp(var->name, "displayconnects")) {
10109 } else if (!strcasecmp(var->name, "timestampevents")) {
10111 } else if (!strcasecmp(var->name, "debug")) {
10113 } else if (!strcasecmp(var->name, "httptimeout")) {
10114 newhttptimeout = atoi(val);
10115 } else if (!strcasecmp(var->name, "authtimeout")) {
10116 int timeout = atoi(var->value);
10117
10118 if (timeout < 1) {
10119 ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
10120 } else {
10121 authtimeout = timeout;
10122 }
10123 } else if (!strcasecmp(var->name, "authlimit")) {
10124 int limit = atoi(var->value);
10125
10126 if (limit < 1) {
10127 ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
10128 } else {
10129 authlimit = limit;
10130 }
10131 } else if (!strcasecmp(var->name, "channelvars")) {
10133 } else if (!strcasecmp(var->name, "disabledevents")) {
10135 } else {
10136 ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
10137 var->name, val);
10138 }
10139 }
10140
10141 if (manager_enabled && !subscribed) {
10142 if (subscribe_all() != 0) {
10143 ast_log(LOG_ERROR, "Manager subscription error\n");
10144 return -1;
10145 }
10146 }
10147
10148 ast_sockaddr_copy(&amis_desc_local_address_tmp, &amis_desc.local_address);
10149
10150 /* if the amis address has not been set, default is the same as non secure ami */
10151 if (ast_sockaddr_isnull(&amis_desc_local_address_tmp)) {
10152 ast_sockaddr_copy(&amis_desc_local_address_tmp, &ami_desc_local_address_tmp);
10153 }
10154
10155 /* if the amis address was not set, it will have non-secure ami port set; if
10156 amis address was set, we need to check that a port was set or not, if not
10157 use the default tls port */
10158 if (ast_sockaddr_port(&amis_desc_local_address_tmp) == 0 ||
10159 (ast_sockaddr_port(&ami_desc_local_address_tmp) == ast_sockaddr_port(&amis_desc_local_address_tmp))) {
10160
10161 ast_sockaddr_set_port(&amis_desc_local_address_tmp, DEFAULT_MANAGER_TLS_PORT);
10162 }
10163
10164 if (manager_enabled) {
10165 ast_sockaddr_copy(&ami_desc.local_address, &ami_desc_local_address_tmp);
10166 ast_sockaddr_copy(&amis_desc.local_address, &amis_desc_local_address_tmp);
10167 }
10168
10170
10171 /* First, get users from users.conf */
10172 ucfg = ast_config_load2("users.conf", "manager", config_flags);
10173 if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
10174 const char *hasmanager;
10175 int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
10176
10177 while ((cat = ast_category_browse(ucfg, cat))) {
10178 if (!strcasecmp(cat, "general")) {
10179 continue;
10180 }
10181
10182 hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
10183 if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
10184 const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
10185 const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
10186 const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
10187 const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
10188 const char *user_allowmultiplelogin = ast_variable_retrieve(ucfg, cat, "allowmultiplelogin");
10189 const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
10190
10191 /* Look for an existing entry,
10192 * if none found - create one and add it to the list
10193 */
10194 if (!(user = get_manager_by_name_locked(cat))) {
10195 if (!(user = ast_calloc(1, sizeof(*user)))) {
10196 break;
10197 }
10198
10199 /* Copy name over */
10200 ast_copy_string(user->username, cat, sizeof(user->username));
10201 /* Insert into list */
10203 user->acl = NULL;
10204 user->keep = 1;
10205 user->readperm = -1;
10206 user->writeperm = -1;
10207 /* Default displayconnect from [general] */
10208 user->displayconnects = displayconnects;
10209 /* Default allowmultiplelogin from [general] */
10210 user->allowmultiplelogin = allowmultiplelogin;
10211 user->writetimeout = 100;
10212 }
10213
10214 if (!user_secret) {
10215 user_secret = ast_variable_retrieve(ucfg, "general", "secret");
10216 }
10217 if (!user_read) {
10218 user_read = ast_variable_retrieve(ucfg, "general", "read");
10219 }
10220 if (!user_write) {
10221 user_write = ast_variable_retrieve(ucfg, "general", "write");
10222 }
10223 if (!user_displayconnects) {
10224 user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
10225 }
10226 if (!user_allowmultiplelogin) {
10227 user_allowmultiplelogin = ast_variable_retrieve(ucfg, "general", "allowmultiplelogin");
10228 }
10229 if (!user_writetimeout) {
10230 user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
10231 }
10232
10233 if (!ast_strlen_zero(user_secret)) {
10234 ast_free(user->secret);
10235 user->secret = ast_strdup(user_secret);
10236 }
10237
10238 if (user_read) {
10239 user->readperm = get_perm(user_read);
10240 }
10241 if (user_write) {
10242 user->writeperm = get_perm(user_write);
10243 }
10244 if (user_displayconnects) {
10245 user->displayconnects = ast_true(user_displayconnects);
10246 }
10247 if (user_allowmultiplelogin) {
10248 user->allowmultiplelogin = ast_true(user_allowmultiplelogin);
10249 }
10250 if (user_writetimeout) {
10251 int value = atoi(user_writetimeout);
10252 if (value < 100) {
10253 ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value);
10254 } else {
10255 user->writetimeout = value;
10256 }
10257 }
10258 }
10259 }
10260 ast_config_destroy(ucfg);
10261 }
10262
10263 /* cat is NULL here in any case */
10264
10265 while ((cat = ast_category_browse(cfg, cat))) {
10266 struct ast_acl_list *oldacl;
10267
10268 if (!strcasecmp(cat, "general")) {
10269 continue;
10270 }
10271
10272 /* Look for an existing entry, if none found - create one and add it to the list */
10273 if (!(user = get_manager_by_name_locked(cat))) {
10274 if (!(user = ast_calloc(1, sizeof(*user)))) {
10275 break;
10276 }
10277 /* Copy name over */
10278 ast_copy_string(user->username, cat, sizeof(user->username));
10279
10280 user->acl = NULL;
10281 user->readperm = 0;
10282 user->writeperm = 0;
10283 /* Default displayconnect from [general] */
10284 user->displayconnects = displayconnects;
10285 /* Default allowmultiplelogin from [general] */
10286 user->allowmultiplelogin = allowmultiplelogin;
10287 user->writetimeout = 100;
10290 if (!user->whitefilters || !user->blackfilters) {
10292 break;
10293 }
10294
10295 /* Insert into list */
10297 } else {
10298 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
10299 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
10300 }
10301
10302 /* Make sure we keep this user and don't destroy it during cleanup */
10303 user->keep = 1;
10304 oldacl = user->acl;
10305 user->acl = NULL;
10306 ast_variables_destroy(user->chanvars);
10307
10308 var = ast_variable_browse(cfg, cat);
10309 for (; var; var = var->next) {
10310 if (!strcasecmp(var->name, "secret")) {
10311 ast_free(user->secret);
10312 user->secret = ast_strdup(var->value);
10313 } else if (!strcasecmp(var->name, "deny") ||
10314 !strcasecmp(var->name, "permit") ||
10315 !strcasecmp(var->name, "acl")) {
10316 int acl_error = 0;
10317
10318 ast_append_acl(var->name, var->value, &user->acl, &acl_error, &acl_subscription_flag);
10319 if (acl_error) {
10320 ast_log(LOG_ERROR, "Invalid ACL '%s' for manager user '%s' on line %d. Deleting user\n",
10321 var->value, user->username, var->lineno);
10322 user->keep = 0;
10323 }
10324 } else if (!strcasecmp(var->name, "read") ) {
10325 user->readperm = get_perm(var->value);
10326 } else if (!strcasecmp(var->name, "write") ) {
10327 user->writeperm = get_perm(var->value);
10328 } else if (!strcasecmp(var->name, "displayconnects") ) {
10329 user->displayconnects = ast_true(var->value);
10330 } else if (!strcasecmp(var->name, "allowmultiplelogin") ) {
10331 user->allowmultiplelogin = ast_true(var->value);
10332 } else if (!strcasecmp(var->name, "writetimeout")) {
10333 int value = atoi(var->value);
10334 if (value < 100) {
10335 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
10336 } else {
10337 user->writetimeout = value;
10338 }
10339 } else if (!strcasecmp(var->name, "setvar")) {
10340 struct ast_variable *tmpvar;
10341 char varbuf[256];
10342 char *varval;
10343 char *varname;
10344
10345 ast_copy_string(varbuf, var->value, sizeof(varbuf));
10346 varname = varbuf;
10347
10348 if ((varval = strchr(varname,'='))) {
10349 *varval++ = '\0';
10350 if ((tmpvar = ast_variable_new(varname, varval, ""))) {
10351 tmpvar->next = user->chanvars;
10352 user->chanvars = tmpvar;
10353 }
10354 }
10355 } else if (!strcasecmp(var->name, "eventfilter")) {
10356 const char *value = var->value;
10357 manager_add_filter(value, user->whitefilters, user->blackfilters);
10358 } else {
10359 ast_debug(1, "%s is an unknown option.\n", var->name);
10360 }
10361 }
10362
10363 oldacl = ast_free_acl_list(oldacl);
10364 }
10365 ast_config_destroy(cfg);
10366
10367 /* Check the flag for named ACL event subscription and if we need to, register a subscription. */
10368 if (acl_subscription_flag && !by_external_config) {
10370 }
10371
10372 /* Perform cleanup - essentially prune out old users that no longer exist */
10374 if (user->keep) { /* valid record. clear flag for the next round */
10375 user->keep = 0;
10376
10377 /* Calculate A1 for Digest auth */
10378 snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
10379 ast_md5_hash(a1_hash,a1);
10380 ast_free(user->a1_hash);
10381 user->a1_hash = ast_strdup(a1_hash);
10382 continue;
10383 }
10384 /* We do not need to keep this user so take them out of the list */
10386 ast_debug(4, "Pruning user '%s'\n", user->username);
10388 }
10390
10392
10394 if (!webregged) {
10398
10402 webregged = 1;
10403 }
10404 } else {
10405 if (webregged) {
10409
10413 webregged = 0;
10414 }
10415 }
10416
10417 if (newhttptimeout > 0) {
10418 httptimeout = newhttptimeout;
10419 }
10420
10422 if (tls_was_enabled && !ami_tls_cfg.enabled) {
10424 } else if (ast_ssl_setup(amis_desc.tls_cfg)) {
10426 }
10427
10428 return 0;
10429}
10430
10431static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
10432 struct stasis_message *message)
10433{
10435 return;
10436 }
10437
10438 /* For now, this is going to be performed simply and just execute a forced reload. */
10439 ast_log(LOG_NOTICE, "Reloading manager in response to ACL change event.\n");
10440 __init_manager(1, 1);
10441}
10442
10443static int unload_module(void)
10444{
10445 return 0;
10446}
10447
10448static int load_module(void)
10449{
10451
10453}
10454
10455static int reload_module(void)
10456{
10457 return __init_manager(1, 0);
10458}
10459
10460int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
10461{
10462 AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
10463
10464 return 0;
10465}
10466
10467int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
10468{
10469 return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
10470}
10471
10472struct ast_datastore *astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
10473{
10474 struct ast_datastore *datastore = NULL;
10475
10476 if (info == NULL)
10477 return NULL;
10478
10480 if (datastore->info != info) {
10481 continue;
10482 }
10483
10484 if (uid == NULL) {
10485 /* matched by type only */
10486 break;
10487 }
10488
10489 if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
10490 /* Matched by type AND uid */
10491 break;
10492 }
10493 }
10495
10496 return datastore;
10497}
10498
10499int ast_str_append_event_header(struct ast_str **fields_string,
10500 const char *header, const char *value)
10501{
10502 if (!*fields_string) {
10503 *fields_string = ast_str_create(128);
10504 if (!*fields_string) {
10505 return -1;
10506 }
10507 }
10508
10509 return (ast_str_append(fields_string, 0, "%s: %s\r\n", header, value) < 0) ? -1 : 0;
10510}
10511
10512static void manager_event_blob_dtor(void *obj)
10513{
10514 struct ast_manager_event_blob *ev = obj;
10515
10517}
10518
10520__attribute__((format(printf, 3, 4)))
10522 int event_flags,
10523 const char *manager_event,
10524 const char *extra_fields_fmt,
10525 ...)
10526{
10527 struct ast_manager_event_blob *ev;
10528 va_list argp;
10529
10530 ast_assert(extra_fields_fmt != NULL);
10532
10534 if (!ev) {
10535 return NULL;
10536 }
10537
10538 if (ast_string_field_init(ev, 20)) {
10539 ao2_ref(ev, -1);
10540 return NULL;
10541 }
10542
10545
10546 va_start(argp, extra_fields_fmt);
10547 ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt, argp);
10548 va_end(argp);
10549
10550 return ev;
10551}
10552
10554 .support_level = AST_MODULE_SUPPORT_CORE,
10555 .load = load_module,
10556 .unload = unload_module,
10558 .load_pri = AST_MODPRI_CORE,
10559 .requires = "extconfig,acl,http",
Access Control of various sorts.
enum ast_acl_sense ast_apply_acl(struct ast_acl_list *acl_list, const struct ast_sockaddr *addr, const char *purpose)
Apply a set of rules to a given IP address.
Definition: acl.c:799
struct stasis_message_type * ast_named_acl_change_type(void)
a stasis_message_type for changes against a named ACL or the set of all named ACLs
void ast_acl_output(int fd, struct ast_acl_list *acl, const char *prefix)
output an ACL to the provided fd
Definition: acl.c:1098
void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag)
Add a rule to an ACL struct.
Definition: acl.c:429
@ AST_SENSE_DENY
Definition: acl.h:37
int ast_acl_list_is_empty(struct ast_acl_list *acl_list)
Determines if an ACL is empty or if it contains entries.
Definition: acl.c:540
struct ast_acl_list * ast_free_acl_list(struct ast_acl_list *acl)
Free a list of ACLs.
Definition: acl.c:233
integer order
Definition: analys.c:66
Generic Advice of Charge encode and decode routines.
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:313
int ast_aoc_s_add_rate_duration(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item, unsigned int amount, enum ast_aoc_currency_multiplier multiplier, const char *currency_name, unsigned long time, enum ast_aoc_time_scale time_scale, unsigned long granularity_time, enum ast_aoc_time_scale granularity_time_scale, int step_function)
Add AOC-S duration rate entry.
Definition: aoc.c:770
ast_aoc_s_charged_item
Definition: aoc.h:145
@ AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION
Definition: aoc.h:148
@ AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT
Definition: aoc.h:147
@ AST_AOC_CHARGED_ITEM_NA
Definition: aoc.h:146
@ AST_AOC_CHARGED_ITEM_USER_USER_INFO
Definition: aoc.h:151
@ AST_AOC_CHARGED_ITEM_CALL_SETUP
Definition: aoc.h:150
@ AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE
Definition: aoc.h:152
@ AST_AOC_CHARGED_ITEM_CALL_ATTEMPT
Definition: aoc.h:149
ast_aoc_charge_type
Definition: aoc.h:69
@ AST_AOC_CHARGE_CURRENCY
Definition: aoc.h:72
@ AST_AOC_CHARGE_FREE
Definition: aoc.h:71
@ AST_AOC_CHARGE_UNIT
Definition: aoc.h:73
@ AST_AOC_CHARGE_NA
Definition: aoc.h:70
ast_aoc_time_scale
Definition: aoc.h:87
@ AST_AOC_TIME_SCALE_TEN_SECOND
Definition: aoc.h:91
@ AST_AOC_TIME_SCALE_DAY
Definition: aoc.h:94
@ AST_AOC_TIME_SCALE_TENTH_SECOND
Definition: aoc.h:89
@ AST_AOC_TIME_SCALE_MINUTE
Definition: aoc.h:92
@ AST_AOC_TIME_SCALE_SECOND
Definition: aoc.h:90
@ AST_AOC_TIME_SCALE_HOUR
Definition: aoc.h:93
@ AST_AOC_TIME_SCALE_HUNDREDTH_SECOND
Definition: aoc.h:88
ast_aoc_volume_unit
Definition: aoc.h:125
@ AST_AOC_VOLUME_UNIT_OCTET
Definition: aoc.h:126
@ AST_AOC_VOLUME_UNIT_SEGMENT
Definition: aoc.h:127
@ AST_AOC_VOLUME_UNIT_MESSAGE
Definition: aoc.h:128
int ast_aoc_s_add_rate_special_charge_code(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item, unsigned int code)
Add AOC-S special rate entry.
Definition: aoc.c:844
ast_aoc_currency_multiplier
Defines the currency multiplier for an aoc message.
Definition: aoc.h:34
@ AST_AOC_MULT_TEN
Definition: aoc.h:39
@ AST_AOC_MULT_ONEHUNDREDTH
Definition: aoc.h:36
@ AST_AOC_MULT_HUNDRED
Definition: aoc.h:40
@ AST_AOC_MULT_ONETENTH
Definition: aoc.h:37
@ AST_AOC_MULT_ONETHOUSANDTH
Definition: aoc.h:35
@ AST_AOC_MULT_THOUSAND
Definition: aoc.h:41
@ AST_AOC_MULT_ONE
Definition: aoc.h:38
struct ast_aoc_decoded * ast_aoc_create(const enum ast_aoc_type msg_type, const enum ast_aoc_charge_type charge_type, const enum ast_aoc_request requests)
creates a ast_aoc_decode object of a specific message type
Definition: aoc.c:276
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:307
int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan)
set the charging association number for an AOC-E message
Definition: aoc.c:1056
int ast_aoc_add_unit_entry(struct ast_aoc_decoded *decoded, const unsigned int amount_is_present, const unsigned int amount, const unsigned int type_is_present, const unsigned int type)
Adds a unit entry into the list of units.
Definition: aoc.c:977
ast_aoc_billing_id
Defines the billing id options for an aoc message.
Definition: aoc.h:49
@ AST_AOC_BILLING_CALL_FWD_BUSY
Definition: aoc.h:55
@ AST_AOC_BILLING_CALL_FWD_NO_REPLY
Definition: aoc.h:56
@ AST_AOC_BILLING_NORMAL
Definition: aoc.h:51
@ AST_AOC_BILLING_CALL_DEFLECTION
Definition: aoc.h:57
@ AST_AOC_BILLING_CREDIT_CARD
Definition: aoc.h:53
@ AST_AOC_BILLING_CALL_TRANSFER
Definition: aoc.h:58
@ AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL
Definition: aoc.h:54
@ AST_AOC_BILLING_REVERSE_CHARGE
Definition: aoc.h:52
@ AST_AOC_BILLING_NA
Definition: aoc.h:50
int ast_aoc_s_add_rate_free(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item, int from_beginning)
Add AOC-S indicating charge item is free.
Definition: aoc.c:857
int ast_aoc_set_billing_id(struct ast_aoc_decoded *decoded, const enum ast_aoc_billing_id id)
set the billing id for a AOC-D or AST_AOC_E message
Definition: aoc.c:1024
int ast_aoc_s_add_special_arrangement(struct ast_aoc_decoded *decoded, unsigned int code)
Add AOC-S special arrangement entry.
Definition: aoc.c:880
int ast_aoc_set_currency_info(struct ast_aoc_decoded *decoded, const unsigned int amount, const enum ast_aoc_currency_multiplier multiplier, const char *name)
Sets the currency values for a AOC-D or AOC-E message.
Definition: aoc.c:919
int ast_aoc_set_association_id(struct ast_aoc_decoded *decoded, const int id)
set the charging association id for an AST_AOC_E message
Definition: aoc.c:1040
int ast_aoc_s_add_rate_flat(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item, unsigned int amount, enum ast_aoc_currency_multiplier multiplier, const char *currency_name)
Add AOC-S flat rate entry.
Definition: aoc.c:801
struct ast_aoc_encoded * ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
encodes a decoded aoc structure so it can be passed on the wire
Definition: aoc.c:650
int ast_aoc_set_total_type(struct ast_aoc_decoded *decoded, const enum ast_aoc_total_type type)
Sets the type of total for a AOC-D message.
Definition: aoc.c:907
int ast_aoc_s_add_rate_volume(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item, enum ast_aoc_volume_unit volume_unit, unsigned int amount, enum ast_aoc_currency_multiplier multiplier, const char *currency_name)
Add AOC-S volume rate entry.
Definition: aoc.c:822
ast_aoc_type
Definition: aoc.h:62
@ AST_AOC_S
Definition: aoc.h:64
@ AST_AOC_D
Definition: aoc.h:65
@ AST_AOC_E
Definition: aoc.h:66
unsigned int ast_aoc_s_get_count(struct ast_aoc_decoded *decoded)
get the number rates associated with an AOC-S message
Definition: aoc.c:756
int ast_aoc_s_add_rate_na(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item)
Add AOC-S entry indicating charge item is not available.
Definition: aoc.c:869
ast_aoc_total_type
Definition: aoc.h:82
@ AST_AOC_TOTAL
Definition: aoc.h:83
@ AST_AOC_SUBTOTAL
Definition: aoc.h:84
ast_aoc_s_rate_type
Definition: aoc.h:155
@ AST_AOC_RATE_TYPE_VOLUME
Definition: aoc.h:161
@ AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING
Definition: aoc.h:158
@ AST_AOC_RATE_TYPE_SPECIAL_CODE
Definition: aoc.h:162
@ AST_AOC_RATE_TYPE_NA
Definition: aoc.h:156
@ AST_AOC_RATE_TYPE_DURATION
Definition: aoc.h:159
@ AST_AOC_RATE_TYPE_FLAT
Definition: aoc.h:160
@ AST_AOC_RATE_TYPE_FREE
Definition: aoc.h:157
static const char app[]
Definition: app_adsiprog.c:56
static const struct adsi_event events[]
Definition: app_adsiprog.c:85
char digit
jack_status_t status
Definition: app_jack.c:146
const char * str
Definition: app_jack.c:147
static volatile unsigned int seq
Definition: app_sms.c:120
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define var
Definition: ast_expr2f.c:605
Asterisk version information.
const char * ast_get_version(void)
Retrieve the Asterisk version string.
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
int ast_shutting_down(void)
Definition: asterisk.c:1872
#define AST_FILE_MODE
Definition: asterisk.h:32
#define PATH_MAX
Definition: asterisk.h:40
static struct ast_mansession session
void ast_std_free(void *ptr)
Definition: astmm.c:1734
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_t_ref(o, delta, tag)
Definition: astobj2.h:460
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#define OBJ_KEY
Definition: astobj2.h:1151
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
#define ao2_t_global_obj_replace_unref(holder, obj, tag)
Definition: astobj2.h:904
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1723
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_t_link(container, obj, tag)
Definition: astobj2.h:1534
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_t_callback_data(container, flags, cb_fn, arg, data, tag)
ao2_callback_data() is a generic function that applies cb_fn() to all objects in a container....
Definition: astobj2.h:1721
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:407
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_t_global_obj_release(holder, tag)
Definition: astobj2.h:861
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
Definition: astobj2.h:1696
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
@ AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT
Reject duplicate objects in container.
Definition: astobj2.h:1201
Bridging API.
enum ast_transfer_result ast_bridge_transfer_blind(int is_external, struct ast_channel *transferer, const char *exten, const char *context, transfer_channel_cb new_channel_cb, void *user_data)
Blind transfer target to the extension and context provided.
Definition: bridge.c:4425
@ AST_BRIDGE_TRANSFER_NOT_PERMITTED
Definition: bridge.h:1102
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition: bridge.h:1100
@ AST_BRIDGE_TRANSFER_INVALID
Definition: bridge.h:1104
@ AST_BRIDGE_TRANSFER_FAIL
Definition: bridge.h:1106
static struct prometheus_metrics_provider provider
Definition: bridges.c:201
static int tmp()
Definition: bt_open.c:389
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
Definition: callerid.c:1063
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()'s,...
Definition: callerid.c:1002
enum cc_state state
Definition: ccss.c:393
int ast_cdr_is_enabled(void)
Return TRUE if CDR subsystem is enabled.
Definition: cdr.c:2923
static int priority
static PGresult * result
Definition: cel_pgsql.c:84
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2365
static const char type[]
Definition: chan_ooh323.c:109
static struct unistimsession * sessions
static int chancount
Definition: channel.c:93
General Asterisk PBX channel definitions.
struct varshead * ast_channel_get_manager_vars(struct ast_channel *chan)
Gets the variables for a given channel, as specified by ast_channel_set_manager_vars().
Definition: channel.c:7982
const char * ast_channel_name(const struct ast_channel *chan)
#define AST_MAX_PUBLIC_UNIQUEID
Definition: channel.h:147
const char * ast_channel_data(const struct ast_channel *chan)
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11033
struct varshead * ast_channel_varshead(struct ast_channel *chan)
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1360
void ast_channel_set_manager_vars(size_t varc, char **vars)
Sets the variables to be stored in the manager_vars field of all snapshots.
Definition: channel.c:7886
#define ast_channel_lock(chan)
Definition: channel.h:2922
struct ast_trans_pvt * ast_channel_readtrans(const struct ast_channel *chan)
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
struct ast_trans_pvt * ast_channel_writetrans(const struct ast_channel *chan)
ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan)
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1422
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition: channel.c:1139
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
int ast_check_hangup_locked(struct ast_channel *chan)
Definition: channel.c:459
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
Definition: channel.c:1434
void ast_channel_softhangup_withcause_locked(struct ast_channel *chan, int causecode)
Lock the given channel, then request softhangup on the channel with the given causecode.
Definition: channel.c:468
int ast_queue_control_data(struct ast_channel *chan, enum ast_control_frame_type control, const void *data, size_t datalen)
Queue a control frame with payload.
Definition: channel.c:1238
const char * ast_channel_appl(const struct ast_channel *chan)
struct timeval ast_channel_creationtime(struct ast_channel *chan)
int ast_active_channels(void)
returns number of active/allocated channels
Definition: channel.c:499
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10544
struct ast_bridge * ast_channel_get_bridge(const struct ast_channel *chan)
Get the bridge associated with a channel.
Definition: channel.c:10533
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4652
#define AST_CHANNEL_NAME
Definition: channel.h:171
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
ast_group_t ast_channel_callgroup(const struct ast_channel *chan)
struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan)
void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval offset)
Set when to hang a channel up.
Definition: channel.c:510
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1282
@ AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT
Definition: channel.h:1035
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1408
#define ast_channel_unlock(chan)
Definition: channel.h:2923
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
const char * ast_var_value(const struct ast_var_t *var)
Definition: chanvars.c:80
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define AST_CLI_YESNO(x)
Return Yes or No depending on the argument.
Definition: cli.h:71
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2758
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define RESULT_SUCCESS
Definition: cli.h:40
ast_cli_command
calling arguments for new-style handlers.
Definition: cli.h:151
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define AST_MAX_CMD_LEN
Definition: cli.h:48
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static struct ao2_container * codecs
Registered codecs.
Definition: codec.c:48
@ AST_MEDIA_TYPE_UNKNOWN
Definition: codec.h:31
static struct channel_usage channels
Local proxy channel special access.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2206
#define max(a, b)
Definition: f2c.h:198
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
Generic File Format Support. Should be included by clients of the file handling routines....
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
Media Format Cache API.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:324
int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
Parse an "allow" or "deny" list and modify a format capabilities structure accordingly.
Definition: format_cap.c:320
void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
Remove all formats matching a specific format type.
Definition: format_cap.c:523
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition: format_cap.c:734
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
static const char name[]
Definition: format_mp3.c:68
static char * synopsis
Definition: func_enum.c:154
static int md5(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_md5.c:52
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:807
static int action_setvar(struct mansession *s, const struct message *m)
Definition: manager.c:4854
static int blackfilter_cmp_fn(void *obj, void *arg, void *data, int flags)
Definition: manager.c:6662
static int action_createconfig(struct mansession *s, const struct message *m)
Definition: manager.c:4455
static void purge_events(void)
Definition: manager.c:2108
static char * handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:2465
static int manager_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: manager.c:8044
static void mansession_unlock(struct mansession *s)
Unlock the 'mansession' structure.
Definition: manager.c:3452
static int action_loggerrotate(struct mansession *s, const struct message *m)
Manager command "LoggerRotate" - reloads and rotates the logger in the same manner as the CLI command...
Definition: manager.c:7205
int __ast_manager_event_multichan(int category, const char *event, int chancount, struct ast_channel **chans, const char *file, int line, const char *func, const char *fmt,...)
Definition: manager.c:7989
#define GET_HEADER_LAST_MATCH
Definition: manager.c:2962
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3396
static int purge_sessions(int n_max)
remove at most n_max stale session from the list.
Definition: manager.c:7776
static int process_message(struct mansession *s, const struct message *m)
Process an AMI message, performing desired action. Return 0 on success, -1 on error that require the ...
Definition: manager.c:7348
static int strings_to_mask(const char *string)
Definition: manager.c:2277
static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance)
Definition: manager.c:9571
static int __manager_event_sessions(struct ao2_container *sessions, int category, const char *event, int chancount, struct ast_channel **chans, const char *file, int line, const char *func, const char *fmt,...)
Definition: manager.c:7967
static struct ast_manager_user * get_manager_by_name_locked(const char *name)
Definition: manager.c:2430
static void acl_change_stasis_subscribe(void)
Definition: manager.c:1658
static char * handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager list eventq.
Definition: manager.c:2901
static void log_action(const struct message *m, const char *action)
Definition: manager.c:7309
static struct mansession_session * build_mansession(const struct ast_sockaddr *addr)
Allocate manager session structure and add it to the list of sessions.
Definition: manager.c:2354
static void report_invalid_user(const struct mansession *s, const char *username)
Definition: manager.c:3480
static int manager_enabled
Definition: manager.c:1593
int ast_manager_check_enabled(void)
Check if AMI is enabled.
Definition: manager.c:2074
static void astman_free_headers(struct message *m)
Free headers inside message structure, but not the message structure itself.
Definition: manager.c:3039
static int action_sendtext(struct mansession *s, const struct message *m)
Definition: manager.c:5210
static int action_mailboxcount(struct mansession *s, const struct message *m)
Definition: manager.c:6523
static void manager_json_to_ast_str(struct ast_json *obj, const char *key, struct ast_str **res, key_exclusion_cb exclusion_cb)
Definition: manager.c:1905
static int ast_manager_register_struct(struct manager_action *act)
Definition: manager.c:8085
static int queue_read_action_payload(struct ast_channel *chan, const unsigned char *payload, size_t payload_size, enum ast_frame_read_action action)
Queue a given read action containing a payload onto a channel.
Definition: manager.c:5142
static AO2_GLOBAL_OBJ_STATIC(mgr_sessions)
static int whitefilter_cmp_fn(void *obj, void *arg, void *data, int flags)
Definition: manager.c:6648
static struct manager_action * action_find(const char *name)
Definition: manager.c:1829
static int action_getconfigjson(struct mansession *s, const struct message *m)
Definition: manager.c:4007
int ast_webmanager_check_enabled(void)
Check if AMI/HTTP is enabled.
Definition: manager.c:2079
static const struct @371 command_blacklist[]
void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
Send response in manager transaction.
Definition: manager.c:3349
static void report_failed_acl(const struct mansession *s, const char *username)
Definition: manager.c:3505
static int action_listcategories(struct mansession *s, const struct message *m)
Definition: manager.c:3941
static int action_hangup(struct mansession *s, const struct message *m)
Definition: manager.c:4848
static void mansession_lock(struct mansession *s)
Lock the 'mansession' structure.
Definition: manager.c:3446
static int action_listcommands(struct mansession *s, const struct message *m)
Definition: manager.c:4591
static void destroy_fast_originate_helper(struct fast_originate_helper *doomed)
Definition: manager.c:5683
static int action_atxfer(struct mansession *s, const struct message *m)
Definition: manager.c:5444
static struct ast_threadstorage manager_event_buf
Definition: manager.c:7857
static int action_timeout(struct mansession *s, const struct message *m)
Definition: manager.c:6614
static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters)
Add an event filter to a manager session.
Definition: manager.c:6733
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3354
static struct stasis_subscription * acl_change_sub
Definition: manager.c:1606
static void generate_status(struct mansession *s, struct ast_channel *chan, char **vars, int varc, int all_variables, char *id_text, int *count)
Definition: manager.c:4939
static int do_message(struct mansession *s)
Definition: manager.c:7597
void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt,...)
Send error in manager transaction (with va_args support)
Definition: manager.c:3359
static void manager_default_msg_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: manager.c:1963
static int action_coresettings(struct mansession *s, const struct message *m)
Show PBX core settings information.
Definition: manager.c:6847
static int mansession_cmp_fn(void *obj, void *arg, int flags)
Definition: manager.c:2387
static int displayconnects
Definition: manager.c:1588
static int action_filter(struct mansession *s, const struct message *m)
Manager command to add an event filter to a manager session.
Definition: manager.c:6681
static int manager_debug
Definition: manager.c:1596
static int action_mailboxstatus(struct mansession *s, const struct message *m)
Definition: manager.c:6506
static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
Definition: manager.c:7840
static int action_login(struct mansession *s, const struct message *m)
Definition: manager.c:4660
static int action_getvar(struct mansession *s, const struct message *m)
Definition: manager.c:4887
static int get_input(struct mansession *s, char *output)
Definition: manager.c:7476
static int action_blind_transfer(struct mansession *s, const struct message *m)
Definition: manager.c:5398
static const char * user_authority_to_str(int authority, struct ast_str **res)
Convert authority code to a list of options for a user. This will only display those authority codes ...
Definition: manager.c:2185
static struct mansession_session * unref_mansession(struct mansession_session *s)
Unreference manager session object. If no more references, then go ahead and delete it.
Definition: manager.c:2308
#define ASTMAN_APPEND_BUF_INITSIZE
initial allocated size for the astman_append_buf and astman_send_*_va
Definition: manager.c:3261
void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
Publish an event to AMI.
Definition: manager.c:2028
static void session_destroy(struct mansession_session *s)
Definition: manager.c:2394
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3432
#define MAX_VARS
Definition: manager.c:1632
struct stasis_message_router * ast_manager_get_message_router(void)
Get the stasis_message_router for AMI.
Definition: manager.c:1850
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1845
static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
send a response with an optional message, and terminate it with an empty line. m is used only to grab...
Definition: manager.c:3318
static void astman_append_json(struct mansession *s, const char *str)
Definition: manager.c:3998
#define MGR_SHOW_TERMINAL_WIDTH
Definition: manager.c:1630
static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
helper function for action_updateconfig
Definition: manager.c:4081
static int action_extensionstate(struct mansession *s, const struct message *m)
Definition: manager.c:6544
static char * handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager list connected.
Definition: manager.c:2850
static int action_getconfig(struct mansession *s, const struct message *m)
Definition: manager.c:3869
static void event_filter_destructor(void *obj)
Definition: manager.c:2317
static void * session_do(void *data)
The body of the individual manager session. Call get_input() to read one line at a time (or be woken ...
Definition: manager.c:7682
static struct eventqent * advance_event(struct eventqent *e)
Definition: manager.c:2948
static struct ast_threadstorage astman_append_buf
Definition: manager.c:3256
error_type
Definition: manager.c:1537
static int restrictedFile(const char *filename)
Check if a file is restricted or not.
Definition: manager.c:3836
static int coreshowchannelmap_add_connected_channels(struct ao2_container *channel_map, struct ast_channel_snapshot *channel_snapshot, struct ast_bridge_snapshot *bridge_snapshot)
Recursive function to get all channels in a bridge. Follow local channels as well.
Definition: manager.c:7047
static void session_destructor(void *obj)
Definition: manager.c:2323
static struct stasis_message_router * stasis_router
The stasis_message_router for all Stasis Message Bus API messages.
Definition: manager.c:1612
static void json_escape(char *out, const char *in)
Definition: manager.c:3980
static int manager_displayconnects(struct mansession_session *session)
Get displayconnects config option.
Definition: manager.c:2447
static int action_logoff(struct mansession *s, const struct message *m)
Definition: manager.c:4654
static char * handle_kickmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager kick session.
Definition: manager.c:2780
static int action_updateconfig(struct mansession *s, const struct message *m)
Definition: manager.c:4364
static void astman_start_ack(struct mansession *s, const struct message *m)
Definition: manager.c:3391
static const char * __astman_get_header(const struct message *m, char *var, int mode)
Return a matching header value.
Definition: manager.c:2978
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3386
STASIS_MESSAGE_TYPE_DEFN(ast_manager_get_generic_type)
Define AMI message types.
static void handle_parse_error(struct mansession *s, struct message *m, char *error)
Definition: manager.c:7580
static int manager_moduleload(struct mansession *s, const struct message *m)
Definition: manager.c:7246
static void acl_change_stasis_unsubscribe(void)
Definition: manager.c:1668
static int reload_module(void)
Definition: manager.c:10455
static void manager_json_array_with_key(struct ast_json *obj, const char *key, size_t index, struct ast_str **res, key_exclusion_cb exclusion_cb)
Definition: manager.c:1880
static void astman_append_headers(struct message *m, const struct ast_variable *params)
Append additional headers into the message structure from params.
Definition: manager.c:3025
static void report_failed_challenge_response(const struct mansession *s, const char *response, const char *expected_response)
Definition: manager.c:3638
#define any_manager_listeners(sessions)
Definition: manager.c:1960
static int action_reload(struct mansession *s, const struct message *m)
Send a reload event.
Definition: manager.c:6931
struct ast_variable * astman_get_variables(const struct message *m)
Get a linked list of the Variable: headers.
Definition: manager.c:3101
static int live_dangerously
Set to true (non-zero) to globally allow all dangerous AMI actions to run.
Definition: manager.c:1623
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:1946
static struct eventqent * grab_last(void)
Definition: manager.c:2088
add_filter_result
Definition: manager.c:1552
static int authlimit
Definition: manager.c:1598
static struct stasis_forward * rtp_topic_forwarder
The stasis_subscription for forwarding the RTP topic to the AMI topic.
Definition: manager.c:1615
static int action_aocmessage(struct mansession *s, const struct message *m)
Definition: manager.c:6234
static char * handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:2695
static int check_manager_session_inuse(const char *name)
Definition: manager.c:2407
static int check_blacklist(const char *cmd)
Definition: manager.c:5539
static int action_events(struct mansession *s, const struct message *m)
Definition: manager.c:4610
void ast_manager_unregister_hook(struct manager_custom_hook *hook)
Delete a custom hook to be called when an event is fired.
Definition: manager.c:2067
static void astman_flush(struct mansession *s, struct ast_str *buf)
Definition: manager.c:3263
static const char * authority_to_str(int authority, struct ast_str **res)
Convert authority code to a list of options. Note that the EVENT_FLAG_ALL authority will always be re...
Definition: manager.c:2209
static int action_redirect(struct mansession *s, const struct message *m)
action_redirect: The redirect manager command
Definition: manager.c:5253
#define MSG_MOREDATA
Definition: manager.c:3309
static struct stasis_forward * security_topic_forwarder
The stasis_subscription for forwarding the Security topic to the AMI topic.
Definition: manager.c:1618
static int action_presencestate(struct mansession *s, const struct message *m)
Definition: manager.c:6574
struct ast_variable * astman_get_variables_order(const struct message *m, enum variable_orders order)
Get a linked list of the Variable: headers with order specified.
Definition: manager.c:3106
static char * manager_channelvars
Definition: manager.c:1599
void ast_manager_register_hook(struct manager_custom_hook *hook)
Add a custom hook to be called when an event is fired.
Definition: manager.c:2059
#define DEFAULT_REALM
Definition: manager.c:1602
static int allowmultiplelogin
Definition: manager.c:1589
static void manager_json_value_str_append(struct ast_json *value, const char *key, struct ast_str **res)
Definition: manager.c:1855
static int queue_sendtext_data(struct ast_channel *chan, const char *body, const char *content_type)
Queue a read action to send a text data message.
Definition: manager.c:5191
const char * astman_get_header(const struct message *m, char *var)
Return the first matching variable from an array.
Definition: manager.c:3015
#define GET_HEADER_SKIP_EMPTY
Definition: manager.c:2963
static struct ast_threadstorage userevent_buf
Definition: manager.c:3258
static enum ast_transport mansession_get_transport(const struct mansession *s)
Definition: manager.c:3474
static int function_capable_string_allowed_with_auths(const char *evaluating, int writepermlist)
Checks to see if a string which can be used to evaluate functions should be rejected.
Definition: manager.c:2171
static char * handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:2622
static int action_cancel_atxfer(struct mansession *s, const struct message *m)
Definition: manager.c:5498
static void report_req_not_allowed(const struct mansession *s, const char *action)
Definition: manager.c:3580
static char global_realm[MAXHOSTNAMELEN]
Definition: manager.c:1603
static int action_originate(struct mansession *s, const struct message *m)
Definition: manager.c:6293
static int send_string(struct mansession *s, char *string)
Definition: manager.c:3220
#define MAX_AUTH_PERM_STRING
Definition: manager.c:2168
static int action_userevent(struct mansession *s, const struct message *m)
Definition: manager.c:6826
static int action_command(struct mansession *s, const struct message *m)
Manager command "command" - execute CLI command.
Definition: manager.c:5575
static void report_inval_password(const struct mansession *s, const char *username)
Definition: manager.c:3530
static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
Definition: manager.c:2237
#define MAX_BLACKLIST_CMD_LEN
Descriptor for a manager session, either on the AMI socket or over HTTP.
Definition: manager.c:1647
int ast_manager_register2(const char *action, int auth, int(*func)(struct mansession *s, const struct message *m), struct ast_module *module, const char *synopsis, const char *description)
register a new command with manager, including online help. This is the preferred way to register a m...
Definition: manager.c:8140
static int process_events(struct mansession *s)
Definition: manager.c:6798
static int broken_events_action
Definition: manager.c:1592
static void report_session_limit(const struct mansession *s)
Definition: manager.c:3668
static int unauth_sessions
Definition: manager.c:1605
static int set_eventmask(struct mansession *s, const char *eventmask)
Rather than braindead on,off this now can also accept a specific int mask value or a ',...
Definition: manager.c:3461
static int timestampevents
Definition: manager.c:1590
static int subscribed
Definition: manager.c:1594
static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: manager.c:1994
static struct ast_aoc_decoded * action_aoc_s_message(struct mansession *s, const struct message *m)
Definition: manager.c:6191
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3440
static char * handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager reload.
Definition: manager.c:2929
static struct ast_aoc_decoded * action_aoc_de_message(struct mansession *s, const struct message *m)
Definition: manager.c:5796
static int authenticate(struct mansession *s, const struct message *m)
Definition: manager.c:3700
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3275
static void manager_json_obj_with_key(struct ast_json *obj, const char *key, const char *parent_key, struct ast_str **res, key_exclusion_cb exclusion_cb)
Definition: manager.c:1890
static int authtimeout
Definition: manager.c:1597
static char * handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager list commands.
Definition: manager.c:2738
#define EVENT_FLAG_SHUTDOWN
Fake event class used to end sessions at shutdown.
Definition: manager.c:1635
static int manager_modulecheck(struct mansession *s, const struct message *m)
Manager function to check if module is loaded.
Definition: manager.c:7217
static void astman_send_list_complete(struct mansession *s, const struct message *m, const char *event_name, int count)
Definition: manager.c:3423
void astman_live_dangerously(int new_live_dangerously)
Enable/disable the inclusion of 'dangerous' configurations outside of the ast_config_AST_CONFIG_DIR.
Definition: manager.c:3815
int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
access for hooks to send action messages to ami
Definition: manager.c:3132
static int action_aoc_s_submessage(struct mansession *s, const struct message *m, struct ast_aoc_decoded *decoded)
Definition: manager.c:5967
static int webmanager_enabled
Definition: manager.c:1595
static struct ast_str * astman_send_list_complete_start_common(struct mansession *s, const struct message *m, const char *event_name, int count)
Definition: manager.c:3401
static int action_status(struct mansession *s, const struct message *m)
Manager "status" command to show channels.
Definition: manager.c:5054
static int match_filter(struct mansession *s, char *eventdata)
Definition: manager.c:6764
static int get_perm(const char *instr)
Definition: manager.c:2256
static int action_coreshowchannels(struct mansession *s, const struct message *m)
Manager command "CoreShowChannels" - List currently defined channels and some information about them.
Definition: manager.c:6963
static struct ast_variable * man_do_variable_value(struct ast_variable *head, const char *hdr_val)
Definition: manager.c:3057
static int action_corestatus(struct mansession *s, const struct message *m)
Show PBX core status information.
Definition: manager.c:6891
static int queue_sendtext(struct ast_channel *chan, const char *body)
Queue a read action to send a text message.
Definition: manager.c:5175
static void action_destroy(void *obj)
Definition: manager.c:8126
static int action_challenge(struct mansession *s, const struct message *m)
Definition: manager.c:4709
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:1609
static int action_waitevent(struct mansession *s, const struct message *m)
Definition: manager.c:4473
static void report_req_bad_format(const struct mansession *s, const char *action)
Definition: manager.c:3609
static int append_event(const char *str, int category)
events are appended to a queue from where they can be dispatched to clients.
Definition: manager.c:7816
static int action_coreshowchannelmap(struct mansession *s, const struct message *m)
Manager command "CoreShowChannelMap" - Lists all channels connected to the specified channel.
Definition: manager.c:7131
mansession_message_parsing
Definition: manager.c:1740
static char * handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:2597
static int action_ping(struct mansession *s, const struct message *m)
Definition: manager.c:3797
#define GET_HEADER_FIRST_MATCH
Definition: manager.c:2961
static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
Definition: manager.c:5771
static int coreshowchannelmap_add_to_map(struct ao2_container *c, const char *s)
Helper function to add a channel name to the vector.
Definition: manager.c:7030
int ast_manager_hangup_helper(struct mansession *s, const struct message *m, manager_hangup_handler_t hangup_handler, manager_hangup_cause_validator_t cause_validator)
A manager helper function that hangs up a channel using a supplied channel type specific hangup funct...
Definition: manager.c:4727
static int httptimeout
Definition: manager.c:1591
static void report_auth_success(const struct mansession *s)
Definition: manager.c:3555
static void * fast_originate(void *data)
Definition: manager.c:5691
static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: manager.c:10431
#define MANAGER_EVENT_BUF_INITSIZE
Definition: manager.c:7858
static const struct permalias perms[]
#define manager_event_sessions(sessions, category, event, contents,...)
Definition: manager.c:1957
static char * manager_disabledevents
Definition: manager.c:1600
static int __manager_event_sessions_va(struct ao2_container *sessions, int category, const char *event, int chancount, struct ast_channel **chans, const char *file, int line, const char *func, const char *fmt, va_list ap)
Definition: manager.c:7860
int ast_manager_unregister(const char *action)
support functions to register/unregister AMI action handlers,
Definition: manager.c:8014
@ FAILURE_EMPTYCAT
Definition: manager.c:1545
@ FAILURE_UPDATE
Definition: manager.c:1546
@ FAILURE_NEWCAT
Definition: manager.c:1543
@ FAILURE_DELETE
Definition: manager.c:1547
@ FAILURE_APPEND
Definition: manager.c:1548
@ UNKNOWN_CATEGORY
Definition: manager.c:1539
@ FAILURE_DELCAT
Definition: manager.c:1544
@ FAILURE_ALLOCATION
Definition: manager.c:1542
@ FAILURE_TEMPLATE
Definition: manager.c:1549
@ UNSPECIFIED_CATEGORY
Definition: manager.c:1540
@ UNSPECIFIED_ARGUMENT
Definition: manager.c:1541
@ UNKNOWN_ACTION
Definition: manager.c:1538
@ FILTER_SUCCESS
Definition: manager.c:1553
@ FILTER_COMPILE_FAIL
Definition: manager.c:1555
@ FILTER_ALLOC_FAILED
Definition: manager.c:1554
@ MESSAGE_OKAY
Definition: manager.c:1741
@ MESSAGE_LINE_TOO_LONG
Definition: manager.c:1742
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
struct ast_channel_snapshot * ast_channel_snapshot_get_latest_by_name(const char *name)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
struct ao2_container * ast_channel_cache_by_name(void)
Secondary channel cache, indexed by name.
struct ast_msg_data * ast_msg_data_alloc2(enum ast_msg_data_source_type source_type, const char *to, const char *from, const char *content_type, const char *body)
Allocates an ast_msg_data structure.
size_t ast_msg_data_get_length(struct ast_msg_data *msg)
Get length of the structure.
@ AST_MSG_DATA_SOURCE_TYPE_UNKNOWN
Definition: message.h:447
int ast_option_maxfiles
Definition: options.c:81
int ast_option_maxcalls
Definition: options.c:79
double ast_option_maxload
Definition: options.c:77
struct ast_flags ast_options
Definition: options.c:61
@ AST_OPT_FLAG_FULLY_BOOTED
Definition: options.h:58
static ENTRY retval
Definition: hsearch.c:50
static int session_limit
Definition: http.c:106
Support for Private Asterisk HTTP Servers.
void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, int fd, unsigned int static_content)
Generic function for sending HTTP/1.1 response.
Definition: http.c:459
struct ast_variable * ast_http_get_post_vars(struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlenco...
Definition: http.c:1356
ast_http_method
HTTP Request methods known by Asterisk.
Definition: http.h:58
@ AST_HTTP_POST
Definition: http.h:61
@ AST_HTTP_GET
Definition: http.h:60
@ AST_HTTP_HEAD
Definition: http.h:62
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
Definition: http.c:708
uint32_t ast_http_manid_from_vars(struct ast_variable *headers) attribute_pure
Return manager id, if exist, from request headers.
Definition: http.c:220
const char * ast_get_http_method(enum ast_http_method method) attribute_pure
Return http method name string.
Definition: http.c:193
void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm, const unsigned long nonce, const unsigned long opaque, int stale, const char *text)
Send http "401 Unauthorized" response and close socket.
Definition: http.c:625
void ast_http_request_close_on_completion(struct ast_tcptls_session_instance *ser)
Request the HTTP connection be closed after this HTTP request.
Definition: http.c:840
void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text)
Send HTTP error message and close socket.
Definition: http.c:651
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
Definition: http.c:676
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
int ast_app_has_voicemail(const char *mailboxes, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX"....
Definition: main/app.c:582
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Determine number of urgent/new/old messages in a mailbox.
Definition: main/app.c:619
char * strsep(char **str, const char *delims)
char * strcasestr(const char *, const char *)
Configuration File Parser.
void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
Definition: main/config.c:383
int ast_category_inherit(struct ast_category *existing, const struct ast_category *base)
Applies base (template) to category.
Definition: main/config.c:1456
const char * ast_category_get_name(const struct ast_category *category)
Return the name of the category.
Definition: main/config.c:1117
struct ast_category * ast_category_new_template(const char *name, const char *in_file, int lineno)
Create a category making it a template.
Definition: main/config.c:1084
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: main/config.c:3321
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
struct ast_category * ast_category_delete(struct ast_config *cfg, struct ast_category *cat)
Delete a category.
Definition: main/config.c:1567
int ast_config_text_file_save2(const char *filename, const struct ast_config *cfg, const char *generator, uint32_t flags)
Save a config text file.
Definition: main/config.c:2725
void ast_category_rename(struct ast_category *cat, const char *name)
Definition: main/config.c:1451
int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
Definition: main/config.c:1488
#define CONFIG_STATUS_FILEMISSING
int ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
Inserts new category.
Definition: main/config.c:1172
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
Definition: extconf.c:2833
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition: extconf.c:1177
int ast_variable_update(struct ast_category *category, const char *variable, const char *value, const char *match, unsigned int object)
Update variable value within a config.
Definition: main/config.c:1533
struct ast_variable * ast_variables_reverse(struct ast_variable *var)
Reverse a variable list.
Definition: main/config.c:565
int ast_realtime_enabled(void)
Check if there's any realtime engines loaded.
Definition: main/config.c:3544
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category.
Definition: extconf.c:2788
#define ast_variable_new(name, value, filename)
struct ast_str * ast_category_get_templates(const struct ast_category *category)
Return the template names this category inherits from.
Definition: main/config.c:1127
#define CONFIG_STATUS_FILEUNCHANGED
@ CONFIG_SAVE_FLAG_NONE
@ CONFIG_SAVE_FLAG_PRESERVE_EFFECTIVE_CONTEXT
#define CONFIG_STATUS_FILEINVALID
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
The argument parsing routine.
Definition: main/config.c:3827
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
Definition: main/config.c:543
void ast_category_destroy(struct ast_category *cat)
Definition: extconf.c:2845
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
int ast_category_empty(struct ast_category *category)
Removes and destroys all variables in a category.
Definition: main/config.c:1599
int ast_category_is_template(const struct ast_category *category)
Check if category is a template.
Definition: main/config.c:1122
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:783
struct ast_variable * ast_category_first(struct ast_category *cat)
given a pointer to a category, return the root variable.
Definition: main/config.c:1246
void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
Definition: main/config.c:499
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
Definition: main/config.c:1111
@ CONFIG_FLAG_NOCACHE
@ CONFIG_FLAG_WITHCOMMENTS
@ CONFIG_FLAG_FILEUNCHANGED
struct ast_category * ast_category_browse_filtered(struct ast_config *config, const char *category_name, struct ast_category *prev, const char *filter)
Browse categories with filters.
Definition: main/config.c:1424
#define AST_FEATURE_MAX_LEN
int ast_get_builtin_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
Get the DTMF code for a builtin feature.
char * ast_get_chan_features_atxferabort(struct ast_channel *chan)
Get the transfer configuration option atxferabort.
ast_frame_read_action
Actions to indicate to, and be handled on channel read.
@ AST_FRAME_READ_ACTION_SEND_TEXT
@ AST_FRAME_READ_ACTION_SEND_TEXT_DATA
#define AST_FRAME_DTMF
@ AST_CONTROL_READ_ACTION
@ AST_CONTROL_AOC
int ast_logger_rotate(void)
Reload logger while rotating log files.
Definition: logger.c:1315
#define AST_LOG_WARNING
#define AST_LOG_ERROR
#define ast_debug(level,...)
Log a DEBUG message.
#define VERBOSITY_ATLEAST(level)
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
void ast_iostream_set_timeout_inactivity(struct ast_iostream *stream, int timeout)
Set the iostream inactivity timeout timer.
Definition: iostream.c:121
struct ast_iostream * ast_iostream_from_fd(int *fd)
Create an iostream from a file descriptor.
Definition: iostream.c:604
ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buffer, size_t count)
Write data to an iostream.
Definition: iostream.c:374
int ast_iostream_get_fd(struct ast_iostream *stream)
Get an iostream's file descriptor.
Definition: iostream.c:84
void ast_iostream_set_exclusive_input(struct ast_iostream *stream, int exclusive_input)
Set the iostream if it can exclusively depend upon the set timeouts.
Definition: iostream.c:148
ssize_t ast_iostream_read(struct ast_iostream *stream, void *buffer, size_t count)
Read data from an iostream.
Definition: iostream.c:273
void ast_iostream_set_timeout_sequence(struct ast_iostream *stream, struct timeval start, int timeout)
Set the iostream I/O sequence timeout timer.
Definition: iostream.c:139
void ast_iostream_nonblock(struct ast_iostream *stream)
Make an iostream non-blocking.
Definition: iostream.c:103
int ast_iostream_close(struct ast_iostream *stream)
Close an iostream.
Definition: iostream.c:528
void ast_iostream_set_timeout_disable(struct ast_iostream *stream)
Disable the iostream timeout timer.
Definition: iostream.c:113
Asterisk JSON abstraction layer.
struct ast_json * ast_json_object_iter_value(struct ast_json_iter *iter)
Get the value from an iterator.
Definition: json.c:455
enum ast_json_type ast_json_typeof(const struct ast_json *value)
Get the type of value.
Definition: json.c:78
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json_iter * ast_json_object_iter_next(struct ast_json *object, struct ast_json_iter *iter)
Get the next iterator.
Definition: json.c:447
struct ast_json * ast_json_array_get(const struct ast_json *array, size_t index)
Get an element from an array.
Definition: json.c:370
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
Definition: json.c:756
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
struct ast_json_iter * ast_json_object_iter(struct ast_json *object)
Get an iterator pointing to the first field in a JSON object.
Definition: json.c:439
@ AST_JSON_STRING
Definition: json.h:166
@ AST_JSON_ARRAY
Definition: json.h:165
@ AST_JSON_OBJECT
Definition: json.h:164
@ AST_JSON_FALSE
Definition: json.h:170
@ AST_JSON_INTEGER
Definition: json.h:167
@ AST_JSON_TRUE
Definition: json.h:169
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
const char * ast_json_object_iter_key(struct ast_json_iter *iter)
Get the key from an iterator.
Definition: json.c:451
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:332
size_t ast_json_array_size(const struct ast_json *array)
Get the size of a JSON array.
Definition: json.c:366
int ast_json_is_null(const struct ast_json *value)
Check if value is JSON null.
Definition: json.c:273
A set of macros to manage forward-linked lists.
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:452
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:570
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:545
#define AST_RWLIST_LAST
Definition: linkedlists.h:431
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
Definition: linkedlists.h:333
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:844
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_RWLIST_INSERT_AFTER
Definition: linkedlists.h:702
#define AST_RWLIST_NEXT
Definition: linkedlists.h:441
#define AST_RWLIST_REMOVE
Definition: linkedlists.h:885
#define AST_RWLIST_FIRST
Definition: linkedlists.h:423
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:741
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:415
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
Asterisk locking-related definitions:
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_unlock(a)
Definition: lock.h:190
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
#define ast_mutex_destroy(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:189
int errno
static int auth_mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:9277
static int manager_subscriptions_init(void)
Initialize all Stasis Message Bus API topics and routers used by the various sub-components of AMI.
Definition: manager.c:9844
#define ROW_FMT
static struct ast_tls_config ami_tls_cfg
Definition: manager.c:9416
static void close_mansession_file(struct mansession *s)
Definition: manager.c:8629
static int ast_xml_doc_item_cmp_fn(const void *a, const void *b)
Definition: manager.c:9483
static struct ast_tcptls_session_args ami_desc
Definition: manager.c:9417
static struct ast_http_uri managerxmluri
Definition: manager.c:9256
const char * words[AST_MAX_CMD_LEN]
Definition: manager.c:1649
static char * handle_manager_show_events(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:9490
static int manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:9207
int astman_verify_session_writepermissions(uint32_t ident, int perm)
Verify a session's write permissions against a permission mask.
Definition: manager.c:8355
static int __init_manager(int reload, int by_external_config)
Definition: manager.c:9935
static struct ast_tcptls_session_args amis_desc
Definition: manager.c:9428
static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
Definition: manager.c:8393
#define FORMAT3
static struct ast_custom_function managerclient_function
description of AMI_CLIENT dialplan function
Definition: manager.c:9389
static void purge_old_stuff(void *data)
cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most
Definition: manager.c:9400
struct ast_datastore * astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a session.
Definition: manager.c:10472
static struct mansession_session * find_session(uint32_t ident, int incinuse)
Definition: manager.c:8234
static int mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:9218
int ast_str_append_event_header(struct ast_str **fields_string, const char *header, const char *value)
append an event header to an ast string
Definition: manager.c:10499
#define HSMCONN_FORMAT1
int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
Add a datastore to a session.
Definition: manager.c:10460
static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
Definition: manager.c:8472
static char * handle_manager_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager show settings.
Definition: manager.c:9439
static void manager_event_blob_dtor(void *obj)
Definition: manager.c:10512
static void load_channelvars(struct ast_variable *var)
Definition: manager.c:9693
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:10521
static struct mansession_session * find_session_by_nonce(const char *username, unsigned long nonce, int *stale)
Definition: manager.c:8273
int astman_verify_session_readpermissions(uint32_t ident, int perm)
Verify a session's read permissions against a permission mask.
Definition: manager.c:8322
static struct ast_http_uri manageruri
Definition: manager.c:9248
static void manager_set_defaults(void)
Definition: manager.c:9907
static void manager_shutdown(void)
Definition: manager.c:9745
#define HSMC_FORMAT
static void process_output(struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
Definition: manager.c:8639
static int rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:9229
static char * handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:9608
static int function_amiclient(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
${AMI_CLIENT()} Dialplan function - reads manager client data
Definition: manager.c:9342
static int auth_rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:9288
static int load_module(void)
Definition: manager.c:10448
static struct ast_http_uri arawmanuri
Definition: manager.c:9299
static void xml_translate(struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
Convert the input into XML or HTML. The input is supposed to be a sequence of lines of the form Name:...
Definition: manager.c:8511
static int variable_count_hash_fn(const void *vvc, const int flags)
Definition: manager.c:8465
#define FORMAT
int astman_is_authed(uint32_t ident)
Determine if a manager session ident is authenticated.
Definition: manager.c:8306
static struct ast_http_uri rawmanuri
Definition: manager.c:9240
static struct ast_cli_entry cli_manager[]
Definition: manager.c:9670
#define FORMAT2
static int unload_module(void)
Definition: manager.c:10443
static void manager_free_user(struct ast_manager_user *user)
Definition: manager.c:9726
static int auth_manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:9266
output_format
Definition: manager.c:8217
@ FORMAT_RAW
Definition: manager.c:8218
@ FORMAT_HTML
Definition: manager.c:8219
@ FORMAT_XML
Definition: manager.c:8220
static int auth_http_callback(struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, const struct ast_sockaddr *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:8884
static struct ast_http_uri amanageruri
Definition: manager.c:9308
#define TEST_STRING
static int webregged
Definition: manager.c:9395
static int get_manager_sessions_cb(void *obj, void *arg, void *data, int flags)
Get number of logged in sessions for a login name.
Definition: manager.c:9327
static int subscribe_all(void)
Definition: manager.c:9877
static const char *const contenttype[]
Definition: manager.c:8223
static struct ast_http_uri amanagerxmluri
Definition: manager.c:9317
static int generic_http_callback(struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, const struct ast_sockaddr *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:8672
int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
Remove a datastore from a session.
Definition: manager.c:10467
static void load_disabledevents(struct ast_variable *var)
Definition: manager.c:9716
#define HSMCONN_FORMAT2
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_VERBOSE
Definition: manager.h:78
#define EVENT_FLAG_REPORTING
Definition: manager.h:84
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:202
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:253
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
int manager_mwi_init(void)
Initialize support for AMI MWI events.
Definition: manager_mwi.c:155
#define EVENT_FLAG_CONFIG
Definition: manager.h:82
int manager_bridging_init(void)
Initialize support for AMI channel events.
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
#define EVENT_FLAG_TEST
Definition: manager.h:92
variable_orders
Definition: manager.h:287
@ ORDER_NATURAL
Definition: manager.h:288
@ ORDER_REVERSE
Definition: manager.h:289
#define EVENT_FLAG_DTMF
Definition: manager.h:83
#define EVENT_FLAG_SECURITY
Definition: manager.h:93
int manager_endpoints_init(void)
Initialize support for AMI endpoint events.
void(* manager_hangup_handler_t)(struct ast_channel *chan, int causecode)
Callback used by ast_manager_hangup_helper that will actually hangup a channel.
Definition: manager.h:631
int(* key_exclusion_cb)(const char *key)
Callback used to determine whether a key should be skipped when converting a JSON object to a manager...
Definition: manager.h:455
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
#define AMI_VERSION
Definition: manager.h:57
#define DEFAULT_MANAGER_PORT
Definition: manager.h:58
int manager_system_init(void)
Initialize support for AMI system events.
#define EVENT_FLAG_HOOKRESPONSE
Definition: manager.h:89
#define ast_manager_event_multichan(category, event, nchans, chans, contents,...)
Definition: manager.h:260
#define DEFAULT_MANAGER_TLS_PORT
Definition: manager.h:59
#define EVENT_FLAG_CALL
Definition: manager.h:76
#define EVENT_FLAG_MESSAGE
Definition: manager.h:95
#define EVENT_FLAG_COMMAND
Definition: manager.h:79
int manager_channels_init(void)
Initialize support for AMI channel events.
#define EVENT_FLAG_AGI
Definition: manager.h:88
#define EVENT_FLAG_USER
Definition: manager.h:81
#define EVENT_FLAG_AGENT
Definition: manager.h:80
#define EVENT_FLAG_AOC
Definition: manager.h:91
#define EVENT_FLAG_DIALPLAN
Definition: manager.h:86
#define EVENT_FLAG_ORIGINATE
Definition: manager.h:87
#define EVENT_FLAG_CDR
Definition: manager.h:85
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
int(* manager_hangup_cause_validator_t)(const char *channel_name, const char *cause)
Callback used by ast_manager_hangup_helper that will validate the cause code.
Definition: manager.h:642
#define EVENT_FLAG_CC
Definition: manager.h:90
#define EVENT_FLAG_LOG
Definition: manager.h:77
MD5 digest functions.
void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len)
Definition: md5.c:72
void MD5Init(struct MD5Context *context)
Definition: md5.c:57
void MD5Final(unsigned char digest[16], struct MD5Context *context)
Definition: md5.c:120
Out-of-call text message support.
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:316
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
int ast_module_check(const char *name)
Check if module with the name given is loaded.
Definition: loader.c:2669
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode)
Unload a module.
Definition: loader.c:1219
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition: loader.c:1824
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_CORE
Definition: module.h:324
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_FORCE_SOFT
Definition: module.h:62
ast_module_reload_result
Possible return types for ast_module_reload.
Definition: module.h:109
@ AST_MODULE_RELOAD_IN_PROGRESS
Definition: module.h:114
@ AST_MODULE_RELOAD_QUEUED
Definition: module.h:111
@ AST_MODULE_RELOAD_SUCCESS
Definition: module.h:110
@ AST_MODULE_RELOAD_ERROR
Definition: module.h:113
@ AST_MODULE_RELOAD_NOT_IMPLEMENTED
Definition: module.h:116
@ AST_MODULE_RELOAD_NOT_FOUND
Definition: module.h:112
@ AST_MODULE_RELOAD_UNINITIALIZED
Definition: module.h:115
#define ast_module_running_ref(mod)
Hold a reference to the module if it is running.
Definition: module.h:455
@ AST_MODULE_LOAD_FAILURE
Module could not be loaded properly.
Definition: module.h:102
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:1567
Asterisk MWI API.
def info(msg)
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:517
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
Definition: netsock2.h:167
ast_transport
Definition: netsock2.h:59
@ AST_TRANSPORT_TLS
Definition: netsock2.h:62
@ AST_TRANSPORT_TCP
Definition: netsock2.h:61
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. "null" in this sense essentially means uninitialized,...
Definition: netsock2.h:127
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:532
static char * ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:286
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
Definition: netsock2.h:138
#define MAXHOSTNAMELEN
Definition: network.h:69
struct timeval ast_lastreloadtime
Definition: asterisk.c:337
struct timeval ast_startuptime
Definition: asterisk.c:336
#define ast_opt_sounds_search_custom
Definition: options.h:138
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_RUN_GROUP
Definition: options.c:169
const char * ast_config_AST_RUN_USER
Definition: options.c:168
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:151
const char * ast_config_AST_SYSTEM_NAME
Definition: options.c:170
Core PBX routines and definitions.
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
Definition: pbx.c:4180
int ast_pbx_outgoing_exten_predial(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, int early_media, const struct ast_assigned_ids *assignedids, const char *predial_callee)
Definition: pbx.c:7926
const char * ast_extension_state2str(int extension_state)
Return string representation of the state of an extension.
Definition: pbx.c:3126
@ AST_OUTGOING_WAIT
Definition: pbx.h:1141
int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, const struct ast_assigned_ids *assignedids)
Synchronously or asynchronously make an outbound call and execute an application on the channel.
Definition: pbx.c:7980
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4175
int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, int early_media, const struct ast_assigned_ids *assignedids)
Synchronously or asynchronously make an outbound call and send it to a particular extension.
Definition: pbx.c:7916
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
Register a custom function.
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
Retrieve the value of a builtin variable or variable from the channel variable stack.
@ AST_HINT_UPDATE_DEVICE
Definition: pbx.h:91
@ AST_HINT_UPDATE_PRESENCE
Definition: pbx.h:93
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition: pbx.c:3823
int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
If an extension hint exists, return non-zero.
Definition: pbx.c:4137
int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Set the channel to next execute the specified dialplan location.
Definition: pbx.c:6969
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
Uses hint and devicestate callback to get the state of an extension.
Definition: pbx.c:3170
Presence state management.
ast_presence_state
Definition: presencestate.h:26
@ AST_PRESENCE_INVALID
Definition: presencestate.h:39
const char * ast_presence_state2str(enum ast_presence_state state)
Convert presence state to text string for output.
static struct templates templates
static int total
Definition: res_adsi.c:970
static char user[512]
static int reload(void)
struct stasis_forward * sub
Definition: res_corosync.c:240
const char * method
Definition: res_pjsip.c:1279
#define NULL
Definition: resample.c:96
Pluggable RTP Architecture.
struct stasis_topic * ast_rtp_topic(void)
Stasis Message Bus API topic for RTP and RTCP related messages
Definition: rtp_engine.c:3573
Security Event Reporting API.
int ast_security_event_report(const struct ast_security_event_common *sec)
Report a security event.
struct stasis_topic * ast_security_topic(void)
A stasis_topic which publishes messages for security related issues.
#define AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION
Event descriptor version.
#define AST_SECURITY_EVENT_SESSION_LIMIT_VERSION
Event descriptor version.
#define AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION
Event descriptor version.
#define AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION
Event descriptor version.
#define AST_SECURITY_EVENT_FAILED_ACL_VERSION
Event descriptor version.
#define AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION
Event descriptor version.
#define AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION
Event descriptor version.
@ AST_SECURITY_EVENT_INVAL_PASSWORD
An attempt at basic password authentication failed.
@ AST_SECURITY_EVENT_SESSION_LIMIT
Session limit reached.
@ AST_SECURITY_EVENT_FAILED_ACL
Failed ACL.
@ AST_SECURITY_EVENT_REQ_NOT_ALLOWED
A request was made that is not allowed.
@ AST_SECURITY_EVENT_CHAL_RESP_FAILED
An attempt at challenge/response authentication failed.
@ AST_SECURITY_EVENT_REQ_BAD_FORMAT
Request received with bad formatting.
@ AST_SECURITY_EVENT_SUCCESSFUL_AUTH
FYI FWIW, Successful authentication has occurred.
@ AST_SECURITY_EVENT_INVAL_ACCT_ID
Invalid Account ID.
#define AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION
Event descriptor version.
#define AST_SEC_EVT(e)
struct ast_manager_event_blob * stasis_message_to_ami(struct stasis_message *msg)
Build the AMI representation of the message.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition: stasis.h:297
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition: stasis.c:1548
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition: stasis.c:617
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1023
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1077
@ STASIS_SUBSCRIPTION_FORMATTER_AMI
Definition: stasis.h:311
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1134
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition: stasis.c:1578
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1511
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:649
int stasis_message_can_be_ami(struct stasis_message *msg)
Determine if the given message can be converted to AMI.
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *bridge_id)
Returns the current snapshot for the bridge.
int stasis_message_router_set_congestion_limits(struct stasis_message_router *router, long low_water, long high_water)
Set the high and low alert water marks of the stasis message router.
#define stasis_message_router_create(topic)
Create a new message router object.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed.
void stasis_message_router_set_formatters_default(struct stasis_message_router *router, stasis_subscription_cb callback, void *data, enum stasis_subscription_message_formatters formatters)
Sets the default route of a router with formatters.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define ast_string_field_ptr_build_va(x, ptr, fmt, args)
Set a field to a complex (built) value with prebuilt va_lists.
Definition: stringfields.h:573
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
@ AST_DYNSTR_BUILD_FAILED
Definition: strings.h:943
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
Definition: strings.h:1030
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
static int force_inline attribute_pure ast_ends_with(const char *str, const char *suffix)
Checks whether a string ends with another.
Definition: strings.h:116
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
@ AST_STRSEP_STRIP
Definition: strings.h:255
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216
#define ast_str_alloca(init_len)
Definition: strings.h:848
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
int ast_in_delimited_string(const char *needle, const char *haystack, char delim)
Check if there is an exact match for 'needle' between delimiters in 'haystack'.
Definition: strings.c:433
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
int ast_str_append_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Append to a dynamic string using a va_list.
Definition: strings.h:1048
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
Definition: strings.h:186
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition: strings.h:97
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
struct ao2_container * ast_str_container_alloc_options(enum ao2_alloc_opts opts, int buckets)
Allocates a hash container for bare strings.
Definition: strings.c:200
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
Definition: strings.c:205
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition: utils.c:1835
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
int ast_regex_string_to_regex_pattern(const char *regex_string, struct ast_str **regex_pattern)
Given a string regex_string in the form of "/regex/", convert it into the form of "regex".
Definition: utils.c:2179
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:909
Definition: md5.h:26
const char * name
list of actions registered
Definition: manager.c:1790
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Wrapper for an ast_acl linked list.
Definition: acl.h:76
Definition: aoc.h:178
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:604
const char * uniqueid2
Definition: channel.h:606
const char * uniqueid
Definition: channel.h:605
Structure that contains a snapshot of information about a bridge.
Definition: bridge.h:314
struct ao2_container * channels
Definition: bridge.h:331
Structure that contains information about a bridge.
Definition: bridge.h:349
const ast_string_field uniqueid
Definition: bridge.h:401
struct ast_category * prev
Definition: main/config.c:244
const ast_string_field uniqueid
const ast_string_field name
const ast_string_field data
const ast_string_field appl
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_dialplan * dialplan
struct ast_channel_snapshot_bridge * bridge
struct ast_channel_snapshot_base * base
Main Channel structure associated with a channel.
const ast_string_field name
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
enum ast_frame_read_action action
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * name
Definition: pbx.h:119
Structure for a data store type.
Definition: datastore.h:31
Structure for a data store object.
Definition: datastore.h:64
const struct ast_datastore_info * info
Definition: datastore.h:67
const char * uid
Definition: datastore.h:65
Structure used to handle boolean flags.
Definition: utils.h:199
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Data structure associated with a single frame of data.
Definition of a URI handler.
Definition: http.h:102
const char * description
Definition: http.h:104
const char * uri
Definition: http.h:105
void * data
Definition: http.h:116
Iterator for JSON object key/values.
struct ast_json * json
Definition: json.h:1083
Abstract JSON element (object, array, string, int, ...).
Struct containing info for an AMI event to send out.
Definition: manager.h:502
const ast_string_field extra_fields
Definition: manager.h:507
const char * manager_event
Definition: manager.h:504
user descriptor, as read from the config file.
Definition: manager.c:1769
struct ast_variable * chanvars
Definition: manager.c:1782
char username[80]
Definition: manager.c:1770
struct ao2_container * whitefilters
Definition: manager.c:1778
int allowmultiplelogin
Definition: manager.c:1776
struct ao2_container * blackfilters
Definition: manager.c:1779
struct ast_acl_list * acl
Definition: manager.c:1780
char * a1_hash
Definition: manager.c:1781
Structure used to transport a message through the frame core.
Structure for mutex and tracking information.
Definition: lock.h:135
Information needed to identify an endpoint in a call.
Definition: channel.h:338
struct ast_party_name name
Subscriber name.
Definition: channel.h:340
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:279
char * str
Subscriber name (Malloced)
Definition: channel.h:264
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:297
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291
An attempt at challenge/response auth failed.
const char * response
Response received.
struct ast_security_event_common common
Common security event descriptor elements.
const char * expected_response
Response expected to be received.
enum ast_security_event_type event_type
The security event sub-type.
Checking against an IP access control list failed.
struct ast_security_event_common common
Common security event descriptor elements.
Invalid account ID specified (invalid username, for example)
struct ast_security_event_common common
Common security event descriptor elements.
An attempt at basic password auth failed.
struct ast_security_event_common common
Common security event descriptor elements.
Invalid formatting of request.
struct ast_security_event_common common
Common security event descriptor elements.
const char * request_type
Request type that was made.
Request denied because it's not allowed.
struct ast_security_event_common common
Common security event descriptor elements.
const char * request_type
Request type that was made.
Request denied because of a session limit.
struct ast_security_event_common common
Common security event descriptor elements.
Socket address structure.
Definition: netsock2.h:97
Support for dynamic strings.
Definition: strings.h:623
arguments for the accepting thread
Definition: tcptls.h:130
struct ast_sockaddr local_address
Definition: tcptls.h:131
struct ast_tls_config * tls_cfg
Definition: tcptls.h:135
describes a server instance
Definition: tcptls.h:150
struct ast_iostream * stream
Definition: tcptls.h:161
struct ast_sockaddr remote_address
Definition: tcptls.h:152
struct ast_tcptls_session_args * parent
Definition: tcptls.h:153
int enabled
Definition: tcptls.h:89
char * certfile
Definition: tcptls.h:90
char * cipher
Definition: tcptls.h:92
char * pvtfile
Definition: tcptls.h:91
char * capath
Definition: tcptls.h:94
char * cafile
Definition: tcptls.h:93
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Struct that contains the XML documentation for a particular item. Note that this is an ao2 ref counte...
Definition: xmldoc.h:56
struct ast_str * syntax
Definition: xmldoc.h:58
struct ast_xml_doc_item * next
Definition: xmldoc.h:80
struct ast_str * arguments
Definition: xmldoc.h:62
struct ast_str * description
Definition: xmldoc.h:66
const ast_string_field name
Definition: xmldoc.h:74
struct ast_str * seealso
Definition: xmldoc.h:60
struct ast_str * synopsis
Definition: xmldoc.h:64
Definition: astman.c:88
Definition: search.h:40
Definition: astman.c:222
unsigned int seq
Definition: manager.c:1580
int category
Definition: manager.c:1579
struct timeval tv
Definition: manager.c:1581
int usecount
Definition: manager.c:1578
helper function for originate
Definition: manager.c:5655
struct ast_variable * vars
Definition: manager.c:5675
struct ast_format_cap * cap
Definition: manager.c:5657
const ast_string_field description
Definition: manager.h:163
struct ast_module * module
Definition: manager.h:172
struct ast_xml_doc_item * final_response
Definition: manager.h:167
const ast_string_field synopsis
Definition: manager.h:163
enum ast_doc_src docsrc
Definition: manager.h:174
int(* func)(struct mansession *s, const struct message *m)
Definition: manager.h:171
const char * action
Definition: manager.h:156
const ast_string_field seealso
Definition: manager.h:163
const ast_string_field syntax
Definition: manager.h:163
unsigned int registered
TRUE if the AMI action is registered and the callback can be called.
Definition: manager.h:183
const ast_string_field arguments
Definition: manager.h:163
struct ast_xml_doc_item * list_responses
Definition: manager.h:165
manager_hook_t helper
Definition: manager.h:117
list of hooks registered
Definition: manager.c:1793
struct ast_variable * chanvars
Definition: manager.c:1725
unsigned int kicked
Definition: manager.c:1734
struct ast_sockaddr addr
Definition: manager.c:1707
uint32_t managerid
Definition: manager.c:1712
ast_mutex_t notify_lock
Definition: manager.c:1735
pthread_t waiting_thread
Definition: manager.c:1711
char challenge[10]
Definition: manager.c:1717
struct ast_iostream * stream
Definition: manager.c:1708
struct timeval sessionstart_tv
Definition: manager.c:1714
char username[80]
Definition: manager.c:1716
struct ao2_container * whitefilters
Definition: manager.c:1723
time_t sessionstart
Definition: manager.c:1713
unsigned long oldnonce
Definition: manager.c:1732
unsigned long nc
Definition: manager.c:1733
struct ao2_container * blackfilters
Definition: manager.c:1724
struct eventqent * last_ev
Definition: manager.c:1727
time_t sessiontimeout
Definition: manager.c:1715
struct mansession_session::mansession_datastores datastores
struct mansession_session::@372 list
char inbuf[1025]
Definition: manager.c:1721
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:1750
struct ast_iostream * stream
Definition: manager.c:1752
unsigned int write_error
Definition: manager.c:1755
struct manager_custom_hook * hook
Definition: manager.c:1756
struct mansession_session * session
Definition: manager.c:1751
enum mansession_message_parsing parsing
Definition: manager.c:1754
ast_mutex_t lock
Definition: manager.c:1757
struct ast_tcptls_session_instance * tcptls_session
Definition: manager.c:1753
unsigned int hdrcount
Definition: manager.h:150
const char * headers[AST_MAX_MANHEADERS]
Definition: manager.h:151
Number structure.
Definition: app_followme.c:154
int num
Definition: manager.c:2141
const char * label
Definition: manager.c:2142
Forwarding information.
Definition: stasis.c:1531
structure to hold users read from users.conf
list of users found in the config file
Definition: ast_expr2.c:325
char * varname
Definition: manager.c:8461
int value
Definition: syslog.c:37
An API for managing task processing threads that can be shared across modules.
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
Definition: taskprocessor.h:64
Generic support for tcp/tls servers in Asterisk.
void * ast_tcptls_server_root(void *)
Definition: tcptls.c:280
#define AST_CERTFILE
Definition: tcptls.h:63
void ast_tcptls_server_stop(struct ast_tcptls_session_args *desc)
Shutdown a running server if there is one.
Definition: tcptls.c:918
int ast_ssl_setup(struct ast_tls_config *cfg)
Set up an SSL server.
Definition: tcptls.c:570
void ast_tcptls_server_start(struct ast_tcptls_session_args *desc)
This is a generic (re)start routine for a TCP server, which does the socket/bind/listen and starts a ...
Definition: tcptls.c:753
int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value)
Used to parse conf files containing tls/ssl options.
Definition: tcptls.c:944
Handy terminal functions for vt* terms.
#define COLOR_MAGENTA
Definition: term.h:60
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
Definition: term.c:235
char * term_strip(char *outbuf, const char *inbuf, int maxout)
Remove colorings from a specified string.
Definition: term.c:362
Test Framework API.
int done
Definition: test_amihooks.c:48
static struct aco_type item
Definition: test_config.c:1463
const char * args
static struct test_options options
static struct test_val b
static struct test_val a
static struct test_val d
static struct test_val c
Definitions to aid in the use of thread local storage.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:86
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
Definition: time.h:73
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:117
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2297
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Support for translation of data formats. translate.c.
const char * ast_translate_path_to_str(struct ast_trans_pvt *t, struct ast_str **str)
Puts a string representation of the translation path into outbuf.
Definition: translate.c:930
FILE * out
Definition: utils/frame.c:33
int error(const char *format,...)
Definition: utils/frame.c:999
FILE * in
Definition: utils/frame.c:33
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
int ast_wait_for_input(int fd, int ms)
Definition: utils.c:1698
int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic)
Parse digest authorization header.
Definition: utils.c:2638
long int ast_random(void)
Definition: utils.c:2312
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:588
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:666
void ast_md5_hash(char *output, const char *input)
Produces MD5 hash based on input string.
Definition: utils.c:250
struct ast_xml_doc_item * ast_xmldoc_build_list_responses(const char *type, const char *name, const char *module)
Generate the [list responses] tag based on type of node ('application', 'function' or 'agi') and name...
Definition: xmldoc.c:2484
char * ast_xmldoc_build_description(const char *type, const char *name, const char *module)
Generate description documentation from XML.
Definition: xmldoc.c:2271
char * ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
Get the syntax for a specified application or function.
Definition: xmldoc.c:1252
char * ast_xmldoc_build_arguments(const char *type, const char *name, const char *module)
Generate the [arguments] tag based on type of node ('application', 'function' or 'agi') and name.
Definition: xmldoc.c:2084
char * ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
Generate synopsis documentation from XML.
Definition: xmldoc.c:2248
struct ao2_container * ast_xmldoc_build_documentation(const char *type)
Build the documentation for a particular source type.
Definition: xmldoc.c:2684
@ AST_XML_DOC
Definition: xmldoc.h:31
@ AST_STATIC_DOC
Definition: xmldoc.h:32
char * ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
Parse the <see-also> node content.
Definition: xmldoc.c:1702
char * ast_xmldoc_printable(const char *bwinput, int withcolors)
Colorize and put delimiters (instead of tags) to the xmldoc output.
Definition: xmldoc.c:241
struct ast_xml_doc_item * ast_xmldoc_build_final_response(const char *type, const char *name, const char *module)
Generate the [final response] tag based on type of node ('application', 'function' or 'agi') and name...
Definition: xmldoc.c:2554