Bug Summary

File:main/manager.c
Location:line 6684, column 2
Description:String copy function overflows destination buffer

Annotated Source Code

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
57ASTERISK_REGISTER_FILE()static void __attribute__((constructor)) __register_file_version
(void) { __ast_register_file("manager.c"); } static void __attribute__
((destructor)) __unregister_file_version(void) { __ast_unregister_file
("manager.c"); }
58
59#include "asterisk/paths.h" /* use various ast_config_AST_* */
60#include <ctype.h>
61#include <sys/time.h>
62#include <signal.h>
63#include <sys/mman.h>
64#include <sys/types.h>
65#include <regex.h>
66
67#include "asterisk/channel.h"
68#include "asterisk/file.h"
69#include "asterisk/manager.h"
70#include "asterisk/module.h"
71#include "asterisk/config.h"
72#include "asterisk/callerid.h"
73#include "asterisk/lock.h"
74#include "asterisk/cli.h"
75#include "asterisk/app.h"
76#include "asterisk/pbx.h"
77#include "asterisk/md5.h"
78#include "asterisk/acl.h"
79#include "asterisk/utils.h"
80#include "asterisk/tcptls.h"
81#include "asterisk/http.h"
82#include "asterisk/ast_version.h"
83#include "asterisk/threadstorage.h"
84#include "asterisk/linkedlists.h"
85#include "asterisk/term.h"
86#include "asterisk/astobj2.h"
87#include "asterisk/features.h"
88#include "asterisk/security_events.h"
89#include "asterisk/aoc.h"
90#include "asterisk/strings.h"
91#include "asterisk/stringfields.h"
92#include "asterisk/presencestate.h"
93#include "asterisk/stasis_message_router.h"
94#include "asterisk/stasis_channels.h"
95#include "asterisk/stasis_bridges.h"
96#include "asterisk/test.h"
97#include "asterisk/json.h"
98#include "asterisk/bridge.h"
99#include "asterisk/features_config.h"
100#include "asterisk/rtp_engine.h"
101#include "asterisk/format_cache.h"
102#include "asterisk/translate.h"
103#include "asterisk/taskprocessor.h"
104
105/*** DOCUMENTATION
106 <manager name="Ping" language="en_US">
107 <synopsis>
108 Keepalive command.
109 </synopsis>
110 <syntax>
111 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
112 </syntax>
113 <description>
114 <para>A 'Ping' action will ellicit a 'Pong' response. Used to keep the
115 manager connection open.</para>
116 </description>
117 </manager>
118 <manager name="Events" language="en_US">
119 <synopsis>
120 Control Event Flow.
121 </synopsis>
122 <syntax>
123 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
124 <parameter name="EventMask" required="true">
125 <enumlist>
126 <enum name="on">
127 <para>If all events should be sent.</para>
128 </enum>
129 <enum name="off">
130 <para>If no events should be sent.</para>
131 </enum>
132 <enum name="system,call,log,...">
133 <para>To select which flags events should have to be sent.</para>
134 </enum>
135 </enumlist>
136 </parameter>
137 </syntax>
138 <description>
139 <para>Enable/Disable sending of events to this manager client.</para>
140 </description>
141 </manager>
142 <manager name="Logoff" language="en_US">
143 <synopsis>
144 Logoff Manager.
145 </synopsis>
146 <syntax>
147 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
148 </syntax>
149 <description>
150 <para>Logoff the current manager session.</para>
151 </description>
152 </manager>
153 <manager name="Login" language="en_US">
154 <synopsis>
155 Login Manager.
156 </synopsis>
157 <syntax>
158 <parameter name="ActionID">
159 <para>ActionID for this transaction. Will be returned.</para>
160 </parameter>
161 <parameter name="Username" required="true">
162 <para>Username to login with as specified in manager.conf.</para>
163 </parameter>
164 <parameter name="Secret">
165 <para>Secret to login with as specified in manager.conf.</para>
166 </parameter>
167 </syntax>
168 <description>
169 <para>Login Manager.</para>
170 </description>
171 </manager>
172 <manager name="Challenge" language="en_US">
173 <synopsis>
174 Generate Challenge for MD5 Auth.
175 </synopsis>
176 <syntax>
177 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
178 <parameter name="AuthType" required="true">
179 <para>Digest algorithm to use in the challenge. Valid values are:</para>
180 <enumlist>
181 <enum name="MD5" />
182 </enumlist>
183 </parameter>
184 </syntax>
185 <description>
186 <para>Generate a challenge for MD5 authentication.</para>
187 </description>
188 </manager>
189 <manager name="Hangup" language="en_US">
190 <synopsis>
191 Hangup channel.
192 </synopsis>
193 <syntax>
194 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
195 <parameter name="Channel" required="true">
196 <para>The exact channel name to be hungup, or to use a regular expression, set this parameter to: /regex/</para>
197 <para>Example exact channel: SIP/provider-0000012a</para>
198 <para>Example regular expression: /^SIP/provider-.*$/</para>
199 </parameter>
200 <parameter name="Cause">
201 <para>Numeric hangup cause.</para>
202 </parameter>
203 </syntax>
204 <description>
205 <para>Hangup a channel.</para>
206 </description>
207 </manager>
208 <manager name="Status" language="en_US">
209 <synopsis>
210 List channel status.
211 </synopsis>
212 <syntax>
213 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
214 <parameter name="Channel" required="false">
215 <para>The name of the channel to query for status.</para>
216 </parameter>
217 <parameter name="Variables">
218 <para>Comma <literal>,</literal> separated list of variable to include.</para>
219 </parameter>
220 <parameter name="AllVariables">
221 <para>If set to "true", the Status event will include all channel variables for
222 the requested channel(s).</para>
223 <enumlist>
224 <enum name="true"/>
225 <enum name="false"/>
226 </enumlist>
227 </parameter>
228 </syntax>
229 <description>
230 <para>Will return the status information of each channel along with the
231 value for the specified channel variables.</para>
232 </description>
233 <responses>
234 <list-elements>
235 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Status'])" />
236 </list-elements>
237 <xi:include xpointer="xpointer(/docs/managerEvent[@name='StatusComplete'])" />
238 </responses>
239 </manager>
240 <managerEvent language="en_US" name="Status">
241 <managerEventInstance class="EVENT_FLAG_CALL">
242 <synopsis>Raised in response to a Status command.</synopsis>
243 <syntax>
244 <parameter name="ActionID" required="false"/>
245 <channel_snapshot/>
246 <parameter name="Type">
247 <para>Type of channel</para>
248 </parameter>
249 <parameter name="DNID">
250 <para>Dialed number identifier</para>
251 </parameter>
252 <parameter name="TimeToHangup">
253 <para>Absolute lifetime of the channel</para>
254 </parameter>
255 <parameter name="BridgeID">
256 <para>Identifier of the bridge the channel is in, may be empty if not in one</para>
257 </parameter>
258 <parameter name="Linkedid">
259 </parameter>
260 <parameter name="Application">
261 <para>Application currently executing on the channel</para>
262 </parameter>
263 <parameter name="Data">
264 <para>Data given to the currently executing channel</para>
265 </parameter>
266 <parameter name="Nativeformats">
267 <para>Media formats the connected party is willing to send or receive</para>
268 </parameter>
269 <parameter name="Readformat">
270 <para>Media formats that frames from the channel are received in</para>
271 </parameter>
272 <parameter name="Readtrans">
273 <para>Translation path for media received in native formats</para>
274 </parameter>
275 <parameter name="Writeformat">
276 <para>Media formats that frames to the channel are accepted in</para>
277 </parameter>
278 <parameter name="Writetrans">
279 <para>Translation path for media sent to the connected party</para>
280 </parameter>
281 <parameter name="Callgroup">
282 <para>Configured call group on the channel</para>
283 </parameter>
284 <parameter name="Pickupgroup">
285 <para>Configured pickup group on the channel</para>
286 </parameter>
287 <parameter name="Seconds">
288 <para>Number of seconds the channel has been active</para>
289 </parameter>
290 </syntax>
291 <see-also>
292 <ref type="manager">Status</ref>
293 </see-also>
294 </managerEventInstance>
295 </managerEvent>
296 <managerEvent language="en_US" name="StatusComplete">
297 <managerEventInstance class="EVENT_FLAG_CALL">
298 <synopsis>Raised in response to a Status command.</synopsis>
299 <syntax>
300 <parameter name="Items">
301 <para>Number of Status events returned</para>
302 </parameter>
303 </syntax>
304 <see-also>
305 <ref type="manager">Status</ref>
306 </see-also>
307 </managerEventInstance>
308 </managerEvent>
309 <manager name="Setvar" language="en_US">
310 <synopsis>
311 Sets a channel variable or function value.
312 </synopsis>
313 <syntax>
314 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
315 <parameter name="Channel">
316 <para>Channel to set variable for.</para>
317 </parameter>
318 <parameter name="Variable" required="true">
319 <para>Variable name, function or expression.</para>
320 </parameter>
321 <parameter name="Value" required="true">
322 <para>Variable or function value.</para>
323 </parameter>
324 </syntax>
325 <description>
326 <para>This command can be used to set the value of channel variables or dialplan
327 functions.</para>
328 <note>
329 <para>If a channel name is not provided then the variable is considered global.</para>
330 </note>
331 </description>
332 </manager>
333 <manager name="Getvar" language="en_US">
334 <synopsis>
335 Gets a channel variable or function value.
336 </synopsis>
337 <syntax>
338 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
339 <parameter name="Channel">
340 <para>Channel to read variable from.</para>
341 </parameter>
342 <parameter name="Variable" required="true">
343 <para>Variable name, function or expression.</para>
344 </parameter>
345 </syntax>
346 <description>
347 <para>Get the value of a channel variable or function return.</para>
348 <note>
349 <para>If a channel name is not provided then the variable is considered global.</para>
350 </note>
351 </description>
352 </manager>
353 <manager name="GetConfig" language="en_US">
354 <synopsis>
355 Retrieve configuration.
356 </synopsis>
357 <syntax>
358 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
359 <parameter name="Filename" required="true">
360 <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
361 </parameter>
362 <parameter name="Category">
363 <para>Category in configuration file.</para>
364 </parameter>
365 <parameter name="Filter">
366 <para>A comma separated list of
367 <replaceable>name_regex</replaceable>=<replaceable>value_regex</replaceable>
368 expressions which will cause only categories whose variables match all expressions
369 to be considered. The special variable name <literal>TEMPLATES</literal>
370 can be used to control whether templates are included. Passing
371 <literal>include</literal> as the value will include templates
372 along with normal categories. Passing
373 <literal>restrict</literal> as the value will restrict the operation to
374 ONLY templates. Not specifying a <literal>TEMPLATES</literal> expression
375 results in the default behavior which is to not include templates.</para>
376 </parameter>
377 </syntax>
378 <description>
379 <para>This action will dump the contents of a configuration
380 file by category and contents or optionally by specified category only.
381 In the case where a category name is non-unique, a filter may be specified
382 to match only categories with matching variable values.</para>
383 </description>
384 </manager>
385 <manager name="GetConfigJSON" language="en_US">
386 <synopsis>
387 Retrieve configuration (JSON format).
388 </synopsis>
389 <syntax>
390 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
391 <parameter name="Filename" required="true">
392 <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
393 </parameter>
394 <parameter name="Category">
395 <para>Category in configuration file.</para>
396 </parameter>
397 <parameter name="Filter">
398 <xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
399 </parameter>
400 </syntax>
401 <description>
402 <para>This action will dump the contents of a configuration file by category
403 and contents in JSON format or optionally by specified category only.
404 This only makes sense to be used using rawman over the HTTP interface.
405 In the case where a category name is non-unique, a filter may be specified
406 to match only categories with matching variable values.</para>
407 </description>
408 </manager>
409 <manager name="UpdateConfig" language="en_US">
410 <synopsis>
411 Update basic configuration.
412 </synopsis>
413 <syntax>
414 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
415 <parameter name="SrcFilename" required="true">
416 <para>Configuration filename to read (e.g. <filename>foo.conf</filename>).</para>
417 </parameter>
418 <parameter name="DstFilename" required="true">
419 <para>Configuration filename to write (e.g. <filename>foo.conf</filename>)</para>
420 </parameter>
421 <parameter name="Reload">
422 <para>Whether or not a reload should take place (or name of specific module).</para>
423 </parameter>
424 <parameter name="PreserveEffectiveContext">
425 <para>Whether the effective category contents should be preserved on template change. Default is true (pre 13.2 behavior).</para>
426 </parameter>
427 <parameter name="Action-000000">
428 <para>Action to take.</para>
429 <para>0's represent 6 digit number beginning with 000000.</para>
430 <enumlist>
431 <enum name="NewCat" />
432 <enum name="RenameCat" />
433 <enum name="DelCat" />
434 <enum name="EmptyCat" />
435 <enum name="Update" />
436 <enum name="Delete" />
437 <enum name="Append" />
438 <enum name="Insert" />
439 </enumlist>
440 </parameter>
441 <parameter name="Cat-000000">
442 <para>Category to operate on.</para>
443 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
444 </parameter>
445 <parameter name="Var-000000">
446 <para>Variable to work on.</para>
447 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
448 </parameter>
449 <parameter name="Value-000000">
450 <para>Value to work on.</para>
451 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
452 </parameter>
453 <parameter name="Match-000000">
454 <para>Extra match required to match line.</para>
455 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
456 </parameter>
457 <parameter name="Line-000000">
458 <para>Line in category to operate on (used with delete and insert actions).</para>
459 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
460 </parameter>
461 <parameter name="Options-000000">
462 <para>A comma separated list of action-specific options.</para>
463 <enumlist>
464 <enum name="NewCat"><para>One or more of the following... </para>
465 <enumlist>
466 <enum name="allowdups"><para>Allow duplicate category names.</para></enum>
467 <enum name="template"><para>This category is a template.</para></enum>
468 <enum name="inherit=&quot;template[,...]&quot;"><para>Templates from which to inherit.</para></enum>
469 </enumlist>
470 </enum>
471 </enumlist>
472 <para> </para>
473 <para>The following actions share the same options...</para>
474 <enumlist>
475 <enum name="RenameCat"/>
476 <enum name="DelCat"/>
477 <enum name="EmptyCat"/>
478 <enum name="Update"/>
479 <enum name="Delete"/>
480 <enum name="Append"/>
481 <enum name="Insert"><para> </para>
482 <enumlist>
483 <enum name="catfilter=&quot;&lt;expression&gt;[,...]&quot;"><para> </para>
484 <xi:include xpointer="xpointer(/docs/manager[@name='GetConfig']/syntax/parameter[@name='Filter']/para[1])" />
485 <para><literal>catfilter</literal> is most useful when a file
486 contains multiple categories with the same name and you wish to
487 operate on specific ones instead of all of them.</para>
488 </enum>
489 </enumlist>
490 </enum>
491 </enumlist>
492 <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-000000']/para[2])" />
493 </parameter>
494 </syntax>
495 <description>
496 <para>This action will modify, create, or delete configuration elements
497 in Asterisk configuration files.</para>
498 </description>
499 </manager>
500 <manager name="CreateConfig" language="en_US">
501 <synopsis>
502 Creates an empty file in the configuration directory.
503 </synopsis>
504 <syntax>
505 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
506 <parameter name="Filename" required="true">
507 <para>The configuration filename to create (e.g. <filename>foo.conf</filename>).</para>
508 </parameter>
509 </syntax>
510 <description>
511 <para>This action will create an empty file in the configuration
512 directory. This action is intended to be used before an UpdateConfig
513 action.</para>
514 </description>
515 </manager>
516 <manager name="ListCategories" language="en_US">
517 <synopsis>
518 List categories in configuration file.
519 </synopsis>
520 <syntax>
521 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
522 <parameter name="Filename" required="true">
523 <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
524 </parameter>
525 </syntax>
526 <description>
527 <para>This action will dump the categories in a given file.</para>
528 </description>
529 </manager>
530 <manager name="Redirect" language="en_US">
531 <synopsis>
532 Redirect (transfer) a call.
533 </synopsis>
534 <syntax>
535 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
536 <parameter name="Channel" required="true">
537 <para>Channel to redirect.</para>
538 </parameter>
539 <parameter name="ExtraChannel">
540 <para>Second call leg to transfer (optional).</para>
541 </parameter>
542 <parameter name="Exten" required="true">
543 <para>Extension to transfer to.</para>
544 </parameter>
545 <parameter name="ExtraExten">
546 <para>Extension to transfer extrachannel to (optional).</para>
547 </parameter>
548 <parameter name="Context" required="true">
549 <para>Context to transfer to.</para>
550 </parameter>
551 <parameter name="ExtraContext">
552 <para>Context to transfer extrachannel to (optional).</para>
553 </parameter>
554 <parameter name="Priority" required="true">
555 <para>Priority to transfer to.</para>
556 </parameter>
557 <parameter name="ExtraPriority">
558 <para>Priority to transfer extrachannel to (optional).</para>
559 </parameter>
560 </syntax>
561 <description>
562 <para>Redirect (transfer) a call.</para>
563 </description>
564 </manager>
565 <manager name="Atxfer" language="en_US">
566 <synopsis>
567 Attended transfer.
568 </synopsis>
569 <syntax>
570 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
571 <parameter name="Channel" required="true">
572 <para>Transferer's channel.</para>
573 </parameter>
574 <parameter name="Exten" required="true">
575 <para>Extension to transfer to.</para>
576 </parameter>
577 <parameter name="Context">
578 <para>Context to transfer to.</para>
579 </parameter>
580 </syntax>
581 <description>
582 <para>Attended transfer.</para>
583 </description>
584 </manager>
585 <manager name="Originate" language="en_US">
586 <synopsis>
587 Originate a call.
588 </synopsis>
589 <syntax>
590 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
591 <parameter name="Channel" required="true">
592 <para>Channel name to call.</para>
593 </parameter>
594 <parameter name="Exten">
595 <para>Extension to use (requires <literal>Context</literal> and
596 <literal>Priority</literal>)</para>
597 </parameter>
598 <parameter name="Context">
599 <para>Context to use (requires <literal>Exten</literal> and
600 <literal>Priority</literal>)</para>
601 </parameter>
602 <parameter name="Priority">
603 <para>Priority to use (requires <literal>Exten</literal> and
604 <literal>Context</literal>)</para>
605 </parameter>
606 <parameter name="Application">
607 <para>Application to execute.</para>
608 </parameter>
609 <parameter name="Data">
610 <para>Data to use (requires <literal>Application</literal>).</para>
611 </parameter>
612 <parameter name="Timeout" default="30000">
613 <para>How long to wait for call to be answered (in ms.).</para>
614 </parameter>
615 <parameter name="CallerID">
616 <para>Caller ID to be set on the outgoing channel.</para>
617 </parameter>
618 <parameter name="Variable">
619 <para>Channel variable to set, multiple Variable: headers are allowed.</para>
620 </parameter>
621 <parameter name="Account">
622 <para>Account code.</para>
623 </parameter>
624 <parameter name="EarlyMedia">
625 <para>Set to <literal>true</literal> to force call bridge on early media..</para>
626 </parameter>
627 <parameter name="Async">
628 <para>Set to <literal>true</literal> for fast origination.</para>
629 </parameter>
630 <parameter name="Codecs">
631 <para>Comma-separated list of codecs to use for this call.</para>
632 </parameter>
633 <parameter name="ChannelId">
634 <para>Channel UniqueId to be set on the channel.</para>
635 </parameter>
636 <parameter name="OtherChannelId">
637 <para>Channel UniqueId to be set on the second local channel.</para>
638 </parameter>
639 </syntax>
640 <description>
641 <para>Generates an outgoing call to a
642 <replaceable>Extension</replaceable>/<replaceable>Context</replaceable>/<replaceable>Priority</replaceable>
643 or <replaceable>Application</replaceable>/<replaceable>Data</replaceable></para>
644 </description>
645 <see-also>
646 <ref type="managerEvent">OriginateResponse</ref>
647 </see-also>
648 </manager>
649 <managerEvent language="en_US" name="OriginateResponse">
650 <managerEventInstance class="EVENT_FLAG_CALL">
651 <synopsis>Raised in response to an Originate command.</synopsis>
652 <syntax>
653 <parameter name="ActionID" required="false"/>
654 <parameter name="Response">
655 <enumlist>
656 <enum name="Failure"/>
657 <enum name="Success"/>
658 </enumlist>
659 </parameter>
660 <parameter name="Channel"/>
661 <parameter name="Context"/>
662 <parameter name="Exten"/>
663 <parameter name="Application"/>
664 <parameter name="Data"/>
665 <parameter name="Reason"/>
666 <parameter name="Uniqueid"/>
667 <parameter name="CallerIDNum"/>
668 <parameter name="CallerIDName"/>
669 </syntax>
670 <see-also>
671 <ref type="manager">Originate</ref>
672 </see-also>
673 </managerEventInstance>
674 </managerEvent>
675 <manager name="Command" language="en_US">
676 <synopsis>
677 Execute Asterisk CLI Command.
678 </synopsis>
679 <syntax>
680 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
681 <parameter name="Command" required="true">
682 <para>Asterisk CLI command to run.</para>
683 </parameter>
684 </syntax>
685 <description>
686 <para>Run a CLI command.</para>
687 </description>
688 </manager>
689 <manager name="ExtensionState" language="en_US">
690 <synopsis>
691 Check Extension Status.
692 </synopsis>
693 <syntax>
694 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
695 <parameter name="Exten" required="true">
696 <para>Extension to check state on.</para>
697 </parameter>
698 <parameter name="Context" required="true">
699 <para>Context for extension.</para>
700 </parameter>
701 </syntax>
702 <description>
703 <para>Report the extension state for given extension. If the extension has a hint,
704 will use devicestate to check the status of the device connected to the extension.</para>
705 <para>Will return an <literal>Extension Status</literal> message. The response will include
706 the hint for the extension and the status.</para>
707 </description>
708 </manager>
709 <manager name="PresenceState" language="en_US">
710 <synopsis>
711 Check Presence State
712 </synopsis>
713 <syntax>
714 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
715 <parameter name="Provider" required="true">
716 <para>Presence Provider to check the state of</para>
717 </parameter>
718 </syntax>
719 <description>
720 <para>Report the presence state for the given presence provider.</para>
721 <para>Will return a <literal>Presence State</literal> message. The response will include the
722 presence state and, if set, a presence subtype and custom message.</para>
723 </description>
724 </manager>
725 <manager name="AbsoluteTimeout" language="en_US">
726 <synopsis>
727 Set absolute timeout.
728 </synopsis>
729 <syntax>
730 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
731 <parameter name="Channel" required="true">
732 <para>Channel name to hangup.</para>
733 </parameter>
734 <parameter name="Timeout" required="true">
735 <para>Maximum duration of the call (sec).</para>
736 </parameter>
737 </syntax>
738 <description>
739 <para>Hangup a channel after a certain time. Acknowledges set time with
740 <literal>Timeout Set</literal> message.</para>
741 </description>
742 </manager>
743 <manager name="MailboxStatus" language="en_US">
744 <synopsis>
745 Check mailbox.
746 </synopsis>
747 <syntax>
748 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
749 <parameter name="Mailbox" required="true">
750 <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
751 </parameter>
752 </syntax>
753 <description>
754 <para>Checks a voicemail account for status.</para>
755 <para>Returns whether there are messages waiting.</para>
756 <para>Message: Mailbox Status.</para>
757 <para>Mailbox: <replaceable>mailboxid</replaceable>.</para>
758 <para>Waiting: <literal>0</literal> if messages waiting, <literal>1</literal>
759 if no messages waiting.</para>
760 </description>
761 </manager>
762 <manager name="MailboxCount" language="en_US">
763 <synopsis>
764 Check Mailbox Message Count.
765 </synopsis>
766 <syntax>
767 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
768 <parameter name="Mailbox" required="true">
769 <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
770 </parameter>
771 </syntax>
772 <description>
773 <para>Checks a voicemail account for new messages.</para>
774 <para>Returns number of urgent, new and old messages.</para>
775 <para>Message: Mailbox Message Count</para>
776 <para>Mailbox: <replaceable>mailboxid</replaceable></para>
777 <para>UrgentMessages: <replaceable>count</replaceable></para>
778 <para>NewMessages: <replaceable>count</replaceable></para>
779 <para>OldMessages: <replaceable>count</replaceable></para>
780 </description>
781 </manager>
782 <manager name="ListCommands" language="en_US">
783 <synopsis>
784 List available manager commands.
785 </synopsis>
786 <syntax>
787 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
788 </syntax>
789 <description>
790 <para>Returns the action name and synopsis for every action that
791 is available to the user.</para>
792 </description>
793 </manager>
794 <manager name="SendText" language="en_US">
795 <synopsis>
796 Send text message to channel.
797 </synopsis>
798 <syntax>
799 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
800 <parameter name="Channel" required="true">
801 <para>Channel to send message to.</para>
802 </parameter>
803 <parameter name="Message" required="true">
804 <para>Message to send.</para>
805 </parameter>
806 </syntax>
807 <description>
808 <para>Sends A Text Message to a channel while in a call.</para>
809 </description>
810 </manager>
811 <manager name="UserEvent" language="en_US">
812 <synopsis>
813 Send an arbitrary event.
814 </synopsis>
815 <syntax>
816 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
817 <parameter name="UserEvent" required="true">
818 <para>Event string to send.</para>
819 </parameter>
820 <parameter name="Header1">
821 <para>Content1.</para>
822 </parameter>
823 <parameter name="HeaderN">
824 <para>ContentN.</para>
825 </parameter>
826 </syntax>
827 <description>
828 <para>Send an event to manager sessions.</para>
829 </description>
830 </manager>
831 <manager name="WaitEvent" language="en_US">
832 <synopsis>
833 Wait for an event to occur.
834 </synopsis>
835 <syntax>
836 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
837 <parameter name="Timeout" required="true">
838 <para>Maximum time (in seconds) to wait for events, <literal>-1</literal> means forever.</para>
839 </parameter>
840 </syntax>
841 <description>
842 <para>This action will ellicit a <literal>Success</literal> response. Whenever
843 a manager event is queued. Once WaitEvent has been called on an HTTP manager
844 session, events will be generated and queued.</para>
845 </description>
846 </manager>
847 <manager name="CoreSettings" language="en_US">
848 <synopsis>
849 Show PBX core settings (version etc).
850 </synopsis>
851 <syntax>
852 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
853 </syntax>
854 <description>
855 <para>Query for Core PBX settings.</para>
856 </description>
857 </manager>
858 <manager name="CoreStatus" language="en_US">
859 <synopsis>
860 Show PBX core status variables.
861 </synopsis>
862 <syntax>
863 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
864 </syntax>
865 <description>
866 <para>Query for Core PBX status.</para>
867 </description>
868 </manager>
869 <manager name="Reload" language="en_US">
870 <synopsis>
871 Send a reload event.
872 </synopsis>
873 <syntax>
874 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
875 <parameter name="Module">
876 <para>Name of the module to reload.</para>
877 </parameter>
878 </syntax>
879 <description>
880 <para>Send a reload event.</para>
881 </description>
882 </manager>
883 <managerEvent language="en_US" name="CoreShowChannel">
884 <managerEventInstance class="EVENT_FLAG_CALL">
885 <synopsis>Raised in response to a CoreShowChannels command.</synopsis>
886 <syntax>
887 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
888 <channel_snapshot/>
889 <parameter name="BridgeId">
890 <para>Identifier of the bridge the channel is in, may be empty if not in one</para>
891 </parameter>
892 <parameter name="Application">
893 <para>Application currently executing on the channel</para>
894 </parameter>
895 <parameter name="ApplicationData">
896 <para>Data given to the currently executing application</para>
897 </parameter>
898 <parameter name="Duration">
899 <para>The amount of time the channel has existed</para>
900 </parameter>
901 </syntax>
902 <see-also>
903 <ref type="manager">CoreShowChannels</ref>
904 <ref type="managerEvent">CoreShowChannelsComplete</ref>
905 </see-also>
906 </managerEventInstance>
907 </managerEvent>
908 <managerEvent language="en_US" name="CoreShowChannelsComplete">
909 <managerEventInstance class="EVENT_FLAG_CALL">
910 <synopsis>Raised at the end of the CoreShowChannel list produced by the CoreShowChannels command.</synopsis>
911 <syntax>
912 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
913 <parameter name="EventList">
914 <para>Conveys the status of the command reponse list</para>
915 </parameter>
916 <parameter name="ListItems">
917 <para>The total number of list items produced</para>
918 </parameter>
919 </syntax>
920 <see-also>
921 <ref type="manager">CoreShowChannels</ref>
922 <ref type="managerEvent">CoreShowChannel</ref>
923 </see-also>
924 </managerEventInstance>
925 </managerEvent>
926 <manager name="CoreShowChannels" language="en_US">
927 <synopsis>
928 List currently active channels.
929 </synopsis>
930 <syntax>
931 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
932 </syntax>
933 <description>
934 <para>List currently defined channels and some information about them.</para>
935 </description>
936 <responses>
937 <list-elements>
938 <xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannel'])" />
939 </list-elements>
940 <xi:include xpointer="xpointer(/docs/managerEvent[@name='CoreShowChannelsComplete'])" />
941 </responses>
942 </manager>
943 <manager name="LoggerRotate" language="en_US">
944 <synopsis>
945 Reload and rotate the Asterisk logger.
946 </synopsis>
947 <syntax>
948 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
949 </syntax>
950 <description>
951 <para>Reload and rotate the logger. Analogous to the CLI command 'logger rotate'.</para>
952 </description>
953 </manager>
954 <manager name="ModuleLoad" language="en_US">
955 <synopsis>
956 Module management.
957 </synopsis>
958 <syntax>
959 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
960 <parameter name="Module">
961 <para>Asterisk module name (including .so extension) or subsystem identifier:</para>
962 <enumlist>
963 <enum name="cdr" />
964 <enum name="dnsmgr" />
965 <enum name="extconfig" />
966 <enum name="enum" />
967 <enum name="acl" />
968 <enum name="manager" />
969 <enum name="http" />
970 <enum name="logger" />
971 <enum name="features" />
972 <enum name="dsp" />
973 <enum name="udptl" />
974 <enum name="indications" />
975 <enum name="cel" />
976 <enum name="plc" />
977 </enumlist>
978 </parameter>
979 <parameter name="LoadType" required="true">
980 <para>The operation to be done on module. Subsystem identifiers may only
981 be reloaded.</para>
982 <enumlist>
983 <enum name="load" />
984 <enum name="unload" />
985 <enum name="reload" />
986 </enumlist>
987 <para>If no module is specified for a <literal>reload</literal> loadtype,
988 all modules are reloaded.</para>
989 </parameter>
990 </syntax>
991 <description>
992 <para>Loads, unloads or reloads an Asterisk module in a running system.</para>
993 </description>
994 </manager>
995 <manager name="ModuleCheck" language="en_US">
996 <synopsis>
997 Check if module is loaded.
998 </synopsis>
999 <syntax>
1000 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1001 <parameter name="Module" required="true">
1002 <para>Asterisk module name (not including extension).</para>
1003 </parameter>
1004 </syntax>
1005 <description>
1006 <para>Checks if Asterisk module is loaded. Will return Success/Failure.
1007 For success returns, the module revision number is included.</para>
1008 </description>
1009 </manager>
1010 <manager name="AOCMessage" language="en_US">
1011 <synopsis>
1012 Generate an Advice of Charge message on a channel.
1013 </synopsis>
1014 <syntax>
1015 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1016 <parameter name="Channel" required="true">
1017 <para>Channel name to generate the AOC message on.</para>
1018 </parameter>
1019 <parameter name="ChannelPrefix">
1020 <para>Partial channel prefix. By using this option one can match the beginning part
1021 of a channel name without having to put the entire name in. For example
1022 if a channel name is SIP/snom-00000001 and this value is set to SIP/snom, then
1023 that channel matches and the message will be sent. Note however that only
1024 the first matched channel has the message sent on it. </para>
1025 </parameter>
1026 <parameter name="MsgType" required="true">
1027 <para>Defines what type of AOC message to create, AOC-D or AOC-E</para>
1028 <enumlist>
1029 <enum name="D" />
1030 <enum name="E" />
1031 </enumlist>
1032 </parameter>
1033 <parameter name="ChargeType" required="true">
1034 <para>Defines what kind of charge this message represents.</para>
1035 <enumlist>
1036 <enum name="NA" />
1037 <enum name="FREE" />
1038 <enum name="Currency" />
1039 <enum name="Unit" />
1040 </enumlist>
1041 </parameter>
1042 <parameter name="UnitAmount(0)">
1043 <para>This represents the amount of units charged. The ETSI AOC standard specifies that
1044 this value along with the optional UnitType value are entries in a list. To accommodate this
1045 these values take an index value starting at 0 which can be used to generate this list of
1046 unit entries. For Example, If two unit entires were required this could be achieved by setting the
1047 paramter UnitAmount(0)=1234 and UnitAmount(1)=5678. Note that UnitAmount at index 0 is
1048 required when ChargeType=Unit, all other entries in the list are optional.
1049 </para>
1050 </parameter>
1051 <parameter name="UnitType(0)">
1052 <para>Defines the type of unit. ETSI AOC standard specifies this as an integer
1053 value between 1 and 16, but this value is left open to accept any positive
1054 integer. Like the UnitAmount parameter, this value represents a list entry
1055 and has an index parameter that starts at 0.
1056 </para>
1057 </parameter>
1058 <parameter name="CurrencyName">
1059 <para>Specifies the currency's name. Note that this value is truncated after 10 characters.</para>
1060 </parameter>
1061 <parameter name="CurrencyAmount">
1062 <para>Specifies the charge unit amount as a positive integer. This value is required
1063 when ChargeType==Currency.</para>
1064 </parameter>
1065 <parameter name="CurrencyMultiplier">
1066 <para>Specifies the currency multiplier. This value is required when ChargeType==Currency.</para>
1067 <enumlist>
1068 <enum name="OneThousandth" />
1069 <enum name="OneHundredth" />
1070 <enum name="OneTenth" />
1071 <enum name="One" />
1072 <enum name="Ten" />
1073 <enum name="Hundred" />
1074 <enum name="Thousand" />
1075 </enumlist>
1076 </parameter>
1077 <parameter name="TotalType" default="Total">
1078 <para>Defines what kind of AOC-D total is represented.</para>
1079 <enumlist>
1080 <enum name="Total" />
1081 <enum name="SubTotal" />
1082 </enumlist>
1083 </parameter>
1084 <parameter name="AOCBillingId">
1085 <para>Represents a billing ID associated with an AOC-D or AOC-E message. Note
1086 that only the first 3 items of the enum are valid AOC-D billing IDs</para>
1087 <enumlist>
1088 <enum name="Normal" />
1089 <enum name="ReverseCharge" />
1090 <enum name="CreditCard" />
1091 <enum name="CallFwdUnconditional" />
1092 <enum name="CallFwdBusy" />
1093 <enum name="CallFwdNoReply" />
1094 <enum name="CallDeflection" />
1095 <enum name="CallTransfer" />
1096 </enumlist>
1097 </parameter>
1098 <parameter name="ChargingAssociationId">
1099 <para>Charging association identifier. This is optional for AOC-E and can be
1100 set to any value between -32768 and 32767</para>
1101 </parameter>
1102 <parameter name="ChargingAssociationNumber">
1103 <para>Represents the charging association party number. This value is optional
1104 for AOC-E.</para>
1105 </parameter>
1106 <parameter name="ChargingAssociationPlan">
1107 <para>Integer representing the charging plan associated with the ChargingAssociationNumber.
1108 The value is bits 7 through 1 of the Q.931 octet containing the type-of-number and
1109 numbering-plan-identification fields.</para>
1110 </parameter>
1111 </syntax>
1112 <description>
1113 <para>Generates an AOC-D or AOC-E message on a channel.</para>
1114 </description>
1115 </manager>
1116 <function name="AMI_CLIENT" language="en_US">
1117 <synopsis>
1118 Checks attributes of manager accounts
1119 </synopsis>
1120 <syntax>
1121 <parameter name="loginname" required="true">
1122 <para>Login name, specified in manager.conf</para>
1123 </parameter>
1124 <parameter name="field" required="true">
1125 <para>The manager account attribute to return</para>
1126 <enumlist>
1127 <enum name="sessions"><para>The number of sessions for this AMI account</para></enum>
1128 </enumlist>
1129 </parameter>
1130 </syntax>
1131 <description>
1132 <para>
1133 Currently, the only supported parameter is "sessions" which will return the current number of
1134 active sessions for this AMI account.
1135 </para>
1136 </description>
1137 </function>
1138 <manager name="Filter" language="en_US">
1139 <synopsis>
1140 Dynamically add filters for the current manager session.
1141 </synopsis>
1142 <syntax>
1143 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1144 <parameter name="Operation">
1145 <enumlist>
1146 <enum name="Add">
1147 <para>Add a filter.</para>
1148 </enum>
1149 </enumlist>
1150 </parameter>
1151 <parameter name="Filter">
1152 <para>Filters can be whitelist or blacklist</para>
1153 <para>Example whitelist filter: "Event: Newchannel"</para>
1154 <para>Example blacklist filter: "!Channel: DAHDI.*"</para>
1155 <para>This filter option is used to whitelist or blacklist events per user to be
1156 reported with regular expressions and are allowed if both the regex matches
1157 and the user has read access as defined in manager.conf. Filters are assumed to be for whitelisting
1158 unless preceeded by an exclamation point, which marks it as being black.
1159 Evaluation of the filters is as follows:</para>
1160 <para>- If no filters are configured all events are reported as normal.</para>
1161 <para>- If there are white filters only: implied black all filter processed first, then white filters.</para>
1162 <para>- If there are black filters only: implied white all filter processed first, then black filters.</para>
1163 <para>- If there are both white and black filters: implied black all filter processed first, then white
1164 filters, and lastly black filters.</para>
1165 </parameter>
1166 </syntax>
1167 <description>
1168 <para>The filters added are only used for the current session.
1169 Once the connection is closed the filters are removed.</para>
1170 <para>This comand requires the system permission because
1171 this command can be used to create filters that may bypass
1172 filters defined in manager.conf</para>
1173 </description>
1174 </manager>
1175 <manager name="FilterList" language="en_US">
1176 <synopsis>
1177 Show current event filters for this session
1178 </synopsis>
1179 <description>
1180 <para>The filters displayed are for the current session. Only those filters defined in
1181 manager.conf will be present upon starting a new session.</para>
1182 </description>
1183 </manager>
1184 <manager name="BlindTransfer" language="en_US">
1185 <synopsis>
1186 Blind transfer channel(s) to the given destination
1187 </synopsis>
1188 <syntax>
1189 <parameter name="Channel" required="true">
1190 </parameter>
1191 <parameter name="Context">
1192 </parameter>
1193 <parameter name="Exten">
1194 </parameter>
1195 </syntax>
1196 <description>
1197 <para>Redirect all channels currently bridged to the specified channel to the specified destination.</para>
1198 </description>
1199 <see-also>
1200 <ref type="manager">Redirect</ref>
1201 </see-also>
1202 </manager>
1203 <managerEvent name="ExtensionStatus" language="en_US">
1204 <managerEventInstance class="EVENT_FLAG_CALL">
1205 <synopsis>Raised when a hint changes due to a device state change.</synopsis>
1206 <syntax>
1207 <parameter name="Exten">
1208 <para>Name of the extension.</para>
1209 </parameter>
1210 <parameter name="Context">
1211 <para>Context that owns the extension.</para>
1212 </parameter>
1213 <parameter name="Hint">
1214 <para>Hint set for the extension</para>
1215 </parameter>
1216 <parameter name="Status">
1217 <para>Numerical value of the extension status. Extension
1218 status is determined by the combined device state of all items
1219 contained in the hint.</para>
1220 <enumlist>
1221 <enum name="-2">
1222 <para>The extension was removed from the dialplan.</para>
1223 </enum>
1224 <enum name="-1">
1225 <para>The extension's hint was removed from the dialplan.</para>
1226 </enum>
1227 <enum name="0">
1228 <para><literal>Idle</literal> - Related device(s) are in an idle
1229 state.</para>
1230 </enum>
1231 <enum name="1">
1232 <para><literal>InUse</literal> - Related device(s) are in active
1233 calls but may take more calls.</para>
1234 </enum>
1235 <enum name="2">
1236 <para><literal>Busy</literal> - Related device(s) are in active
1237 calls and may not take any more calls.</para>
1238 </enum>
1239 <enum name="4">
1240 <para><literal>Unavailable</literal> - Related device(s) are
1241 not reachable.</para>
1242 </enum>
1243 <enum name="8">
1244 <para><literal>Ringing</literal> - Related device(s) are
1245 currently ringing.</para>
1246 </enum>
1247 <enum name="9">
1248 <para><literal>InUse&amp;Ringing</literal> - Related device(s)
1249 are currently ringing and in active calls.</para>
1250 </enum>
1251 <enum name="16">
1252 <para><literal>Hold</literal> - Related device(s) are
1253 currently on hold.</para>
1254 </enum>
1255 <enum name="17">
1256 <para><literal>InUse&amp;Hold</literal> - Related device(s)
1257 are currently on hold and in active calls.</para>
1258 </enum>
1259 </enumlist>
1260 </parameter>
1261 <parameter name="StatusText">
1262 <para>Text representation of <literal>Status</literal>.</para>
1263 <enumlist>
1264 <enum name="Idle" />
1265 <enum name="InUse" />
1266 <enum name="Busy" />
1267 <enum name="Unavailable" />
1268 <enum name="Ringing" />
1269 <enum name="InUse&amp;Ringing" />
1270 <enum name="Hold" />
1271 <enum name="InUse&amp;Hold" />
1272 <enum name="Unknown">
1273 <para>Status does not match any of the above values.</para>
1274 </enum>
1275 </enumlist>
1276 </parameter>
1277 </syntax>
1278 </managerEventInstance>
1279 </managerEvent>
1280 <managerEvent name="PresenceStatus" language="en_US">
1281 <managerEventInstance class="EVENT_FLAG_CALL">
1282 <synopsis>Raised when a hint changes due to a presence state change.</synopsis>
1283 <syntax>
1284 <parameter name="Exten" />
1285 <parameter name="Context" />
1286 <parameter name="Hint" />
1287 <parameter name="Status" />
1288 <parameter name="Subtype" />
1289 <parameter name="Message" />
1290 </syntax>
1291 </managerEventInstance>
1292 </managerEvent>
1293 ***/
1294
1295/*! \addtogroup Group_AMI AMI functions
1296*/
1297/*! @{
1298 Doxygen group */
1299
1300enum error_type {
1301 UNKNOWN_ACTION = 1,
1302 UNKNOWN_CATEGORY,
1303 UNSPECIFIED_CATEGORY,
1304 UNSPECIFIED_ARGUMENT,
1305 FAILURE_ALLOCATION,
1306 FAILURE_NEWCAT,
1307 FAILURE_DELCAT,
1308 FAILURE_EMPTYCAT,
1309 FAILURE_UPDATE,
1310 FAILURE_DELETE,
1311 FAILURE_APPEND,
1312 FAILURE_TEMPLATE
1313};
1314
1315enum add_filter_result {
1316 FILTER_SUCCESS,
1317 FILTER_ALLOC_FAILED,
1318 FILTER_COMPILE_FAIL,
1319};
1320
1321/*!
1322 * Linked list of events.
1323 * Global events are appended to the list by append_event().
1324 * The usecount is the number of stored pointers to the element,
1325 * excluding the list pointers. So an element that is only in
1326 * the list has a usecount of 0, not 1.
1327 *
1328 * Clients have a pointer to the last event processed, and for each
1329 * of these clients we track the usecount of the elements.
1330 * If we have a pointer to an entry in the list, it is safe to navigate
1331 * it forward because elements will not be deleted, but only appended.
1332 * The worst that can happen is seeing the pointer still NULL.
1333 *
1334 * When the usecount of an element drops to 0, and the element is the
1335 * first in the list, we can remove it. Removal is done within the
1336 * main thread, which is woken up for the purpose.
1337 *
1338 * For simplicity of implementation, we make sure the list is never empty.
1339 */
1340struct eventqent {
1341 int usecount; /*!< # of clients who still need the event */
1342 int category;
1343 unsigned int seq; /*!< sequence number */
1344 struct timeval tv; /*!< When event was allocated */
1345 AST_RWLIST_ENTRY(eventqent)struct { struct eventqent *next; } eq_next;
1346 char eventdata[1]; /*!< really variable size, allocated by append_event() */
1347};
1348
1349static AST_RWLIST_HEAD_STATIC(all_events, eventqent)struct all_events { struct eventqent *first; struct eventqent
*last; ast_rwlock_t lock; } all_events = { .first = ((void*)
0), .last = ((void*)0), .lock = { { { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 } }, ((void*)0), 1 }, }
;
1350
1351static int displayconnects = 1;
1352static int allowmultiplelogin = 1;
1353static int timestampevents;
1354static int httptimeout = 60;
1355static int broken_events_action = 0;
1356static int manager_enabled = 0;
1357static int subscribed = 0;
1358static int webmanager_enabled = 0;
1359static int manager_debug = 0; /*!< enable some debugging code in the manager */
1360static int authtimeout;
1361static int authlimit;
1362static char *manager_channelvars;
1363
1364#define DEFAULT_REALM"asterisk" "asterisk"
1365static char global_realm[MAXHOSTNAMELEN64]; /*!< Default realm */
1366
1367static int unauth_sessions = 0;
1368static struct stasis_subscription *acl_change_sub;
1369
1370/*! \brief A \ref stasis_topic that all topics AMI cares about will be forwarded to */
1371static struct stasis_topic *manager_topic;
1372
1373/*! \brief The \ref stasis_message_router for all \ref stasis messages */
1374static struct stasis_message_router *stasis_router;
1375
1376/*! \brief The \ref stasis_subscription for forwarding the RTP topic to the AMI topic */
1377static struct stasis_forward *rtp_topic_forwarder;
1378
1379/*! \brief The \ref stasis_subscription for forwarding the Security topic to the AMI topic */
1380static struct stasis_forward *security_topic_forwarder;
1381
1382#ifdef TEST_FRAMEWORK
1383/*! \brief The \ref stasis_subscription for forwarding the Test topic to the AMI topic */
1384static struct stasis_forward *test_suite_forwarder;
1385#endif
1386
1387#define MGR_SHOW_TERMINAL_WIDTH80 80
1388
1389#define MAX_VARS128 128
1390
1391/*! \brief Fake event class used to end sessions at shutdown */
1392#define EVENT_FLAG_SHUTDOWN-1 -1
1393
1394/*! \brief
1395 * Descriptor for a manager session, either on the AMI socket or over HTTP.
1396 *
1397 * \note
1398 * AMI session have managerid == 0; the entry is created upon a connect,
1399 * and destroyed with the socket.
1400 * HTTP sessions have managerid != 0, the value is used as a search key
1401 * to lookup sessions (using the mansession_id cookie, or nonce key from
1402 * Digest Authentication http header).
1403 */
1404#define MAX_BLACKLIST_CMD_LEN2 2
1405static const struct {
1406 const char *words[AST_MAX_CMD_LEN16];
1407} command_blacklist[] = {
1408 {{ "module", "load", NULL((void*)0) }},
1409 {{ "module", "unload", NULL((void*)0) }},
1410 {{ "restart", "gracefully", NULL((void*)0) }},
1411};
1412
1413static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
1414
1415static void acl_change_stasis_subscribe(void)
1416{
1417 if (!acl_change_sub) {
1418 acl_change_sub = stasis_subscribe(ast_security_topic(),
1419 acl_change_stasis_cb, NULL((void*)0));
1420 }
1421}
1422
1423static void acl_change_stasis_unsubscribe(void)
1424{
1425 acl_change_sub = stasis_unsubscribe_and_join(acl_change_sub);
1426}
1427
1428/* In order to understand what the heck is going on with the
1429 * mansession_session and mansession structs, we need to have a bit of a history
1430 * lesson.
1431 *
1432 * In the beginning, there was the mansession. The mansession contained data that was
1433 * intrinsic to a manager session, such as the time that it started, the name of the logged-in
1434 * user, etc. In addition to these parameters were the f and fd parameters. For typical manager
1435 * sessions, these were used to represent the TCP socket over which the AMI session was taking
1436 * place. It makes perfect sense for these fields to be a part of the session-specific data since
1437 * the session actually defines this information.
1438 *
1439 * Then came the HTTP AMI sessions. With these, the f and fd fields need to be opened and closed
1440 * for every single action that occurs. Thus the f and fd fields aren't really specific to the session
1441 * but rather to the action that is being executed. Because a single session may execute many commands
1442 * at once, some sort of safety needed to be added in order to be sure that we did not end up with fd
1443 * leaks from one action overwriting the f and fd fields used by a previous action before the previous action
1444 * has had a chance to properly close its handles.
1445 *
1446 * The initial idea to solve this was to use thread synchronization, but this prevented multiple actions
1447 * from being run at the same time in a single session. Some manager actions may block for a long time, thus
1448 * creating a large queue of actions to execute. In addition, this fix did not address the basic architectural
1449 * issue that for HTTP manager sessions, the f and fd variables are not really a part of the session, but are
1450 * part of the action instead.
1451 *
1452 * The new idea was to create a structure on the stack for each HTTP Manager action. This structure would
1453 * contain the action-specific information, such as which file to write to. In order to maintain expectations
1454 * of action handlers and not have to change the public API of the manager code, we would need to name this
1455 * new stacked structure 'mansession' and contain within it the old mansession struct that we used to use.
1456 * We renamed the old mansession struct 'mansession_session' to hopefully convey that what is in this structure
1457 * is session-specific data. The structure that it is wrapped in, called a 'mansession' really contains action-specific
1458 * data.
1459 */
1460struct mansession_session {
1461 /*! \todo XXX need to document which fields it is protecting */
1462 struct ast_sockaddr addr; /*!< address we are connecting from */
1463 FILE *f; /*!< fdopen() on the underlying fd */
1464 int fd; /*!< descriptor used for output. Either the socket (AMI) or a temporary file (HTTP) */
1465 int inuse; /*!< number of HTTP sessions using this entry */
1466 int needdestroy; /*!< Whether an HTTP session should be destroyed */
1467 pthread_t waiting_thread; /*!< Sleeping thread using this descriptor */
1468 uint32_t managerid; /*!< Unique manager identifier, 0 for AMI sessions */
1469 time_t sessionstart; /*!< Session start time */
1470 struct timeval sessionstart_tv; /*!< Session start time */
1471 time_t sessiontimeout; /*!< Session timeout if HTTP */
1472 char username[80]; /*!< Logged in username */
1473 char challenge[10]; /*!< Authentication challenge */
1474 int authenticated; /*!< Authentication status */
1475 int readperm; /*!< Authorization for reading */
1476 int writeperm; /*!< Authorization for writing */
1477 char inbuf[1025]; /*!< Buffer - we use the extra byte to add a '\\0' and simplify parsing */
1478 int inlen; /*!< number of buffered bytes */
1479 struct ao2_container *whitefilters; /*!< Manager event filters - white list */
1480 struct ao2_container *blackfilters; /*!< Manager event filters - black list */
1481 struct ast_variable *chanvars; /*!< Channel variables to set for originate */
1482 int send_events; /*!< XXX what ? */
1483 struct eventqent *last_ev; /*!< last event processed. */
1484 int writetimeout; /*!< Timeout for ast_carefulwrite() */
1485 time_t authstart;
1486 int pending_event; /*!< Pending events indicator in case when waiting_thread is NULL */
1487 time_t noncetime; /*!< Timer for nonce value expiration */
1488 unsigned long oldnonce; /*!< Stale nonce value */
1489 unsigned long nc; /*!< incremental nonce counter */
1490 AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore)struct mansession_datastores { struct ast_datastore *first; struct
ast_datastore *last; }
datastores; /*!< Data stores on the session */
1491 AST_LIST_ENTRY(mansession_session)struct { struct mansession_session *next; } list;
1492};
1493
1494enum mansession_message_parsing {
1495 MESSAGE_OKAY,
1496 MESSAGE_LINE_TOO_LONG
1497};
1498
1499/*! \brief In case you didn't read that giant block of text above the mansession_session struct, the
1500 * \ref struct mansession is named this solely to keep the API the same in Asterisk. This structure really
1501 * represents data that is different from Manager action to Manager action. The mansession_session pointer
1502 * contained within points to session-specific data.
1503 */
1504struct mansession {
1505 struct mansession_session *session;
1506 struct ast_tcptls_session_instance *tcptls_session;
1507 FILE *f;
1508 int fd;
1509 enum mansession_message_parsing parsing;
1510 int write_error:1;
1511 struct manager_custom_hook *hook;
1512 ast_mutex_t lock;
1513};
1514
1515/*! Active manager connection sessions container. */
1516static AO2_GLOBAL_OBJ_STATIC(mgr_sessions)struct ao2_global_obj mgr_sessions = { .lock = { { { 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 } }, ((void*)0), 1 }, }
;
1517
1518/*! \brief user descriptor, as read from the config file.
1519 *
1520 * \note It is still missing some fields -- e.g. we can have multiple permit and deny
1521 * lines which are not supported here, and readperm/writeperm/writetimeout
1522 * are not stored.
1523 */
1524struct ast_manager_user {
1525 char username[80];
1526 char *secret; /*!< Secret for logging in */
1527 int readperm; /*!< Authorization for reading */
1528 int writeperm; /*!< Authorization for writing */
1529 int writetimeout; /*!< Per user Timeout for ast_carefulwrite() */
1530 int displayconnects; /*!< XXX unused */
1531 int allowmultiplelogin; /*!< Per user option*/
1532 int keep; /*!< mark entries created on a reload */
1533 struct ao2_container *whitefilters; /*!< Manager event filters - white list */
1534 struct ao2_container *blackfilters; /*!< Manager event filters - black list */
1535 struct ast_acl_list *acl; /*!< ACL setting */
1536 char *a1_hash; /*!< precalculated A1 for Digest auth */
1537 struct ast_variable *chanvars; /*!< Channel variables to set for originate */
1538 AST_RWLIST_ENTRY(ast_manager_user)struct { struct ast_manager_user *next; } list;
1539};
1540
1541/*! \brief list of users found in the config file */
1542static AST_RWLIST_HEAD_STATIC(users, ast_manager_user)struct users { struct ast_manager_user *first; struct ast_manager_user
*last; ast_rwlock_t lock; } users = { .first = ((void*)0), .
last = ((void*)0), .lock = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0 } }, ((void*)0), 1 }, }
;
1543
1544/*! \brief list of actions registered */
1545static AST_RWLIST_HEAD_STATIC(actions, manager_action)struct actions { struct manager_action *first; struct manager_action
*last; ast_rwlock_t lock; } actions = { .first = ((void*)0),
.last = ((void*)0), .lock = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0 } }, ((void*)0), 1 }, }
;
1546
1547/*! \brief list of hooks registered */
1548static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook)struct manager_hooks { struct manager_custom_hook *first; struct
manager_custom_hook *last; ast_rwlock_t lock; } manager_hooks
= { .first = ((void*)0), .last = ((void*)0), .lock = { { { 0
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, ((void*)0), 1 }, }
;
1549
1550/*! \brief A container of event documentation nodes */
1551static AO2_GLOBAL_OBJ_STATIC(event_docs)struct ao2_global_obj event_docs = { .lock = { { { 0, 0, 0, 0
, 0, 0, 0, 0, 0, 0, 0 } }, ((void*)0), 1 }, }
;
1552
1553static int __attribute__((format(printf, 9, 0))) __manager_event_sessions(
1554 struct ao2_container *sessions,
1555 int category,
1556 const char *event,
1557 int chancount,
1558 struct ast_channel **chans,
1559 const char *file,
1560 int line,
1561 const char *func,
1562 const char *fmt,
1563 ...);
1564static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters);
1565
1566static int match_filter(struct mansession *s, char *eventdata);
1567
1568/*!
1569 * @{ \brief Define AMI message types.
1570 */
1571STASIS_MESSAGE_TYPE_DEFN(ast_manager_get_generic_type)static struct stasis_message_vtable _priv_ast_manager_get_generic_type_v
= { }; static struct stasis_message_type *_priv_ast_manager_get_generic_type
; struct stasis_message_type *ast_manager_get_generic_type(void
) { if (_priv_ast_manager_get_generic_type == ((void*)0)) { stasis_log_bad_type_access
("ast_manager_get_generic_type"); } return _priv_ast_manager_get_generic_type
; }
;
1572/*! @} */
1573
1574/*!
1575 * \internal
1576 * \brief Find a registered action object.
1577 *
1578 * \param name Name of AMI action to find.
1579 *
1580 * \return Reffed action found or NULL
1581 */
1582static struct manager_action *action_find(const char *name)
1583{
1584 struct manager_action *act;
1585
1586 AST_RWLIST_RDLOCK(&actions)__ast_rwlock_rdlock("manager.c", 1586, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
1587 AST_RWLIST_TRAVERSE(&actions, act, list)for((act) = (&actions)->first; (act); (act) = (act)->
list.next)
{
1588 if (!strcasecmp(name, act->action)) {
1589 ao2_t_ref(act, +1, "found action object")__ao2_ref((act), (+1), ("found action object"), "manager.c", 1589
, __PRETTY_FUNCTION__)
;
1590 break;
1591 }
1592 }
1593 AST_RWLIST_UNLOCK(&actions)__ast_rwlock_unlock("manager.c", 1593, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
1594
1595 return act;
1596}
1597
1598struct stasis_topic *ast_manager_get_topic(void)
1599{
1600 return manager_topic;
1601}
1602
1603struct stasis_message_router *ast_manager_get_message_router(void)
1604{
1605 return stasis_router;
1606}
1607
1608static void manager_json_value_str_append(struct ast_json *value, const char *key,
1609 struct ast_str **res)
1610{
1611 switch (ast_json_typeof(value)) {
1612 case AST_JSON_STRING:
1613 ast_str_append(res, 0, "%s: %s\r\n", key, ast_json_string_get(value));
1614 break;
1615 case AST_JSON_INTEGER:
1616 ast_str_append(res, 0, "%s: %jd\r\n", key, ast_json_integer_get(value));
1617 break;
1618 case AST_JSON_TRUE:
1619 ast_str_append(res, 0, "%s: True\r\n", key);
1620 break;
1621 case AST_JSON_FALSE:
1622 ast_str_append(res, 0, "%s: False\r\n", key);
1623 break;
1624 default:
1625 ast_str_append(res, 0, "%s: \r\n", key);
1626 break;
1627 }
1628}
1629
1630static void manager_json_to_ast_str(struct ast_json *obj, const char *key,
1631 struct ast_str **res, key_exclusion_cb exclusion_cb);
1632
1633static void manager_json_array_with_key(struct ast_json *obj, const char* key,
1634 size_t index, struct ast_str **res,
1635 key_exclusion_cb exclusion_cb)
1636{
1637 struct ast_str *key_str = ast_str_alloca(64)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 64); __ast_str_buf->len = 64; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
1638 ast_str_set(&key_str, 0, "%s(%zu)", key, index);
1639 manager_json_to_ast_str(obj, ast_str_buffer(key_str),
1640 res, exclusion_cb);
1641}
1642
1643static void manager_json_obj_with_key(struct ast_json *obj, const char* key,
1644 const char *parent_key, struct ast_str **res,
1645 key_exclusion_cb exclusion_cb)
1646{
1647 if (parent_key) {
1648 struct ast_str *key_str = ast_str_alloca(64)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 64); __ast_str_buf->len = 64; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
1649 ast_str_set(&key_str, 0, "%s/%s", parent_key, key);
1650 manager_json_to_ast_str(obj, ast_str_buffer(key_str),
1651 res, exclusion_cb);
1652 return;
1653 }
1654
1655 manager_json_to_ast_str(obj, key, res, exclusion_cb);
1656}
1657
1658void manager_json_to_ast_str(struct ast_json *obj, const char *key,
1659 struct ast_str **res, key_exclusion_cb exclusion_cb)
1660{
1661 struct ast_json_iter *i;
1662
1663 if (!obj || (!res && !(*res) && (!(*res = ast_str_create(1024))))) {
1664 return;
1665 }
1666
1667 if (exclusion_cb && key && exclusion_cb(key)) {
1668 return;
1669 }
1670
1671 if (ast_json_typeof(obj) != AST_JSON_OBJECT &&
1672 ast_json_typeof(obj) != AST_JSON_ARRAY) {
1673 manager_json_value_str_append(obj, key, res);
1674 return;
1675 }
1676
1677 if (ast_json_typeof(obj) == AST_JSON_ARRAY) {
1678 size_t j;
1679 for (j = 0; j < ast_json_array_size(obj); ++j) {
1680 manager_json_array_with_key(ast_json_array_get(obj, j),
1681 key, j, res, exclusion_cb);
1682 }
1683 return;
1684 }
1685
1686 for (i = ast_json_object_iter(obj); i;
1687 i = ast_json_object_iter_next(obj, i)) {
1688 manager_json_obj_with_key(ast_json_object_iter_value(i),
1689 ast_json_object_iter_key(i),
1690 key, res, exclusion_cb);
1691 }
1692}
1693
1694
1695struct ast_str *ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
1696{
1697 struct ast_str *res = ast_str_create(1024);
1698 manager_json_to_ast_str(blob, NULL((void*)0), &res, exclusion_cb);
1699 return res;
1700}
1701
1702#define manager_event_sessions(sessions, category, event, contents , ...)__manager_event_sessions(sessions, category, event, 0, ((void
*)0), "manager.c", 1702, __PRETTY_FUNCTION__, contents , ...)
\
1703 __manager_event_sessions(sessions, category, event, 0, NULL((void*)0), __FILE__"manager.c", __LINE__1703, __PRETTY_FUNCTION__, contents , ## __VA_ARGS__)
1704
1705#define any_manager_listeners(sessions)((sessions && ao2_container_count(sessions)) || !(((&
manager_hooks)->first) == ((void*)0)))
\
1706 ((sessions && ao2_container_count(sessions)) || !AST_RWLIST_EMPTY(&manager_hooks)(((&manager_hooks)->first) == ((void*)0)))
1707
1708static void manager_default_msg_cb(void *data, struct stasis_subscription *sub,
1709 struct stasis_message *message)
1710{
1711 struct ao2_container *sessions;
1712 struct ast_manager_event_blob *ev;
1713
1714 if (!stasis_message_can_be_ami(message)) {
1715 /* Not an AMI message; disregard */
1716 return;
1717 }
1718
1719 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 1719
, __PRETTY_FUNCTION__, "mgr_sessions")
;
1720 if (!any_manager_listeners(sessions)((sessions && ao2_container_count(sessions)) || !(((&
manager_hooks)->first) == ((void*)0)))
) {
1721 /* Nobody is listening */
1722 ao2_cleanup(sessions)__ao2_cleanup_debug((sessions), "", "manager.c", 1722, __PRETTY_FUNCTION__
)
;
1723 return;
1724 }
1725
1726 ev = stasis_message_to_ami(message);
1727 if (!ev) {
1728 /* Conversion failure */
1729 ao2_cleanup(sessions)__ao2_cleanup_debug((sessions), "", "manager.c", 1729, __PRETTY_FUNCTION__
)
;
1730 return;
1731 }
1732
1733 manager_event_sessions(sessions, ev->event_flags, ev->manager_event,__manager_event_sessions(sessions, ev->event_flags, ev->
manager_event, 0, ((void*)0), "manager.c", 1734, __PRETTY_FUNCTION__
, "%s" , ev->extra_fields)
1734 "%s", ev->extra_fields)__manager_event_sessions(sessions, ev->event_flags, ev->
manager_event, 0, ((void*)0), "manager.c", 1734, __PRETTY_FUNCTION__
, "%s" , ev->extra_fields)
;
1735 ao2_ref(ev, -1)__ao2_ref((ev), (-1), "", "manager.c", 1735, __PRETTY_FUNCTION__
)
;
1736 ao2_cleanup(sessions)__ao2_cleanup_debug((sessions), "", "manager.c", 1736, __PRETTY_FUNCTION__
)
;
1737}
1738
1739static void manager_generic_msg_cb(void *data, struct stasis_subscription *sub,
1740 struct stasis_message *message)
1741{
1742 struct ast_json_payload *payload;
1743 int class_type;
1744 const char *type;
1745 struct ast_json *event;
1746 struct ast_str *event_buffer;
1747 struct ao2_container *sessions;
1748
1749 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 1749
, __PRETTY_FUNCTION__, "mgr_sessions")
;
1750 if (!any_manager_listeners(sessions)((sessions && ao2_container_count(sessions)) || !(((&
manager_hooks)->first) == ((void*)0)))
) {
1751 /* Nobody is listening */
1752 ao2_cleanup(sessions)__ao2_cleanup_debug((sessions), "", "manager.c", 1752, __PRETTY_FUNCTION__
)
;
1753 return;
1754 }
1755
1756 payload = stasis_message_data(message);
1757 class_type = ast_json_integer_get(ast_json_object_get(payload->json, "class_type"));
1758 type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
1759 event = ast_json_object_get(payload->json, "event");
1760
1761 event_buffer = ast_manager_str_from_json_object(event, NULL((void*)0));
1762 if (!event_buffer) {
1763 ast_log(AST_LOG_WARNING3, "manager.c", 1763, __PRETTY_FUNCTION__, "Error while creating payload for event %s\n", type);
1764 ao2_cleanup(sessions)__ao2_cleanup_debug((sessions), "", "manager.c", 1764, __PRETTY_FUNCTION__
)
;
1765 return;
1766 }
1767 manager_event_sessions(sessions, class_type, type,__manager_event_sessions(sessions, class_type, type, 0, ((void
*)0), "manager.c", 1768, __PRETTY_FUNCTION__, "%s" , ast_str_buffer
(event_buffer))
1768 "%s", ast_str_buffer(event_buffer))__manager_event_sessions(sessions, class_type, type, 0, ((void
*)0), "manager.c", 1768, __PRETTY_FUNCTION__, "%s" , ast_str_buffer
(event_buffer))
;
1769 ast_freefree(event_buffer);
1770 ao2_cleanup(sessions)__ao2_cleanup_debug((sessions), "", "manager.c", 1770, __PRETTY_FUNCTION__
)
;
1771}
1772
1773void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
1774{
1775 RAII_VAR(struct ast_json *, event_info, NULL, ast_json_unref)_raii_cleanup_block_t _raii_cleanup_event_info __attribute__(
(cleanup(_raii_cleanup_block),unused)) = ((void*)0); __attribute__
((__blocks__(byref))) struct ast_json * event_info = ((void*)
0); _raii_cleanup_event_info = ^{ {(void)ast_json_unref(event_info
);} }
;
1776 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup)_raii_cleanup_block_t _raii_cleanup_payload __attribute__((cleanup
(_raii_cleanup_block),unused)) = ((void*)0); __attribute__((__blocks__
(byref))) struct ast_json_payload * payload = ((void*)0); _raii_cleanup_payload
= ^{ {(void)__ao2_cleanup_debug((payload), "", "manager.c", 1776
, __PRETTY_FUNCTION__);} }
;
1777 RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup)_raii_cleanup_block_t _raii_cleanup_message __attribute__((cleanup
(_raii_cleanup_block),unused)) = ((void*)0); __attribute__((__blocks__
(byref))) struct stasis_message * message = ((void*)0); _raii_cleanup_message
= ^{ {(void)__ao2_cleanup_debug((message), "", "manager.c", 1777
, __PRETTY_FUNCTION__);} }
;
1778
1779 if (!obj || !ast_manager_get_generic_type()) {
1780 return;
1781 }
1782
1783 ast_json_ref(obj);
1784 event_info = ast_json_pack("{s: s, s: i, s: o}",
1785 "type", type,
1786 "class_type", class_type,
1787 "event", obj);
1788 if (!event_info) {
1789 return;
1790 }
1791
1792 payload = ast_json_payload_create(event_info);
1793 if (!payload) {
1794 return;
1795 }
1796 message = stasis_message_create(ast_manager_get_generic_type(), payload);
1797 if (!message) {
1798 return;
1799 }
1800 stasis_publish(ast_manager_get_topic(), message);
1801}
1802
1803/*! \brief Add a custom hook to be called when an event is fired */
1804void ast_manager_register_hook(struct manager_custom_hook *hook)
1805{
1806 AST_RWLIST_WRLOCK(&manager_hooks)__ast_rwlock_wrlock("manager.c", 1806, __PRETTY_FUNCTION__, &
(&manager_hooks)->lock, "&(&manager_hooks)->lock"
)
;
1807 AST_RWLIST_INSERT_TAIL(&manager_hooks, hook, list)do { if (!(&manager_hooks)->first) { (&manager_hooks
)->first = (hook); (&manager_hooks)->last = (hook);
} else { (&manager_hooks)->last->list.next = (hook
); (&manager_hooks)->last = (hook); } } while (0)
;
1808 AST_RWLIST_UNLOCK(&manager_hooks)__ast_rwlock_unlock("manager.c", 1808, __PRETTY_FUNCTION__, &
(&manager_hooks)->lock, "&(&manager_hooks)->lock"
)
;
1809}
1810
1811/*! \brief Delete a custom hook to be called when an event is fired */
1812void ast_manager_unregister_hook(struct manager_custom_hook *hook)
1813{
1814 AST_RWLIST_WRLOCK(&manager_hooks)__ast_rwlock_wrlock("manager.c", 1814, __PRETTY_FUNCTION__, &
(&manager_hooks)->lock, "&(&manager_hooks)->lock"
)
;
1815 AST_RWLIST_REMOVE(&manager_hooks, hook, list)({ __typeof(hook) __elm = (hook); if (__elm) { if ((&manager_hooks
)->first == __elm) { (&manager_hooks)->first = __elm
->list.next; __elm->list.next = ((void*)0); if ((&manager_hooks
)->last == __elm) { (&manager_hooks)->last = ((void
*)0); } } else { typeof(hook) __prev = (&manager_hooks)->
first; while (__prev && __prev->list.next != __elm
) { __prev = __prev->list.next; } if (__prev) { __prev->
list.next = __elm->list.next; __elm->list.next = ((void
*)0); if ((&manager_hooks)->last == __elm) { (&manager_hooks
)->last = __prev; } } else { __elm = ((void*)0); } } } __elm
; })
;
1816 AST_RWLIST_UNLOCK(&manager_hooks)__ast_rwlock_unlock("manager.c", 1816, __PRETTY_FUNCTION__, &
(&manager_hooks)->lock, "&(&manager_hooks)->lock"
)
;
1817}
1818
1819int check_manager_enabled(void)
1820{
1821 return manager_enabled;
1822}
1823
1824int check_webmanager_enabled(void)
1825{
1826 return (webmanager_enabled && manager_enabled);
1827}
1828
1829/*!
1830 * Grab a reference to the last event, update usecount as needed.
1831 * Can handle a NULL pointer.
1832 */
1833static struct eventqent *grab_last(void)
1834{
1835 struct eventqent *ret;
1836
1837 AST_RWLIST_WRLOCK(&all_events)__ast_rwlock_wrlock("manager.c", 1837, __PRETTY_FUNCTION__, &
(&all_events)->lock, "&(&all_events)->lock"
)
;
1838 ret = AST_RWLIST_LAST(&all_events)((&all_events)->last);
1839 /* the list is never empty now, but may become so when
1840 * we optimize it in the future, so be prepared.
1841 */
1842 if (ret) {
1843 ast_atomic_fetchadd_int(&ret->usecount, 1);
1844 }
1845 AST_RWLIST_UNLOCK(&all_events)__ast_rwlock_unlock("manager.c", 1845, __PRETTY_FUNCTION__, &
(&all_events)->lock, "&(&all_events)->lock"
)
;
1846 return ret;
1847}
1848
1849/*!
1850 * Purge unused events. Remove elements from the head
1851 * as long as their usecount is 0 and there is a next element.
1852 */
1853static void purge_events(void)
1854{
1855 struct eventqent *ev;
1856 struct timeval now = ast_tvnow();
1857
1858 AST_RWLIST_WRLOCK(&all_events)__ast_rwlock_wrlock("manager.c", 1858, __PRETTY_FUNCTION__, &
(&all_events)->lock, "&(&all_events)->lock"
)
;
1859 while ( (ev = AST_RWLIST_FIRST(&all_events)((&all_events)->first)) &&
1860 ev->usecount == 0 && AST_RWLIST_NEXT(ev, eq_next)((ev)->eq_next.next)) {
1861 AST_RWLIST_REMOVE_HEAD(&all_events, eq_next)({ typeof((&all_events)->first) __cur = (&all_events
)->first; if (__cur) { (&all_events)->first = __cur
->eq_next.next; __cur->eq_next.next = ((void*)0); if ((
&all_events)->last == __cur) (&all_events)->last
= ((void*)0); } __cur; })
;
1862 ast_freefree(ev);
1863 }
1864
1865 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&all_events, ev, eq_next){ typeof((&all_events)) __list_head = &all_events; typeof
(__list_head->first) __list_next; typeof(__list_head->first
) __list_prev = ((void*)0); typeof(__list_head->first) __list_current
; for ((ev) = __list_head->first, __list_current = (ev), __list_next
= (ev) ? (ev)->eq_next.next : ((void*)0); (ev); __list_prev
= __list_current, (ev) = __list_next, __list_current = (ev),
__list_next = (ev) ? (ev)->eq_next.next : ((void*)0), (void
) __list_prev )
{
1866 /* Never release the last event */
1867 if (!AST_RWLIST_NEXT(ev, eq_next)((ev)->eq_next.next)) {
1868 break;
1869 }
1870
1871 /* 2.5 times whatever the HTTP timeout is (maximum 2.5 hours) is the maximum time that we will definitely cache an event */
1872 if (ev->usecount == 0 && ast_tvdiff_sec(now, ev->tv) > (httptimeout > 3600 ? 3600 : httptimeout) * 2.5) {
1873 AST_RWLIST_REMOVE_CURRENT(eq_next)do { __list_current->eq_next.next = ((void*)0); __list_current
= __list_prev; if (__list_prev) { __list_prev->eq_next.next
= __list_next; } else { __list_head->first = __list_next;
} if (!__list_next) { __list_head->last = __list_prev; } }
while (0)
;
1874 ast_freefree(ev);
1875 }
1876 }
1877 AST_RWLIST_TRAVERSE_SAFE_END};
1878 AST_RWLIST_UNLOCK(&all_events)__ast_rwlock_unlock("manager.c", 1878, __PRETTY_FUNCTION__, &
(&all_events)->lock, "&(&all_events)->lock"
)
;
1879}
1880
1881/*!
1882 * helper functions to convert back and forth between
1883 * string and numeric representation of set of flags
1884 */
1885static const struct permalias {
1886 int num;
1887 const char *label;
1888} perms[] = {
1889 { EVENT_FLAG_SYSTEM(1 << 0), "system" },
1890 { EVENT_FLAG_CALL(1 << 1), "call" },
1891 { EVENT_FLAG_LOG(1 << 2), "log" },
1892 { EVENT_FLAG_VERBOSE(1 << 3), "verbose" },
1893 { EVENT_FLAG_COMMAND(1 << 4), "command" },
1894 { EVENT_FLAG_AGENT(1 << 5), "agent" },
1895 { EVENT_FLAG_USER(1 << 6), "user" },
1896 { EVENT_FLAG_CONFIG(1 << 7), "config" },
1897 { EVENT_FLAG_DTMF(1 << 8), "dtmf" },
1898 { EVENT_FLAG_REPORTING(1 << 9), "reporting" },
1899 { EVENT_FLAG_CDR(1 << 10), "cdr" },
1900 { EVENT_FLAG_DIALPLAN(1 << 11), "dialplan" },
1901 { EVENT_FLAG_ORIGINATE(1 << 12), "originate" },
1902 { EVENT_FLAG_AGI(1 << 13), "agi" },
1903 { EVENT_FLAG_CC(1 << 15), "cc" },
1904 { EVENT_FLAG_AOC(1 << 16), "aoc" },
1905 { EVENT_FLAG_TEST(1 << 17), "test" },
1906 { EVENT_FLAG_SECURITY(1 << 18), "security" },
1907 { EVENT_FLAG_MESSAGE(1 << 30), "message" },
1908 { INT_MAX2147483647, "all" },
1909 { 0, "none" },
1910};
1911
1912/*! Maximum string length of the AMI authority permission string buildable from perms[]. */
1913#define MAX_AUTH_PERM_STRING150 150
1914
1915/*! \brief Checks to see if a string which can be used to evaluate functions should be rejected */
1916static int function_capable_string_allowed_with_auths(const char *evaluating, int writepermlist)
1917{
1918 if (!(writepermlist & EVENT_FLAG_SYSTEM(1 << 0))
1919 && (
1920 strstr(evaluating, "SHELL") || /* NoOp(${SHELL(rm -rf /)}) */
1921 strstr(evaluating, "EVAL") /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
1922 )) {
1923 return 0;
1924 }
1925 return 1;
1926}
1927
1928/*! \brief Convert authority code to a list of options for a user. This will only
1929 * display those authority codes that have an explicit match on authority */
1930static const char *user_authority_to_str(int authority, struct ast_str **res)
1931{
1932 int i;
1933 char *sep = "";
1934
1935 ast_str_reset(*res);
1936 for (i = 0; i < ARRAY_LEN(perms)(size_t) (sizeof(perms) / sizeof(0[perms])) - 1; i++) {
1937 if ((authority & perms[i].num) == perms[i].num) {
1938 ast_str_append(res, 0, "%s%s", sep, perms[i].label);
1939 sep = ",";
1940 }
1941 }
1942
1943 if (ast_str_strlen(*res) == 0) {
1944 /* replace empty string with something sensible */
1945 ast_str_append(res, 0, "<none>");
1946 }
1947
1948 return ast_str_buffer(*res);
1949}
1950
1951
1952/*! \brief Convert authority code to a list of options. Note that the EVENT_FLAG_ALL
1953 * authority will always be returned. */
1954static const char *authority_to_str(int authority, struct ast_str **res)
1955{
1956 int i;
1957 char *sep = "";
1958
1959 ast_str_reset(*res);
1960 if (authority != EVENT_FLAG_SHUTDOWN-1) {
1961 for (i = 0; i < ARRAY_LEN(perms)(size_t) (sizeof(perms) / sizeof(0[perms])) - 1; i++) {
1962 if (authority & perms[i].num) {
1963 ast_str_append(res, 0, "%s%s", sep, perms[i].label);
1964 sep = ",";
1965 }
1966 }
1967 }
1968
1969 if (ast_str_strlen(*res) == 0) {
1970 /* replace empty string with something sensible */
1971 ast_str_append(res, 0, "<none>");
1972 }
1973
1974 return ast_str_buffer(*res);
1975}
1976
1977/*! Tells you if smallstr exists inside bigstr
1978 which is delim by delim and uses no buf or stringsep
1979 ast_instring("this|that|more","this",'|') == 1;
1980
1981 feel free to move this to app.c -anthm */
1982static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
1983{
1984 const char *val = bigstr, *next;
1985
1986 do {
1987 if ((next = strchr(val, delim)(__extension__ (__builtin_constant_p (delim) && !__builtin_constant_p
(val) && (delim) == '\0' ? (char *) __rawmemchr (val
, delim) : __builtin_strchr (val, delim)))
)) {
1988 if (!strncmp(val, smallstr, (next - val))(__extension__ (__builtin_constant_p ((next - val)) &&
((__builtin_constant_p (val) && strlen (val) < ((
size_t) ((next - val)))) || (__builtin_constant_p (smallstr) &&
strlen (smallstr) < ((size_t) ((next - val))))) ? strcmp (
val, smallstr) : strncmp (val, smallstr, (next - val))))
) {
1989 return 1;
1990 } else {
1991 continue;
1992 }
1993 } else {
1994 return !strcmp(smallstr, val);
1995 }
1996 } while (*(val = (next + 1)));
1997
1998 return 0;
1999}
2000
2001static int get_perm(const char *instr)
2002{
2003 int x = 0, ret = 0;
2004
2005 if (!instr) {
2006 return 0;
2007 }
2008
2009 for (x = 0; x < ARRAY_LEN(perms)(size_t) (sizeof(perms) / sizeof(0[perms])); x++) {
2010 if (ast_instring(instr, perms[x].label, ',')) {
2011 ret |= perms[x].num;
2012 }
2013 }
2014
2015 return ret;
2016}
2017
2018/*!
2019 * A number returns itself, false returns 0, true returns all flags,
2020 * other strings return the flags that are set.
2021 */
2022static int strings_to_mask(const char *string)
2023{
2024 const char *p;
2025
2026 if (ast_strlen_zero(string)_ast_strlen_zero(string, "manager.c", __PRETTY_FUNCTION__, 2026
)
) {
2027 return -1;
2028 }
2029
2030 for (p = string; *p; p++) {
2031 if (*p < '0' || *p > '9') {
2032 break;
2033 }
2034 }
2035 if (!*p) { /* all digits */
2036 return atoi(string);
2037 }
2038 if (ast_false(string)) {
2039 return 0;
2040 }
2041 if (ast_true(string)) { /* all permissions */
2042 int x, ret = 0;
2043 for (x = 0; x < ARRAY_LEN(perms)(size_t) (sizeof(perms) / sizeof(0[perms])); x++) {
2044 ret |= perms[x].num;
2045 }
2046 return ret;
2047 }
2048 return get_perm(string);
2049}
2050
2051/*! \brief Unreference manager session object.
2052 If no more references, then go ahead and delete it */
2053static struct mansession_session *unref_mansession(struct mansession_session *s)
2054{
2055 int refcount = ao2_ref(s, -1)__ao2_ref((s), (-1), "", "manager.c", 2055, __PRETTY_FUNCTION__
)
;
2056 if (manager_debug) {
2057 ast_debug(1, "Mansession: %p refcount now %d\n", s, refcount - 1)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 2057, __PRETTY_FUNCTION__, "Mansession: %p refcount now %d\n"
, s, refcount - 1); } } while (0)
;
2058 }
2059 return NULL((void*)0);
2060}
2061
2062static void event_filter_destructor(void *obj)
2063{
2064 regex_t *regex_filter = obj;
2065 regfree(regex_filter);
2066}
2067
2068static void session_destructor(void *obj)
2069{
2070 struct mansession_session *session = obj;
2071 struct eventqent *eqe = session->last_ev;
2072 struct ast_datastore *datastore;
2073
2074 /* Get rid of each of the data stores on the session */
2075 while ((datastore = AST_LIST_REMOVE_HEAD(&session->datastores, entry)({ typeof((&session->datastores)->first) __cur = (&
session->datastores)->first; if (__cur) { (&session
->datastores)->first = __cur->entry.next; __cur->
entry.next = ((void*)0); if ((&session->datastores)->
last == __cur) (&session->datastores)->last = ((void
*)0); } __cur; })
)) {
2076 /* Free the data store */
2077 ast_datastore_free(datastore);
2078 }
2079
2080 if (session->f != NULL((void*)0)) {
2081 fflush(session->f);
2082 fclose(session->f);
2083 }
2084 if (eqe) {
2085 ast_atomic_fetchadd_int(&eqe->usecount, -1);
2086 }
2087 if (session->chanvars) {
2088 ast_variables_destroy(session->chanvars);
2089 }
2090
2091 if (session->whitefilters) {
2092 ao2_t_ref(session->whitefilters, -1, "decrement ref for white container, should be last one")__ao2_ref((session->whitefilters), (-1), ("decrement ref for white container, should be last one"
), "manager.c", 2092, __PRETTY_FUNCTION__)
;
2093 }
2094
2095 if (session->blackfilters) {
2096 ao2_t_ref(session->blackfilters, -1, "decrement ref for black container, should be last one")__ao2_ref((session->blackfilters), (-1), ("decrement ref for black container, should be last one"
), "manager.c", 2096, __PRETTY_FUNCTION__)
;
2097 }
2098}
2099
2100/*! \brief Allocate manager session structure and add it to the list of sessions */
2101static struct mansession_session *build_mansession(const struct ast_sockaddr *addr)
2102{
2103 struct ao2_container *sessions;
2104 struct mansession_session *newsession;
2105
2106 newsession = ao2_alloc(sizeof(*newsession), session_destructor)__ao2_alloc((sizeof(*newsession)), (session_destructor), AO2_ALLOC_OPT_LOCK_MUTEX
, "", "manager.c", 2106, __PRETTY_FUNCTION__)
;
2107 if (!newsession) {
2108 return NULL((void*)0);
2109 }
2110
2111 newsession->whitefilters = ao2_container_alloc(1, NULL, NULL)__ao2_container_alloc_hash(((AO2_ALLOC_OPT_LOCK_MUTEX)), (0),
(((1))), (((((void*)0)))), (((void*)0)), (((((void*)0)))), ""
, "manager.c", 2111, __PRETTY_FUNCTION__)
;
2112 newsession->blackfilters = ao2_container_alloc(1, NULL, NULL)__ao2_container_alloc_hash(((AO2_ALLOC_OPT_LOCK_MUTEX)), (0),
(((1))), (((((void*)0)))), (((void*)0)), (((((void*)0)))), ""
, "manager.c", 2112, __PRETTY_FUNCTION__)
;
2113 if (!newsession->whitefilters || !newsession->blackfilters) {
2114 ao2_ref(newsession, -1)__ao2_ref((newsession), (-1), "", "manager.c", 2114, __PRETTY_FUNCTION__
)
;
2115 return NULL((void*)0);
2116 }
2117
2118 newsession->fd = -1;
2119 newsession->waiting_thread = AST_PTHREADT_NULL(pthread_t) -1;
2120 newsession->writetimeout = 100;
2121 newsession->send_events = -1;
2122 ast_sockaddr_copy(&newsession->addr, addr);
2123
2124 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 2124
, __PRETTY_FUNCTION__, "mgr_sessions")
;
2125 if (sessions) {
2126 ao2_link(sessions, newsession)__ao2_link((sessions), (newsession), 0, "", "manager.c", 2126
, __PRETTY_FUNCTION__)
;
2127 ao2_ref(sessions, -1)__ao2_ref((sessions), (-1), "", "manager.c", 2127, __PRETTY_FUNCTION__
)
;
2128 }
2129
2130 return newsession;
2131}
2132
2133static int mansession_cmp_fn(void *obj, void *arg, int flags)
2134{
2135 struct mansession_session *s = obj;
2136 char *str = arg;
2137 return !strcasecmp(s->username, str) ? CMP_MATCH : 0;
2138}
2139
2140static void session_destroy(struct mansession_session *s)
2141{
2142 struct ao2_container *sessions;
2143
2144 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 2144
, __PRETTY_FUNCTION__, "mgr_sessions")
;
2145 if (sessions) {
2146 ao2_unlink(sessions, s)__ao2_unlink((sessions), (s), 0, "", "manager.c", 2146, __PRETTY_FUNCTION__
)
;
2147 ao2_ref(sessions, -1)__ao2_ref((sessions), (-1), "", "manager.c", 2147, __PRETTY_FUNCTION__
)
;
2148 }
2149 unref_mansession(s);
2150}
2151
2152
2153static int check_manager_session_inuse(const char *name)
2154{
2155 struct ao2_container *sessions;
2156 struct mansession_session *session;
2157 int inuse = 0;
2158
2159 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 2159
, __PRETTY_FUNCTION__, "mgr_sessions")
;
2160 if (sessions) {
2161 session = ao2_find(sessions, (char *) name, 0)__ao2_find((sessions), ((char *) name), (0), "", "manager.c",
2161, __PRETTY_FUNCTION__)
;
2162 ao2_ref(sessions, -1)__ao2_ref((sessions), (-1), "", "manager.c", 2162, __PRETTY_FUNCTION__
)
;
2163 if (session) {
2164 unref_mansession(session);
2165 inuse = 1;
2166 }
2167 }
2168 return inuse;
2169}
2170
2171
2172/*!
2173 * lookup an entry in the list of registered users.
2174 * must be called with the list lock held.
2175 */
2176static struct ast_manager_user *get_manager_by_name_locked(const char *name)
2177{
2178 struct ast_manager_user *user = NULL((void*)0);
2179
2180 AST_RWLIST_TRAVERSE(&users, user, list)for((user) = (&users)->first; (user); (user) = (user)->
list.next)
{
2181 if (!strcasecmp(user->username, name)) {
2182 break;
2183 }
2184 }
2185
2186 return user;
2187}
2188
2189/*! \brief Get displayconnects config option.
2190 * \param session manager session to get parameter from.
2191 * \return displayconnects config option value.
2192 */
2193static int manager_displayconnects(struct mansession_session *session)
2194{
2195 struct ast_manager_user *user = NULL((void*)0);
2196 int ret = 0;
2197
2198 AST_RWLIST_RDLOCK(&users)__ast_rwlock_rdlock("manager.c", 2198, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
2199 if ((user = get_manager_by_name_locked(session->username))) {
2200 ret = user->displayconnects;
2201 }
2202 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 2202, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
2203
2204 return ret;
2205}
2206
2207static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance);
2208
2209static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2210{
2211 struct manager_action *cur;
2212 struct ast_str *authority;
2213 int num, l, which;
2214 const char *auth_str;
2215 char *ret = NULL((void*)0);
2216#ifdef AST_XML_DOCS
2217 char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64];
2218 char arguments_title[64], privilege_title[64], final_response_title[64], list_responses_title[64];
2219#endif
2220
2221 switch (cmd) {
2222 case CLI_INIT:
2223 e->command = "manager show command";
2224 e->usage =
2225 "Usage: manager show command <actionname> [<actionname> [<actionname> [...]]]\n"
2226 " Shows the detailed description for a specific Asterisk manager interface command.\n";
2227 return NULL((void*)0);
2228 case CLI_GENERATE:
2229 l = strlen(a->word);
2230 which = 0;
2231 AST_RWLIST_RDLOCK(&actions)__ast_rwlock_rdlock("manager.c", 2231, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
2232 AST_RWLIST_TRAVERSE(&actions, cur, list)for((cur) = (&actions)->first; (cur); (cur) = (cur)->
list.next)
{
2233 if (!strncasecmp(a->word, cur->action, l) && ++which > a->n) {
2234 ret = ast_strdup(cur->action)_ast_strdup((cur->action), "manager.c", 2234, __PRETTY_FUNCTION__
)
;
2235 break; /* make sure we exit even if ast_strdup() returns NULL */
2236 }
2237 }
2238 AST_RWLIST_UNLOCK(&actions)__ast_rwlock_unlock("manager.c", 2238, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
2239 return ret;
2240 }
2241 authority = ast_str_alloca(MAX_AUTH_PERM_STRING)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 150); __ast_str_buf->len = 150; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
2242 if (a->argc < 4) {
2243 return CLI_SHOWUSAGE(char *)1;
2244 }
2245
2246#ifdef AST_XML_DOCS
2247 /* setup the titles */
2248 term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA35, 0, 40);
2249 term_color(description_title, "[Description]\n", COLOR_MAGENTA35, 0, 40);
2250 term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA35, 0, 40);
2251 term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA35, 0, 40);
2252 term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA35, 0, 40);
2253 term_color(privilege_title, "[Privilege]\n", COLOR_MAGENTA35, 0, 40);
2254 term_color(final_response_title, "[Final Response]\n", COLOR_MAGENTA35, 0, 40);
2255 term_color(list_responses_title, "[List Responses]\n", COLOR_MAGENTA35, 0, 40);
2256#endif
2257
2258 AST_RWLIST_RDLOCK(&actions)__ast_rwlock_rdlock("manager.c", 2258, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
2259 AST_RWLIST_TRAVERSE(&actions, cur, list)for((cur) = (&actions)->first; (cur); (cur) = (cur)->
list.next)
{
2260 for (num = 3; num < a->argc; num++) {
2261 if (!strcasecmp(cur->action, a->argv[num])) {
2262 auth_str = authority_to_str(cur->authority, &authority);
2263
2264#ifdef AST_XML_DOCS
2265 if (cur->docsrc == AST_XML_DOC) {
2266 char *syntax = ast_xmldoc_printable(S_OR(cur->syntax, "Not available")({typeof(&((cur->syntax)[0])) __x = (cur->syntax); _ast_strlen_zero
(__x, "manager.c", __PRETTY_FUNCTION__, 2266) ? ("Not available"
) : __x;})
, 1);
2267 char *synopsis = ast_xmldoc_printable(S_OR(cur->synopsis, "Not available")({typeof(&((cur->synopsis)[0])) __x = (cur->synopsis
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 2267
) ? ("Not available") : __x;})
, 1);
2268 char *description = ast_xmldoc_printable(S_OR(cur->description, "Not available")({typeof(&((cur->description)[0])) __x = (cur->description
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 2268
) ? ("Not available") : __x;})
, 1);
2269 char *arguments = ast_xmldoc_printable(S_OR(cur->arguments, "Not available")({typeof(&((cur->arguments)[0])) __x = (cur->arguments
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 2269
) ? ("Not available") : __x;})
, 1);
2270 char *seealso = ast_xmldoc_printable(S_OR(cur->seealso, "Not available")({typeof(&((cur->seealso)[0])) __x = (cur->seealso)
; _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 2270
) ? ("Not available") : __x;})
, 1);
2271 char *privilege = ast_xmldoc_printable(S_OR(auth_str, "Not available")({typeof(&((auth_str)[0])) __x = (auth_str); _ast_strlen_zero
(__x, "manager.c", __PRETTY_FUNCTION__, 2271) ? ("Not available"
) : __x;})
, 1);
2272 char *responses = ast_xmldoc_printable("None", 1);
2273 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",
2274 syntax_title, syntax,
2275 synopsis_title, synopsis,
2276 description_title, description,
2277 arguments_title, arguments,
2278 seealso_title, seealso,
2279 privilege_title, privilege,
2280 list_responses_title);
2281
2282 if (!cur->list_responses) {
2283 ast_cli(a->fd, "%s\n\n", responses);
2284 } else {
2285 struct ast_xml_doc_item *temp;
2286 for (temp = cur->list_responses; temp; temp = AST_LIST_NEXT(temp, next)((temp)->next.next)) {
2287 ast_cli(a->fd, "Event: %s\n", temp->name);
2288 print_event_instance(a, temp);
2289 }
2290 }
2291
2292 ast_cli(a->fd, "%s", final_response_title);
2293
2294 if (!cur->final_response) {
2295 ast_cli(a->fd, "%s\n\n", responses);
2296 } else {
2297 ast_cli(a->fd, "Event: %s\n", cur->final_response->name);
2298 print_event_instance(a, cur->final_response);
2299 }
2300 } else
2301#endif
2302 {
2303 ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
2304 cur->action, cur->synopsis,
2305 auth_str,
2306 S_OR(cur->description, "")({typeof(&((cur->description)[0])) __x = (cur->description
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 2306
) ? ("") : __x;})
);
2307 }
2308 }
2309 }
2310 }
2311 AST_RWLIST_UNLOCK(&actions)__ast_rwlock_unlock("manager.c", 2311, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
2312
2313 return CLI_SUCCESS(char *)0;
2314}
2315
2316static char *handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2317{
2318 switch (cmd) {
2319 case CLI_INIT:
2320 e->command = "manager set debug [on|off]";
2321 e->usage = "Usage: manager set debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
2322 return NULL((void*)0);
2323 case CLI_GENERATE:
2324 return NULL((void*)0);
2325 }
2326
2327 if (a->argc == 3) {
2328 ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
2329 } else if (a->argc == 4) {
2330 if (!strcasecmp(a->argv[3], "on")) {
2331 manager_debug = 1;
2332 } else if (!strcasecmp(a->argv[3], "off")) {
2333 manager_debug = 0;
2334 } else {
2335 return CLI_SHOWUSAGE(char *)1;
2336 }
2337 }
2338 return CLI_SUCCESS(char *)0;
2339}
2340
2341static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2342{
2343 struct ast_manager_user *user = NULL((void*)0);
2344 int l, which;
2345 char *ret = NULL((void*)0);
2346 struct ast_str *rauthority = ast_str_alloca(MAX_AUTH_PERM_STRING)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 150); __ast_str_buf->len = 150; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
2347 struct ast_str *wauthority = ast_str_alloca(MAX_AUTH_PERM_STRING)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 150); __ast_str_buf->len = 150; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
2348 struct ast_variable *v;
2349
2350 switch (cmd) {
2351 case CLI_INIT:
2352 e->command = "manager show user";
2353 e->usage =
2354 " Usage: manager show user <user>\n"
2355 " Display all information related to the manager user specified.\n";
2356 return NULL((void*)0);
2357 case CLI_GENERATE:
2358 l = strlen(a->word);
2359 which = 0;
2360 if (a->pos != 3) {
2361 return NULL((void*)0);
2362 }
2363 AST_RWLIST_RDLOCK(&users)__ast_rwlock_rdlock("manager.c", 2363, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
2364 AST_RWLIST_TRAVERSE(&users, user, list)for((user) = (&users)->first; (user); (user) = (user)->
list.next)
{
2365 if ( !strncasecmp(a->word, user->username, l) && ++which > a->n ) {
2366 ret = ast_strdup(user->username)_ast_strdup((user->username), "manager.c", 2366, __PRETTY_FUNCTION__
)
;
2367 break;
2368 }
2369 }
2370 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 2370, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
2371 return ret;
2372 }
2373
2374 if (a->argc != 4) {
2375 return CLI_SHOWUSAGE(char *)1;
2376 }
2377
2378 AST_RWLIST_RDLOCK(&users)__ast_rwlock_rdlock("manager.c", 2378, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
2379
2380 if (!(user = get_manager_by_name_locked(a->argv[3]))) {
2381 ast_cli(a->fd, "There is no manager called %s\n", a->argv[3]);
2382 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 2382, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
2383 return CLI_SUCCESS(char *)0;
2384 }
2385
2386 ast_cli(a->fd, "\n");
2387 ast_cli(a->fd,
2388 " username: %s\n"
2389 " secret: %s\n"
2390 " ACL: %s\n"
2391 " read perm: %s\n"
2392 " write perm: %s\n"
2393 " displayconnects: %s\n"
2394 "allowmultiplelogin: %s\n",
2395 S_OR(user->username, "(N/A)")({typeof(&((user->username)[0])) __x = (user->username
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 2395
) ? ("(N/A)") : __x;})
,
2396 (user->secret ? "<Set>" : "(N/A)"),
2397 ((user->acl && !ast_acl_list_is_empty(user->acl)) ? "yes" : "no"),
2398 user_authority_to_str(user->readperm, &rauthority),
2399 user_authority_to_str(user->writeperm, &wauthority),
2400 (user->displayconnects ? "yes" : "no"),
2401 (user->allowmultiplelogin ? "yes" : "no"));
2402 ast_cli(a->fd, " Variables: \n");
2403 for (v = user->chanvars ; v ; v = v->next) {
2404 ast_cli(a->fd, " %s = %s\n", v->name, v->value);
2405 }
2406
2407 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 2407, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
2408
2409 return CLI_SUCCESS(char *)0;
2410}
2411
2412static char *handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2413{
2414 struct ast_manager_user *user = NULL((void*)0);
2415 int count_amu = 0;
2416 switch (cmd) {
2417 case CLI_INIT:
2418 e->command = "manager show users";
2419 e->usage =
2420 "Usage: manager show users\n"
2421 " Prints a listing of all managers that are currently configured on that\n"
2422 " system.\n";
2423 return NULL((void*)0);
2424 case CLI_GENERATE:
2425 return NULL((void*)0);
2426 }
2427 if (a->argc != 3) {
2428 return CLI_SHOWUSAGE(char *)1;
2429 }
2430
2431 AST_RWLIST_RDLOCK(&users)__ast_rwlock_rdlock("manager.c", 2431, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
2432
2433 /* If there are no users, print out something along those lines */
2434 if (AST_RWLIST_EMPTY(&users)(((&users)->first) == ((void*)0))) {
2435 ast_cli(a->fd, "There are no manager users.\n");
2436 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 2436, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
2437 return CLI_SUCCESS(char *)0;
2438 }
2439
2440 ast_cli(a->fd, "\nusername\n--------\n");
2441
2442 AST_RWLIST_TRAVERSE(&users, user, list)for((user) = (&users)->first; (user); (user) = (user)->
list.next)
{
2443 ast_cli(a->fd, "%s\n", user->username);
2444 count_amu++;
2445 }
2446
2447 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 2447, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
2448
2449 ast_cli(a->fd,"-------------------\n"
2450 "%d manager users configured.\n", count_amu);
2451 return CLI_SUCCESS(char *)0;
2452}
2453
2454/*! \brief CLI command manager list commands */
2455static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2456{
2457 struct manager_action *cur;
2458 int name_len = 1;
2459 int space_remaining;
2460#define HSMC_FORMAT" %-*.*s %-.*s\n" " %-*.*s %-.*s\n"
2461 switch (cmd) {
2462 case CLI_INIT:
2463 e->command = "manager show commands";
2464 e->usage =
2465 "Usage: manager show commands\n"
2466 " Prints a listing of all the available Asterisk manager interface commands.\n";
2467 return NULL((void*)0);
2468 case CLI_GENERATE:
2469 return NULL((void*)0);
2470 }
2471
2472 AST_RWLIST_RDLOCK(&actions)__ast_rwlock_rdlock("manager.c", 2472, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
2473 AST_RWLIST_TRAVERSE(&actions, cur, list)for((cur) = (&actions)->first; (cur); (cur) = (cur)->
list.next)
{
2474 int incoming_len = strlen(cur->action);
2475 if (incoming_len > name_len) {
2476 name_len = incoming_len;
2477 }
2478 }
2479
2480 space_remaining = MGR_SHOW_TERMINAL_WIDTH80 - name_len - 4;
2481 if (space_remaining < 0) {
2482 space_remaining = 0;
2483 }
2484
2485 ast_cli(a->fd, HSMC_FORMAT" %-*.*s %-.*s\n", name_len, name_len, "Action", space_remaining, "Synopsis");
2486 ast_cli(a->fd, HSMC_FORMAT" %-*.*s %-.*s\n", name_len, name_len, "------", space_remaining, "--------");
2487
2488 AST_RWLIST_TRAVERSE(&actions, cur, list)for((cur) = (&actions)->first; (cur); (cur) = (cur)->
list.next)
{
2489 ast_cli(a->fd, HSMC_FORMAT" %-*.*s %-.*s\n", name_len, name_len, cur->action, space_remaining, cur->synopsis);
2490 }
2491 AST_RWLIST_UNLOCK(&actions)__ast_rwlock_unlock("manager.c", 2491, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
2492
2493 return CLI_SUCCESS(char *)0;
2494}
2495
2496/*! \brief CLI command manager list connected */
2497static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2498{
2499 struct ao2_container *sessions;
2500 struct mansession_session *session;
2501 time_t now = time(NULL((void*)0));
2502#define HSMCONN_FORMAT1" %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n" " %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
2503#define HSMCONN_FORMAT2" %-15.15s %-55.55s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n" " %-15.15s %-55.55s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
2504 int count = 0;
2505 struct ao2_iterator i;
2506
2507 switch (cmd) {
2508 case CLI_INIT:
2509 e->command = "manager show connected";
2510 e->usage =
2511 "Usage: manager show connected\n"
2512 " Prints a listing of the users that are currently connected to the\n"
2513 "Asterisk manager interface.\n";
2514 return NULL((void*)0);
2515 case CLI_GENERATE:
2516 return NULL((void*)0);
2517 }
2518
2519 ast_cli(a->fd, HSMCONN_FORMAT1" %-15.15s %-55.55s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n", "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
2520
2521 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 2521
, __PRETTY_FUNCTION__, "mgr_sessions")
;
2522 if (sessions) {
2523 i = ao2_iterator_init(sessions, 0);
2524 ao2_ref(sessions, -1)__ao2_ref((sessions), (-1), "", "manager.c", 2524, __PRETTY_FUNCTION__
)
;
2525 while ((session = ao2_iterator_next(&i)__ao2_iterator_next((&i), "", "manager.c", 2525, __PRETTY_FUNCTION__
)
)) {
2526 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 2526, "session")
;
2527 ast_cli(a->fd, HSMCONN_FORMAT2" %-15.15s %-55.55s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n", session->username,
2528 ast_sockaddr_stringify_addr(&session->addr),
2529 (int) (session->sessionstart),
2530 (int) (now - session->sessionstart),
2531 session->fd,
2532 session->inuse,
2533 session->readperm,
2534 session->writeperm);
2535 count++;
2536 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 2536,
"session")
;
2537 unref_mansession(session);
2538 }
2539 ao2_iterator_destroy(&i);
2540 }
2541 ast_cli(a->fd, "%d users connected.\n", count);
2542
2543 return CLI_SUCCESS(char *)0;
2544}
2545
2546/*! \brief CLI command manager list eventq */
2547/* Should change to "manager show connected" */
2548static char *handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2549{
2550 struct eventqent *s;
2551 switch (cmd) {
2552 case CLI_INIT:
2553 e->command = "manager show eventq";
2554 e->usage =
2555 "Usage: manager show eventq\n"
2556 " Prints a listing of all events pending in the Asterisk manger\n"
2557 "event queue.\n";
2558 return NULL((void*)0);
2559 case CLI_GENERATE:
2560 return NULL((void*)0);
2561 }
2562 AST_RWLIST_RDLOCK(&all_events)__ast_rwlock_rdlock("manager.c", 2562, __PRETTY_FUNCTION__, &
(&all_events)->lock, "&(&all_events)->lock"
)
;
2563 AST_RWLIST_TRAVERSE(&all_events, s, eq_next)for((s) = (&all_events)->first; (s); (s) = (s)->eq_next
.next)
{
2564 ast_cli(a->fd, "Usecount: %d\n", s->usecount);
2565 ast_cli(a->fd, "Category: %d\n", s->category);
2566 ast_cli(a->fd, "Event:\n%s", s->eventdata);
2567 }
2568 AST_RWLIST_UNLOCK(&all_events)__ast_rwlock_unlock("manager.c", 2568, __PRETTY_FUNCTION__, &
(&all_events)->lock, "&(&all_events)->lock"
)
;
2569
2570 return CLI_SUCCESS(char *)0;
2571}
2572
2573/*! \brief CLI command manager reload */
2574static char *handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2575{
2576 switch (cmd) {
2577 case CLI_INIT:
2578 e->command = "manager reload";
2579 e->usage =
2580 "Usage: manager reload\n"
2581 " Reloads the manager configuration.\n";
2582 return NULL((void*)0);
2583 case CLI_GENERATE:
2584 return NULL((void*)0);
2585 }
2586 if (a->argc > 2) {
2587 return CLI_SHOWUSAGE(char *)1;
2588 }
2589 reload_manager();
2590 return CLI_SUCCESS(char *)0;
2591}
2592
2593static struct eventqent *advance_event(struct eventqent *e)
2594{
2595 struct eventqent *next;
2596
2597 AST_RWLIST_RDLOCK(&all_events)__ast_rwlock_rdlock("manager.c", 2597, __PRETTY_FUNCTION__, &
(&all_events)->lock, "&(&all_events)->lock"
)
;
2598 if ((next = AST_RWLIST_NEXT(e, eq_next)((e)->eq_next.next))) {
2599 ast_atomic_fetchadd_int(&next->usecount, 1);
2600 ast_atomic_fetchadd_int(&e->usecount, -1);
2601 }
2602 AST_RWLIST_UNLOCK(&all_events)__ast_rwlock_unlock("manager.c", 2602, __PRETTY_FUNCTION__, &
(&all_events)->lock, "&(&all_events)->lock"
)
;
2603 return next;
2604}
2605
2606#define GET_HEADER_FIRST_MATCH0 0
2607#define GET_HEADER_LAST_MATCH1 1
2608#define GET_HEADER_SKIP_EMPTY2 2
2609
2610/*!
2611 * \brief Return a matching header value.
2612 *
2613 * \details
2614 * Generic function to return either the first or the last
2615 * matching header from a list of variables, possibly skipping
2616 * empty strings.
2617 *
2618 * \note At the moment there is only one use of this function in
2619 * this file, so we make it static.
2620 *
2621 * \note Never returns NULL.
2622 */
2623static const char *__astman_get_header(const struct message *m, char *var, int mode)
2624{
2625 int x, l = strlen(var);
2626 const char *result = "";
2627
2628 if (!m) {
2629 return result;
2630 }
2631
2632 for (x = 0; x < m->hdrcount; x++) {
2633 const char *h = m->headers[x];
2634 if (!strncasecmp(var, h, l) && h[l] == ':') {
2635 const char *value = h + l + 1;
2636 value = ast_skip_blanks(value); /* ignore leading spaces in the value */
2637 /* found a potential candidate */
2638 if ((mode & GET_HEADER_SKIP_EMPTY2) && ast_strlen_zero(value)_ast_strlen_zero(value, "manager.c", __PRETTY_FUNCTION__, 2638
)
) {
2639 continue; /* not interesting */
2640 }
2641 if (mode & GET_HEADER_LAST_MATCH1) {
2642 result = value; /* record the last match so far */
2643 } else {
2644 return value;
2645 }
2646 }
2647 }
2648
2649 return result;
2650}
2651
2652/*!
2653 * \brief Return the first matching variable from an array.
2654 *
2655 * \note This is the legacy function and is implemented in
2656 * therms of __astman_get_header().
2657 *
2658 * \note Never returns NULL.
2659 */
2660const char *astman_get_header(const struct message *m, char *var)
2661{
2662 return __astman_get_header(m, var, GET_HEADER_FIRST_MATCH0);
2663}
2664
2665/*!
2666 * \internal
2667 * \brief Process one "Variable:" header value string.
2668 *
2669 * \param head Current list of AMI variables to get new values added.
2670 * \param hdr_val Header value string to process.
2671 *
2672 * \return New variable list head.
2673 */
2674static struct ast_variable *man_do_variable_value(struct ast_variable *head, const char *hdr_val)
2675{
2676 char *parse;
2677 AST_DECLARE_APP_ARGS(args,struct { unsigned int argc; char *argv[0]; char *vars[64]; } args
= { 0, }
2678 AST_APP_ARG(vars)[64];struct { unsigned int argc; char *argv[0]; char *vars[64]; } args
= { 0, }
2679 )struct { unsigned int argc; char *argv[0]; char *vars[64]; } args
= { 0, }
;
2680
2681 hdr_val = ast_skip_blanks(hdr_val); /* ignore leading spaces in the value */
2682 parse = ast_strdupa(hdr_val)(__extension__ ({ const char *__old = (hdr_val); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
;
2683
2684 /* Break the header value string into name=val pair items. */
2685 AST_STANDARD_APP_ARGS(args, parse)args.argc = __ast_app_separate_args(parse, ',', 1, args.argv,
((sizeof(args) - __builtin_offsetof(typeof(args), argv)) / sizeof
(args.argv[0])))
;
2686 if (args.argc) {
2687 int y;
2688
2689 /* Process each name=val pair item. */
2690 for (y = 0; y < args.argc; y++) {
2691 struct ast_variable *cur;
2692 char *var;
2693 char *val;
2694
2695 if (!args.vars[y]) {
2696 continue;
2697 }
2698 var = val = args.vars[y];
2699 strsep(&val, "=");
2700
2701 /* XXX We may wish to trim whitespace from the strings. */
2702 if (!val || ast_strlen_zero(var)_ast_strlen_zero(var, "manager.c", __PRETTY_FUNCTION__, 2702)) {
2703 continue;
2704 }
2705
2706 /* Create new variable list node and prepend it to the list. */
2707 cur = ast_variable_new(var, val, "");
2708 if (cur) {
2709 cur->next = head;
2710 head = cur;
2711 }
2712 }
2713 }
2714
2715 return head;
2716}
2717
2718struct ast_variable *astman_get_variables(const struct message *m)
2719{
2720 return astman_get_variables_order(m, ORDER_REVERSE);
2721}
2722
2723struct ast_variable *astman_get_variables_order(const struct message *m,
2724 enum variable_orders order)
2725{
2726 int varlen;
2727 int x;
2728 struct ast_variable *head = NULL((void*)0);
2729
2730 static const char var_hdr[] = "Variable:";
2731
2732 /* Process all "Variable:" headers. */
2733 varlen = strlen(var_hdr);
2734 for (x = 0; x < m->hdrcount; x++) {
2735 if (strncasecmp(var_hdr, m->headers[x], varlen)) {
2736 continue;
2737 }
2738 head = man_do_variable_value(head, m->headers[x] + varlen);
2739 }
2740
2741 if (order == ORDER_NATURAL) {
2742 head = ast_variables_reverse(head);
2743 }
2744
2745 return head;
2746}
2747
2748/*! \brief access for hooks to send action messages to ami */
2749int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
2750{
2751 const char *action;
2752 int ret = 0;
2753 struct manager_action *act_found;
2754 struct mansession s = {.session = NULL((void*)0), };
2755 struct message m = { 0 };
2756 char *dup_str;
2757 char *src;
2758 int x = 0;
2759 int curlen;
2760
2761 if (hook == NULL((void*)0)) {
2762 return -1;
2763 }
2764
2765 /* Create our own copy of the AMI action msg string. */
2766 src = dup_str = ast_strdup(msg)_ast_strdup((msg), "manager.c", 2766, __PRETTY_FUNCTION__);
2767 if (!dup_str) {
2768 return -1;
2769 }
2770
2771 /* convert msg string to message struct */
2772 curlen = strlen(src);
2773 for (x = 0; x < curlen; x++) {
2774 int cr; /* set if we have \r */
2775 if (src[x] == '\r' && x+1 < curlen && src[x+1] == '\n')
2776 cr = 2; /* Found. Update length to include \r\n */
2777 else if (src[x] == '\n')
2778 cr = 1; /* also accept \n only */
2779 else
2780 continue;
2781 /* don't keep empty lines */
2782 if (x && m.hdrcount < ARRAY_LEN(m.headers)(size_t) (sizeof(m.headers) / sizeof(0[m.headers]))) {
2783 /* ... but trim \r\n and terminate the header string */
2784 src[x] = '\0';
2785 m.headers[m.hdrcount++] = src;
2786 }
2787 x += cr;
2788 curlen -= x; /* remaining size */
2789 src += x; /* update pointer */
2790 x = -1; /* reset loop */
2791 }
2792
2793 action = astman_get_header(&m, "Action");
2794 if (strcasecmp(action, "login")) {
2795 act_found = action_find(action);
2796 if (act_found) {
2797 /*
2798 * we have to simulate a session for this action request
2799 * to be able to pass it down for processing
2800 * This is necessary to meet the previous design of manager.c
2801 */
2802 s.hook = hook;
2803 s.f = (void*)1; /* set this to something so our request will make it through all functions that test it*/
2804
2805 ao2_lock(act_found)__ao2_lock(act_found, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 2805, "act_found")
;
2806 if (act_found->registered && act_found->func) {
2807 if (act_found->module) {
2808 ast_module_ref(act_found->module)__ast_module_ref(act_found->module, "manager.c", 2808, __PRETTY_FUNCTION__
)
;
2809 }
2810 ao2_unlock(act_found)__ao2_unlock(act_found, "manager.c", __PRETTY_FUNCTION__, 2810
, "act_found")
;
2811 ret = act_found->func(&s, &m);
2812 ao2_lock(act_found)__ao2_lock(act_found, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 2812, "act_found")
;
2813 if (act_found->module) {
2814 ast_module_unref(act_found->module)__ast_module_unref(act_found->module, "manager.c", 2814, __PRETTY_FUNCTION__
)
;
2815 }
2816 } else {
2817 ret = -1;
2818 }
2819 ao2_unlock(act_found)__ao2_unlock(act_found, "manager.c", __PRETTY_FUNCTION__, 2819
, "act_found")
;
2820 ao2_t_ref(act_found, -1, "done with found action object")__ao2_ref((act_found), (-1), ("done with found action object"
), "manager.c", 2820, __PRETTY_FUNCTION__)
;
2821 }
2822 }
2823 ast_freefree(dup_str);
2824 return ret;
2825}
2826
2827
2828/*!
2829 * helper function to send a string to the socket.
2830 * Return -1 on error (e.g. buffer full).
2831 */
2832static int send_string(struct mansession *s, char *string)
2833{
2834 int res;
2835 FILE *f = s->f ? s->f : s->session->f;
2836 int fd = s->f ? s->fd : s->session->fd;
2837
2838 /* It's a result from one of the hook's action invocation */
2839 if (s->hook) {
2840 /*
2841 * to send responses, we're using the same function
2842 * as for receiving events. We call the event "HookResponse"
2843 */
2844 s->hook->helper(EVENT_FLAG_HOOKRESPONSE(1 << 14), "HookResponse", string);
2845 return 0;
2846 }
2847
2848 if ((res = ast_careful_fwrite(f, fd, string, strlen(string), s->session->writetimeout))) {
2849 s->write_error = 1;
2850 }
2851
2852 return res;
2853}
2854
2855/*!
2856 * \brief thread local buffer for astman_append
2857 *
2858 * \note This can not be defined within the astman_append() function
2859 * because it declares a couple of functions that get used to
2860 * initialize the thread local storage key.
2861 */
2862AST_THREADSTORAGE(astman_append_buf)static void __init_astman_append_buf(void); static struct ast_threadstorage
astman_append_buf = { .once = 0, .key_init = __init_astman_append_buf
, .custom_init = ((void*)0), }; static void __init_astman_append_buf
(void) { pthread_key_create(&(astman_append_buf).key, free
); }
;
2863
2864AST_THREADSTORAGE(userevent_buf)static void __init_userevent_buf(void); static struct ast_threadstorage
userevent_buf = { .once = 0, .key_init = __init_userevent_buf
, .custom_init = ((void*)0), }; static void __init_userevent_buf
(void) { pthread_key_create(&(userevent_buf).key, free); }
;
2865
2866/*! \brief initial allocated size for the astman_append_buf and astman_send_*_va */
2867#define ASTMAN_APPEND_BUF_INITSIZE256 256
2868
2869/*!
2870 * utility functions for creating AMI replies
2871 */
2872void astman_append(struct mansession *s, const char *fmt, ...)
2873{
2874 int res;
2875 va_list ap;
2876 struct ast_str *buf;
2877
2878 if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE256))) {
2879 return;
2880 }
2881
2882 va_start(ap, fmt)__builtin_va_start(ap, fmt);
2883 res = ast_str_set_va(&buf, 0, fmt, ap);
2884 va_end(ap)__builtin_va_end(ap);
2885 if (res == AST_DYNSTR_BUILD_FAILED) {
2886 return;
2887 }
2888
2889 if (s->f != NULL((void*)0) || s->session->f != NULL((void*)0)) {
2890 send_string(s, ast_str_buffer(buf));
2891 } else {
2892 ast_verbose("fd == -1 in astman_append, should not happen\n")__ast_verbose("manager.c", 2892, __PRETTY_FUNCTION__, -1, "fd == -1 in astman_append, should not happen\n"
)
;
2893 }
2894}
2895
2896/*! \note NOTE: XXX this comment is unclear and possibly wrong.
2897 Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
2898 hold the session lock _or_ be running in an action callback (in which case s->session->busy will
2899 be non-zero). In either of these cases, there is no need to lock-protect the session's
2900 fd, since no other output will be sent (events will be queued), and no input will
2901 be read until either the current action finishes or get_input() obtains the session
2902 lock.
2903 */
2904
2905/*! \todo XXX MSG_MOREDATA should go to a header file. */
2906#define MSG_MOREDATA((char *)astman_send_response) ((char *)astman_send_response)
2907
2908/*! \brief send a response with an optional message,
2909 * and terminate it with an empty line.
2910 * m is used only to grab the 'ActionID' field.
2911 *
2912 * Use the explicit constant MSG_MOREDATA to remove the empty line.
2913 * XXX MSG_MOREDATA should go to a header file.
2914 */
2915static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
2916{
2917 const char *id = astman_get_header(m, "ActionID");
2918
2919 astman_append(s, "Response: %s\r\n", resp);
2920 if (!ast_strlen_zero(id)_ast_strlen_zero(id, "manager.c", __PRETTY_FUNCTION__, 2920)) {
2921 astman_append(s, "ActionID: %s\r\n", id);
2922 }
2923 if (listflag) {
2924 astman_append(s, "EventList: %s\r\n", listflag); /* Start, complete, cancelled */
2925 }
2926 if (msg == MSG_MOREDATA((char *)astman_send_response)) {
2927 return;
2928 } else if (msg) {
2929 astman_append(s, "Message: %s\r\n\r\n", msg);
2930 } else {
2931 astman_append(s, "\r\n");
2932 }
2933}
2934
2935void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
2936{
2937 astman_send_response_full(s, m, resp, msg, NULL((void*)0));
2938}
2939
2940void astman_send_error(struct mansession *s, const struct message *m, char *error)
2941{
2942 astman_send_response_full(s, m, "Error", error, NULL((void*)0));
2943}
2944
2945void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt, ...)
2946{
2947 int res;
2948 va_list ap;
2949 struct ast_str *buf;
2950 char *msg;
2951
2952 if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE256))) {
2953 return;
2954 }
2955
2956 va_start(ap, fmt)__builtin_va_start(ap, fmt);
2957 res = ast_str_set_va(&buf, 0, fmt, ap);
2958 va_end(ap)__builtin_va_end(ap);
2959 if (res == AST_DYNSTR_BUILD_FAILED) {
2960 return;
2961 }
2962
2963 /* astman_append will use the same underlying buffer, so copy the message out
2964 * before sending the response */
2965 msg = ast_str_buffer(buf);
2966 if (msg) {
2967 msg = ast_strdupa(msg)(__extension__ ({ const char *__old = (msg); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
2968 }
2969 astman_send_response_full(s, m, "Error", msg, NULL((void*)0));
2970}
2971
2972void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
2973{
2974 astman_send_response_full(s, m, "Success", msg, NULL((void*)0));
2975}
2976
2977static void astman_start_ack(struct mansession *s, const struct message *m)
2978{
2979 astman_send_response_full(s, m, "Success", MSG_MOREDATA((char *)astman_send_response), NULL((void*)0));
2980}
2981
2982void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
2983{
2984 astman_send_response_full(s, m, "Success", msg, listflag);
2985}
2986
2987void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
2988{
2989 const char *id = astman_get_header(m, "ActionID");
2990
2991 astman_append(s, "Event: %s\r\n", event_name);
2992 if (!ast_strlen_zero(id)_ast_strlen_zero(id, "manager.c", __PRETTY_FUNCTION__, 2992)) {
2993 astman_append(s, "ActionID: %s\r\n", id);
2994 }
2995 astman_append(s,
2996 "EventList: Complete\r\n"
2997 "ListItems: %d\r\n",
2998 count);
2999}
3000
3001void astman_send_list_complete_end(struct mansession *s)
3002{
3003 astman_append(s, "\r\n");
3004}
3005
3006/*! \brief Lock the 'mansession' structure. */
3007static void mansession_lock(struct mansession *s)
3008{
3009 ast_mutex_lock(&s->lock)__ast_pthread_mutex_lock("manager.c", 3009, __PRETTY_FUNCTION__
, "&s->lock", &s->lock)
;
3010}
3011
3012/*! \brief Unlock the 'mansession' structure. */
3013static void mansession_unlock(struct mansession *s)
3014{
3015 ast_mutex_unlock(&s->lock)__ast_pthread_mutex_unlock("manager.c", 3015, __PRETTY_FUNCTION__
, "&s->lock", &s->lock)
;
3016}
3017
3018/*! \brief
3019 Rather than braindead on,off this now can also accept a specific int mask value
3020 or a ',' delim list of mask strings (the same as manager.conf) -anthm
3021*/
3022static int set_eventmask(struct mansession *s, const char *eventmask)
3023{
3024 int maskint = strings_to_mask(eventmask);
3025
3026 ao2_lock(s->session)__ao2_lock(s->session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 3026, "s->session")
;
3027 if (maskint >= 0) {
3028 s->session->send_events = maskint;
3029 }
3030 ao2_unlock(s->session)__ao2_unlock(s->session, "manager.c", __PRETTY_FUNCTION__,
3030, "s->session")
;
3031
3032 return maskint;
3033}
3034
3035static enum ast_transport mansession_get_transport(const struct mansession *s)
3036{
3037 return s->tcptls_session->parent->tls_cfg ? AST_TRANSPORT_TLS :
3038 AST_TRANSPORT_TCP;
3039}
3040
3041static void report_invalid_user(const struct mansession *s, const char *username)
3042{
3043 char session_id[32];
3044 struct ast_security_event_inval_acct_id inval_acct_id = {
3045 .common.event_type = AST_SECURITY_EVENT_INVAL_ACCT_ID,
3046 .common.version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION1,
3047 .common.service = "AMI",
3048 .common.account_id = username,
3049 .common.session_tv = &s->session->sessionstart_tv,
3050 .common.local_addr = {
3051 .addr = &s->tcptls_session->parent->local_address,
3052 .transport = mansession_get_transport(s),
3053 },
3054 .common.remote_addr = {
3055 .addr = &s->session->addr,
3056 .transport = mansession_get_transport(s),
3057 },
3058 .common.session_id = session_id,
3059 };
3060
3061 snprintf(session_id, sizeof(session_id), "%p", s);
3062
3063 ast_security_event_report(AST_SEC_EVT(&inval_acct_id)((struct ast_security_event_common *) &inval_acct_id));
3064}
3065
3066static void report_failed_acl(const struct mansession *s, const char *username)
3067{
3068 char session_id[32];
3069 struct ast_security_event_failed_acl failed_acl_event = {
3070 .common.event_type = AST_SECURITY_EVENT_FAILED_ACL,
3071 .common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION1,
3072 .common.service = "AMI",
3073 .common.account_id = username,
3074 .common.session_tv = &s->session->sessionstart_tv,
3075 .common.local_addr = {
3076 .addr = &s->tcptls_session->parent->local_address,
3077 .transport = mansession_get_transport(s),
3078 },
3079 .common.remote_addr = {
3080 .addr = &s->session->addr,
3081 .transport = mansession_get_transport(s),
3082 },
3083 .common.session_id = session_id,
3084 };
3085
3086 snprintf(session_id, sizeof(session_id), "%p", s->session);
3087
3088 ast_security_event_report(AST_SEC_EVT(&failed_acl_event)((struct ast_security_event_common *) &failed_acl_event));
3089}
3090
3091static void report_inval_password(const struct mansession *s, const char *username)
3092{
3093 char session_id[32];
3094 struct ast_security_event_inval_password inval_password = {
3095 .common.event_type = AST_SECURITY_EVENT_INVAL_PASSWORD,
3096 .common.version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION2,
3097 .common.service = "AMI",
3098 .common.account_id = username,
3099 .common.session_tv = &s->session->sessionstart_tv,
3100 .common.local_addr = {
3101 .addr = &s->tcptls_session->parent->local_address,
3102 .transport = mansession_get_transport(s),
3103 },
3104 .common.remote_addr = {
3105 .addr = &s->session->addr,
3106 .transport = mansession_get_transport(s),
3107 },
3108 .common.session_id = session_id,
3109 };
3110
3111 snprintf(session_id, sizeof(session_id), "%p", s->session);
3112
3113 ast_security_event_report(AST_SEC_EVT(&inval_password)((struct ast_security_event_common *) &inval_password));
3114}
3115
3116static void report_auth_success(const struct mansession *s)
3117{
3118 char session_id[32];
3119 struct ast_security_event_successful_auth successful_auth = {
3120 .common.event_type = AST_SECURITY_EVENT_SUCCESSFUL_AUTH,
3121 .common.version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION1,
3122 .common.service = "AMI",
3123 .common.account_id = s->session->username,
3124 .common.session_tv = &s->session->sessionstart_tv,
3125 .common.local_addr = {
3126 .addr = &s->tcptls_session->parent->local_address,
3127 .transport = mansession_get_transport(s),
3128 },
3129 .common.remote_addr = {
3130 .addr = &s->session->addr,
3131 .transport = mansession_get_transport(s),
3132 },
3133 .common.session_id = session_id,
3134 };
3135
3136 snprintf(session_id, sizeof(session_id), "%p", s->session);
3137
3138 ast_security_event_report(AST_SEC_EVT(&successful_auth)((struct ast_security_event_common *) &successful_auth));
3139}
3140
3141static void report_req_not_allowed(const struct mansession *s, const char *action)
3142{
3143 char session_id[32];
3144 char request_type[64];
3145 struct ast_security_event_req_not_allowed req_not_allowed = {
3146 .common.event_type = AST_SECURITY_EVENT_REQ_NOT_ALLOWED,
3147 .common.version = AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION1,
3148 .common.service = "AMI",
3149 .common.account_id = s->session->username,
3150 .common.session_tv = &s->session->sessionstart_tv,
3151 .common.local_addr = {
3152 .addr = &s->tcptls_session->parent->local_address,
3153 .transport = mansession_get_transport(s),
3154 },
3155 .common.remote_addr = {
3156 .addr = &s->session->addr,
3157 .transport = mansession_get_transport(s),
3158 },
3159 .common.session_id = session_id,
3160
3161 .request_type = request_type,
3162 };
3163
3164 snprintf(session_id, sizeof(session_id), "%p", s->session);
3165 snprintf(request_type, sizeof(request_type), "Action: %s", action);
3166
3167 ast_security_event_report(AST_SEC_EVT(&req_not_allowed)((struct ast_security_event_common *) &req_not_allowed));
3168}
3169
3170static void report_req_bad_format(const struct mansession *s, const char *action)
3171{
3172 char session_id[32];
3173 char request_type[64];
3174 struct ast_security_event_req_bad_format req_bad_format = {
3175 .common.event_type = AST_SECURITY_EVENT_REQ_BAD_FORMAT,
3176 .common.version = AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION1,
3177 .common.service = "AMI",
3178 .common.account_id = s->session->username,
3179 .common.session_tv = &s->session->sessionstart_tv,
3180 .common.local_addr = {
3181 .addr = &s->tcptls_session->parent->local_address,
3182 .transport = mansession_get_transport(s),
3183 },
3184 .common.remote_addr = {
3185 .addr = &s->session->addr,
3186 .transport = mansession_get_transport(s),
3187 },
3188 .common.session_id = session_id,
3189
3190 .request_type = request_type,
3191 };
3192
3193 snprintf(session_id, sizeof(session_id), "%p", s->session);
3194 snprintf(request_type, sizeof(request_type), "Action: %s", action);
3195
3196 ast_security_event_report(AST_SEC_EVT(&req_bad_format)((struct ast_security_event_common *) &req_bad_format));
3197}
3198
3199static void report_failed_challenge_response(const struct mansession *s,
3200 const char *response, const char *expected_response)
3201{
3202 char session_id[32];
3203 struct ast_security_event_chal_resp_failed chal_resp_failed = {
3204 .common.event_type = AST_SECURITY_EVENT_CHAL_RESP_FAILED,
3205 .common.version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION1,
3206 .common.service = "AMI",
3207 .common.account_id = s->session->username,
3208 .common.session_tv = &s->session->sessionstart_tv,
3209 .common.local_addr = {
3210 .addr = &s->tcptls_session->parent->local_address,
3211 .transport = mansession_get_transport(s),
3212 },
3213 .common.remote_addr = {
3214 .addr = &s->session->addr,
3215 .transport = mansession_get_transport(s),
3216 },
3217 .common.session_id = session_id,
3218
3219 .challenge = s->session->challenge,
3220 .response = response,
3221 .expected_response = expected_response,
3222 };
3223
3224 snprintf(session_id, sizeof(session_id), "%p", s->session);
3225
3226 ast_security_event_report(AST_SEC_EVT(&chal_resp_failed)((struct ast_security_event_common *) &chal_resp_failed));
3227}
3228
3229static void report_session_limit(const struct mansession *s)
3230{
3231 char session_id[32];
3232 struct ast_security_event_session_limit session_limit = {
3233 .common.event_type = AST_SECURITY_EVENT_SESSION_LIMIT,
3234 .common.version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION1,
3235 .common.service = "AMI",
3236 .common.account_id = s->session->username,
3237 .common.session_tv = &s->session->sessionstart_tv,
3238 .common.local_addr = {
3239 .addr = &s->tcptls_session->parent->local_address,
3240 .transport = mansession_get_transport(s),
3241 },
3242 .common.remote_addr = {
3243 .addr = &s->session->addr,
3244 .transport = mansession_get_transport(s),
3245 },
3246 .common.session_id = session_id,
3247 };
3248
3249 snprintf(session_id, sizeof(session_id), "%p", s->session);
3250
3251 ast_security_event_report(AST_SEC_EVT(&session_limit)((struct ast_security_event_common *) &session_limit));
3252}
3253
3254/*
3255 * Here we start with action_ handlers for AMI actions,
3256 * and the internal functions used by them.
3257 * Generally, the handlers are called action_foo()
3258 */
3259
3260/* helper function for action_login() */
3261static int authenticate(struct mansession *s, const struct message *m)
3262{
3263 const char *username = astman_get_header(m, "Username");
3264 const char *password = astman_get_header(m, "Secret");
3265 int error = -1;
3266 struct ast_manager_user *user = NULL((void*)0);
3267 regex_t *regex_filter;
3268 struct ao2_iterator filter_iter;
3269
3270 if (ast_strlen_zero(username)_ast_strlen_zero(username, "manager.c", __PRETTY_FUNCTION__, 3270
)
) { /* missing username */
3271 return -1;
3272 }
3273
3274 /* locate user in locked state */
3275 AST_RWLIST_WRLOCK(&users)__ast_rwlock_wrlock("manager.c", 3275, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
3276
3277 if (!(user = get_manager_by_name_locked(username))) {
3278 report_invalid_user(s, username);
3279 ast_log(LOG_NOTICE2, "manager.c", 3279, __PRETTY_FUNCTION__, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3280 } else if (user->acl && (ast_apply_acl(user->acl, &s->session->addr, "Manager User ACL: ") == AST_SENSE_DENY)) {
3281 report_failed_acl(s, username);
3282 ast_log(LOG_NOTICE2, "manager.c", 3282, __PRETTY_FUNCTION__, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3283 } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
3284 const char *key = astman_get_header(m, "Key");
3285 if (!ast_strlen_zero(key)_ast_strlen_zero(key, "manager.c", __PRETTY_FUNCTION__, 3285) && !ast_strlen_zero(s->session->challenge)_ast_strlen_zero(s->session->challenge, "manager.c", __PRETTY_FUNCTION__
, 3285)
&& user->secret) {
3286 int x;
3287 int len = 0;
3288 char md5key[256] = "";
3289 struct MD5Context md5;
3290 unsigned char digest[16];
3291
3292 MD5Init(&md5);
3293 MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
3294 MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
3295 MD5Final(digest, &md5);
3296 for (x = 0; x < 16; x++)
3297 len += sprintf(md5key + len, "%02hhx", digest[x]);
3298 if (!strcmp(md5key, key)) {
3299 error = 0;
3300 } else {
3301 report_failed_challenge_response(s, key, md5key);
3302 }
3303 } else {
3304 ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 3305, __PRETTY_FUNCTION__, "MD5 authentication is not possible. challenge: '%s'\n"
, ({typeof(&((s->session->challenge)[0])) __x = (s->
session->challenge); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__
, 3305) ? ("") : __x;})); } } while (0)
3305 S_OR(s->session->challenge, ""))do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 3305, __PRETTY_FUNCTION__, "MD5 authentication is not possible. challenge: '%s'\n"
, ({typeof(&((s->session->challenge)[0])) __x = (s->
session->challenge); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__
, 3305) ? ("") : __x;})); } } while (0)
;
3306 }
3307 } else if (user->secret) {
3308 if (!strcmp(password, user->secret)) {
3309 error = 0;
3310 } else {
3311 report_inval_password(s, username);
3312 }
3313 }
3314
3315 if (error) {
3316 ast_log(LOG_NOTICE2, "manager.c", 3316, __PRETTY_FUNCTION__, "%s failed to authenticate as '%s'\n", ast_sockaddr_stringify_addr(&s->session->addr), username);
3317 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 3317, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
3318 return -1;
3319 }
3320
3321 /* auth complete */
3322
3323 /* All of the user parameters are copied to the session so that in the event
3324 * of a reload and a configuration change, the session parameters are not
3325 * changed. */
3326 ast_copy_string(s->session->username, username, sizeof(s->session->username));
3327 s->session->readperm = user->readperm;
3328 s->session->writeperm = user->writeperm;
3329 s->session->writetimeout = user->writetimeout;
3330 if (user->chanvars) {
3331 s->session->chanvars = ast_variables_dup(user->chanvars);
3332 }
3333
3334 filter_iter = ao2_iterator_init(user->whitefilters, 0);
3335 while ((regex_filter = ao2_iterator_next(&filter_iter)__ao2_iterator_next((&filter_iter), "", "manager.c", 3335
, __PRETTY_FUNCTION__)
)) {
3336 ao2_t_link(s->session->whitefilters, regex_filter, "add white user filter to session")__ao2_link((s->session->whitefilters), (regex_filter), 0
, ("add white user filter to session"), "manager.c", 3336, __PRETTY_FUNCTION__
)
;
3337 ao2_t_ref(regex_filter, -1, "remove iterator ref")__ao2_ref((regex_filter), (-1), ("remove iterator ref"), "manager.c"
, 3337, __PRETTY_FUNCTION__)
;
3338 }
3339 ao2_iterator_destroy(&filter_iter);
3340
3341 filter_iter = ao2_iterator_init(user->blackfilters, 0);
3342 while ((regex_filter = ao2_iterator_next(&filter_iter)__ao2_iterator_next((&filter_iter), "", "manager.c", 3342
, __PRETTY_FUNCTION__)
)) {
3343 ao2_t_link(s->session->blackfilters, regex_filter, "add black user filter to session")__ao2_link((s->session->blackfilters), (regex_filter), 0
, ("add black user filter to session"), "manager.c", 3343, __PRETTY_FUNCTION__
)
;
3344 ao2_t_ref(regex_filter, -1, "remove iterator ref")__ao2_ref((regex_filter), (-1), ("remove iterator ref"), "manager.c"
, 3344, __PRETTY_FUNCTION__)
;
3345 }
3346 ao2_iterator_destroy(&filter_iter);
3347
3348 s->session->sessionstart = time(NULL((void*)0));
3349 s->session->sessionstart_tv = ast_tvnow();
3350 set_eventmask(s, astman_get_header(m, "Events"));
3351
3352 report_auth_success(s);
3353
3354 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 3354, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
3355 return 0;
3356}
3357
3358static int action_ping(struct mansession *s, const struct message *m)
3359{
3360 const char *actionid = astman_get_header(m, "ActionID");
3361 struct timeval now = ast_tvnow();
3362
3363 astman_append(s, "Response: Success\r\n");
3364 if (!ast_strlen_zero(actionid)_ast_strlen_zero(actionid, "manager.c", __PRETTY_FUNCTION__, 3364
)
){
3365 astman_append(s, "ActionID: %s\r\n", actionid);
3366 }
3367 astman_append(
3368 s,
3369 "Ping: Pong\r\n"
3370 "Timestamp: %ld.%06lu\r\n"
3371 "\r\n",
3372 (long) now.tv_sec, (unsigned long) now.tv_usec);
3373 return 0;
3374}
3375
3376static int action_getconfig(struct mansession *s, const struct message *m)
3377{
3378 struct ast_config *cfg;
3379 const char *fn = astman_get_header(m, "Filename");
3380 const char *category = astman_get_header(m, "Category");
3381 const char *filter = astman_get_header(m, "Filter");
3382 const char *category_name;
3383 int catcount = 0;
3384 int lineno = 0;
3385 struct ast_category *cur_category = NULL((void*)0);
3386 struct ast_variable *v;
3387 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3388
3389 if (ast_strlen_zero(fn)_ast_strlen_zero(fn, "manager.c", __PRETTY_FUNCTION__, 3389)) {
3390 astman_send_error(s, m, "Filename not specified");
3391 return 0;
3392 }
3393
3394 cfg = ast_config_load2(fn, "manager", config_flags);
3395 if (cfg == CONFIG_STATUS_FILEMISSING(void *)0) {
3396 astman_send_error(s, m, "Config file not found");
3397 return 0;
3398 } else if (cfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
3399 astman_send_error(s, m, "Config file has invalid format");
3400 return 0;
3401 }
3402
3403 astman_start_ack(s, m);
3404 while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
3405 struct ast_str *templates;
3406
3407 category_name = ast_category_get_name(cur_category);
3408 lineno = 0;
3409 astman_append(s, "Category-%06d: %s\r\n", catcount, category_name);
3410
3411 if (ast_category_is_template(cur_category)) {
3412 astman_append(s, "IsTemplate-%06d: %d\r\n", catcount, 1);
3413 }
3414
3415 if ((templates = ast_category_get_templates(cur_category))
3416 && ast_str_strlen(templates) > 0) {
3417 astman_append(s, "Templates-%06d: %s\r\n", catcount, ast_str_buffer(templates));
3418 ast_freefree(templates);
3419 }
3420
3421 for (v = ast_category_first(cur_category); v; v = v->next) {
3422 astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
3423 }
3424
3425 catcount++;
3426 }
3427
3428 if (!ast_strlen_zero(category)_ast_strlen_zero(category, "manager.c", __PRETTY_FUNCTION__, 3428
)
&& catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
3429 astman_append(s, "No categories found\r\n");
3430 }
3431
3432 ast_config_destroy(cfg);
3433 astman_append(s, "\r\n");
3434
3435 return 0;
3436}
3437
3438static int action_listcategories(struct mansession *s, const struct message *m)
3439{
3440 struct ast_config *cfg;
3441 const char *fn = astman_get_header(m, "Filename");
3442 const char *match = astman_get_header(m, "Match");
3443 struct ast_category *category = NULL((void*)0);
3444 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3445 int catcount = 0;
3446
3447 if (ast_strlen_zero(fn)_ast_strlen_zero(fn, "manager.c", __PRETTY_FUNCTION__, 3447)) {
3448 astman_send_error(s, m, "Filename not specified");
3449 return 0;
3450 }
3451
3452 if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
3453 astman_send_error(s, m, "Config file not found");
3454 return 0;
3455 } else if (cfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
3456 astman_send_error(s, m, "Config file has invalid format");
3457 return 0;
3458 }
3459
3460 astman_start_ack(s, m);
3461 while ((category = ast_category_browse_filtered(cfg, NULL((void*)0), category, match))) {
3462 astman_append(s, "Category-%06d: %s\r\n", catcount, ast_category_get_name(category));
3463 catcount++;
3464 }
3465
3466 if (catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
3467 astman_append(s, "Error: no categories found\r\n");
3468 }
3469
3470 ast_config_destroy(cfg);
3471 astman_append(s, "\r\n");
3472
3473 return 0;
3474}
3475
3476/*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
3477static void json_escape(char *out, const char *in)
3478{
3479 for (; *in; in++) {
3480 if (*in == '\\' || *in == '\"') {
3481 *out++ = '\\';
3482 }
3483 *out++ = *in;
3484 }
3485 *out = '\0';
3486}
3487
3488/*!
3489 * \internal
3490 * \brief Append a JSON escaped string to the manager stream.
3491 *
3492 * \param s AMI stream to append a string.
3493 * \param str String to append to the stream after JSON escaping it.
3494 *
3495 * \return Nothing
3496 */
3497static void astman_append_json(struct mansession *s, const char *str)
3498{
3499 char *buf;
3500
3501 buf = ast_alloca(2 * strlen(str) + 1)__builtin_alloca(2 * strlen(str) + 1);
3502 json_escape(buf, str);
3503 astman_append(s, "%s", buf);
3504}
3505
3506static int action_getconfigjson(struct mansession *s, const struct message *m)
3507{
3508 struct ast_config *cfg;
3509 const char *fn = astman_get_header(m, "Filename");
3510 const char *filter = astman_get_header(m, "Filter");
3511 const char *category = astman_get_header(m, "Category");
3512 struct ast_category *cur_category = NULL((void*)0);
3513 const char *category_name;
3514 struct ast_variable *v;
3515 int comma1 = 0;
3516 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3517
3518 if (ast_strlen_zero(fn)_ast_strlen_zero(fn, "manager.c", __PRETTY_FUNCTION__, 3518)) {
3519 astman_send_error(s, m, "Filename not specified");
3520 return 0;
3521 }
3522
3523 if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
3524 astman_send_error(s, m, "Config file not found");
3525 return 0;
3526 } else if (cfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
3527 astman_send_error(s, m, "Config file has invalid format");
3528 return 0;
3529 }
3530
3531 astman_start_ack(s, m);
3532 astman_append(s, "JSON: {");
3533 while ((cur_category = ast_category_browse_filtered(cfg, category, cur_category, filter))) {
3534 int comma2 = 0;
3535 struct ast_str *templates;
3536
3537 category_name = ast_category_get_name(cur_category);
3538 astman_append(s, "%s\"", comma1 ? "," : "");
3539 astman_append_json(s, category_name);
3540 astman_append(s, "\":{");
3541 comma1 = 1;
3542
3543 if (ast_category_is_template(cur_category)) {
3544 astman_append(s, "\"istemplate\":1");
3545 comma2 = 1;
3546 }
3547
3548 if ((templates = ast_category_get_templates(cur_category))
3549 && ast_str_strlen(templates) > 0) {
3550 astman_append(s, "%s", comma2 ? "," : "");
3551 astman_append(s, "\"templates\":\"%s\"", ast_str_buffer(templates));
3552 ast_freefree(templates);
3553 comma2 = 1;
3554 }
3555
3556 for (v = ast_category_first(cur_category); v; v = v->next) {
3557 astman_append(s, "%s\"", comma2 ? "," : "");
3558 astman_append_json(s, v->name);
3559 astman_append(s, "\":\"");
3560 astman_append_json(s, v->value);
3561 astman_append(s, "\"");
3562 comma2 = 1;
3563 }
3564
3565 astman_append(s, "}");
3566 }
3567 astman_append(s, "}\r\n\r\n");
3568
3569 ast_config_destroy(cfg);
3570
3571 return 0;
3572}
3573
3574/*! \brief helper function for action_updateconfig */
3575static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
3576{
3577 int x;
3578 char hdr[40];
3579 const char *action, *cat, *var, *value, *match, *line, *options;
3580 struct ast_variable *v;
3581 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
3582 enum error_type result = 0;
3583
3584 for (x = 0; x < 100000; x++) { /* 100000 = the max number of allowed updates + 1 */
3585 unsigned int object = 0;
3586 char *dupoptions;
3587 int allowdups = 0;
3588 int istemplate = 0;
3589 int ignoreerror = 0;
3590 char *inherit = NULL((void*)0);
3591 char *catfilter = NULL((void*)0);
3592 char *token;
3593 int foundvar = 0;
3594 int foundcat = 0;
3595 struct ast_category *category = NULL((void*)0);
3596
3597 snprintf(hdr, sizeof(hdr), "Action-%06d", x);
3598 action = astman_get_header(m, hdr);
3599 if (ast_strlen_zero(action)_ast_strlen_zero(action, "manager.c", __PRETTY_FUNCTION__, 3599
)
) /* breaks the for loop if no action header */
3600 break; /* this could cause problems if actions come in misnumbered */
3601
3602 snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
3603 cat = astman_get_header(m, hdr);
3604 if (ast_strlen_zero(cat)_ast_strlen_zero(cat, "manager.c", __PRETTY_FUNCTION__, 3604)) { /* every action needs a category */
3605 result = UNSPECIFIED_CATEGORY;
3606 break;
3607 }
3608
3609 snprintf(hdr, sizeof(hdr), "Var-%06d", x);
3610 var = astman_get_header(m, hdr);
3611
3612 snprintf(hdr, sizeof(hdr), "Value-%06d", x);
3613 value = astman_get_header(m, hdr);
3614
3615 if (!ast_strlen_zero(value)_ast_strlen_zero(value, "manager.c", __PRETTY_FUNCTION__, 3615
)
&& *value == '>') {
3616 object = 1;
3617 value++;
3618 }
3619
3620 snprintf(hdr, sizeof(hdr), "Match-%06d", x);
3621 match = astman_get_header(m, hdr);
3622
3623 snprintf(hdr, sizeof(hdr), "Line-%06d", x);
3624 line = astman_get_header(m, hdr);
3625
3626 snprintf(hdr, sizeof(hdr), "Options-%06d", x);
3627 options = astman_get_header(m, hdr);
3628 if (!ast_strlen_zero(options)_ast_strlen_zero(options, "manager.c", __PRETTY_FUNCTION__, 3628
)
) {
3629 dupoptions = ast_strdupa(options)(__extension__ ({ const char *__old = (options); size_t __len
= strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
;
3630 while ((token = ast_strsep(&dupoptions, ',', AST_STRSEP_STRIP))) {
3631 if (!strcasecmp("allowdups", token)) {
3632 allowdups = 1;
3633 continue;
3634 }
3635 if (!strcasecmp("template", token)) {
3636 istemplate = 1;
3637 continue;
3638 }
3639 if (!strcasecmp("ignoreerror", token)) {
3640 ignoreerror = 1;
3641 continue;
3642 }
3643 if (ast_begins_with(token, "inherit")) {
3644 char *c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3645 c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3646 if (c) {
3647 inherit = ast_strdupa(c)(__extension__ ({ const char *__old = (c); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
3648 }
3649 continue;
3650 }
3651 if (ast_begins_with(token, "catfilter")) {
3652 char *c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3653 c = ast_strsep(&token, '=', AST_STRSEP_STRIP);
3654 if (c) {
3655 catfilter = ast_strdupa(c)(__extension__ ({ const char *__old = (c); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
3656 }
3657 continue;
3658 }
3659 }
3660 }
3661
3662 if (!strcasecmp(action, "newcat")) {
3663 struct ast_category *template;
3664 char *tmpl_name = NULL((void*)0);
3665
3666 if (!allowdups) {
3667 if (ast_category_get(cfg, cat, "TEMPLATES=include")) {
3668 if (ignoreerror) {
3669 continue;
3670 } else {
3671 result = FAILURE_NEWCAT; /* already exist */
3672 break;
3673 }
3674 }
3675 }
3676
3677 if (istemplate) {
3678 category = ast_category_new_template(cat, dfn, -1);
3679 } else {
3680 category = ast_category_new(cat, dfn, -1);
3681 }
3682
3683 if (!category) {
3684 result = FAILURE_ALLOCATION;
3685 break;
3686 }
3687
3688 if (inherit) {
3689 while ((tmpl_name = ast_strsep(&inherit, ',', AST_STRSEP_STRIP))) {
3690 if ((template = ast_category_get(cfg, tmpl_name, "TEMPLATES=restrict"))) {
3691 if (ast_category_inherit(category, template)) {
3692 result = FAILURE_ALLOCATION;
3693 break;
3694 }
3695 } else {
3696 ast_category_destroy(category);
3697 category = NULL((void*)0);
3698 result = FAILURE_TEMPLATE; /* template not found */
3699 break;
3700 }
3701 }
3702 }
3703
3704 if (category != NULL((void*)0)) {
3705 if (ast_strlen_zero(match)_ast_strlen_zero(match, "manager.c", __PRETTY_FUNCTION__, 3705
)
) {
3706 ast_category_append(cfg, category);
3707 } else {
3708 if (ast_category_insert(cfg, category, match)) {
3709 ast_category_destroy(category);
3710 result = FAILURE_NEWCAT;
3711 break;
3712 }
3713 }
3714 }
3715 } else if (!strcasecmp(action, "renamecat")) {
3716 if (ast_strlen_zero(value)_ast_strlen_zero(value, "manager.c", __PRETTY_FUNCTION__, 3716
)
) {
3717 result = UNSPECIFIED_ARGUMENT;
3718 break;
3719 }
3720
3721 foundcat = 0;
3722 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3723 ast_category_rename(category, value);
3724 foundcat = 1;
3725 }
3726
3727 if (!foundcat) {
3728 result = UNKNOWN_CATEGORY;
3729 break;
3730 }
3731 } else if (!strcasecmp(action, "delcat")) {
3732 foundcat = 0;
3733 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3734 category = ast_category_delete(cfg, category);
3735 foundcat = 1;
3736 }
3737
3738 if (!foundcat && !ignoreerror) {
3739 result = UNKNOWN_CATEGORY;
3740 break;
3741 }
3742 } else if (!strcasecmp(action, "emptycat")) {
3743 foundcat = 0;
3744 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3745 ast_category_empty(category);
3746 foundcat = 1;
3747 }
3748
3749 if (!foundcat) {
3750 result = UNKNOWN_CATEGORY;
3751 break;
3752 }
3753 } else if (!strcasecmp(action, "update")) {
3754 if (ast_strlen_zero(var)_ast_strlen_zero(var, "manager.c", __PRETTY_FUNCTION__, 3754)) {
3755 result = UNSPECIFIED_ARGUMENT;
3756 break;
3757 }
3758
3759 foundcat = 0;
3760 foundvar = 0;
3761 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3762 if (!ast_variable_update(category, var, value, match, object)) {
3763 foundvar = 1;
3764 }
3765 foundcat = 1;
3766 }
3767
3768 if (!foundcat) {
3769 result = UNKNOWN_CATEGORY;
3770 break;
3771 }
3772
3773 if (!foundvar) {
3774 result = FAILURE_UPDATE;
3775 break;
3776 }
3777 } else if (!strcasecmp(action, "delete")) {
3778 if ((ast_strlen_zero(var)_ast_strlen_zero(var, "manager.c", __PRETTY_FUNCTION__, 3778) && ast_strlen_zero(line)_ast_strlen_zero(line, "manager.c", __PRETTY_FUNCTION__, 3778
)
)) {
3779 result = UNSPECIFIED_ARGUMENT;
3780 break;
3781 }
3782
3783 foundcat = 0;
3784 foundvar = 0;
3785 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3786 if (!ast_variable_delete(category, var, match, line)) {
3787 foundvar = 1;
3788 }
3789 foundcat = 1;
3790 }
3791
3792 if (!foundcat) {
3793 result = UNKNOWN_CATEGORY;
3794 break;
3795 }
3796
3797 if (!foundvar && !ignoreerror) {
3798 result = FAILURE_UPDATE;
3799 break;
3800 }
3801 } else if (!strcasecmp(action, "append")) {
3802 if (ast_strlen_zero(var)_ast_strlen_zero(var, "manager.c", __PRETTY_FUNCTION__, 3802)) {
3803 result = UNSPECIFIED_ARGUMENT;
3804 break;
3805 }
3806
3807 foundcat = 0;
3808 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3809 if (!(v = ast_variable_new(var, value, dfn))) {
3810 result = FAILURE_ALLOCATION;
3811 break;
3812 }
3813 if (object || (match && !strcasecmp(match, "object"))) {
3814 v->object = 1;
3815 }
3816 ast_variable_append(category, v);
3817 foundcat = 1;
3818 }
3819
3820 if (!foundcat) {
3821 result = UNKNOWN_CATEGORY;
3822 break;
3823 }
3824 } else if (!strcasecmp(action, "insert")) {
3825 if (ast_strlen_zero(var)_ast_strlen_zero(var, "manager.c", __PRETTY_FUNCTION__, 3825) || ast_strlen_zero(line)_ast_strlen_zero(line, "manager.c", __PRETTY_FUNCTION__, 3825
)
) {
3826 result = UNSPECIFIED_ARGUMENT;
3827 break;
3828 }
3829
3830 foundcat = 0;
3831 while ((category = ast_category_browse_filtered(cfg, cat, category, catfilter))) {
3832 if (!(v = ast_variable_new(var, value, dfn))) {
3833 result = FAILURE_ALLOCATION;
3834 break;
3835 }
3836 ast_variable_insert(category, v, line);
3837 foundcat = 1;
3838 }
3839
3840 if (!foundcat) {
3841 result = UNKNOWN_CATEGORY;
3842 break;
3843 }
3844 }
3845 else {
3846 ast_log(LOG_WARNING3, "manager.c", 3846, __PRETTY_FUNCTION__, "Action-%06d: %s not handled\n", x, action);
3847 result = UNKNOWN_ACTION;
3848 break;
3849 }
3850 }
3851 ast_freefree(str1);
3852 ast_freefree(str2);
3853 return result;
3854}
3855
3856static int action_updateconfig(struct mansession *s, const struct message *m)
3857{
3858 struct ast_config *cfg;
3859 const char *sfn = astman_get_header(m, "SrcFilename");
3860 const char *dfn = astman_get_header(m, "DstFilename");
3861 int res;
3862 const char *rld = astman_get_header(m, "Reload");
3863 int preserve_effective_context = CONFIG_SAVE_FLAG_PRESERVE_EFFECTIVE_CONTEXT;
3864 const char *preserve_effective_context_string = astman_get_header(m, "PreserveEffectiveContext");
3865 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
3866 enum error_type result;
3867
3868 if (ast_strlen_zero(sfn)_ast_strlen_zero(sfn, "manager.c", __PRETTY_FUNCTION__, 3868) || ast_strlen_zero(dfn)_ast_strlen_zero(dfn, "manager.c", __PRETTY_FUNCTION__, 3868)) {
3869 astman_send_error(s, m, "Filename not specified");
3870 return 0;
3871 }
3872 if (!(cfg = ast_config_load2(sfn, "manager", config_flags))) {
3873 astman_send_error(s, m, "Config file not found");
3874 return 0;
3875 } else if (cfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
3876 astman_send_error(s, m, "Config file has invalid format");
3877 return 0;
3878 }
3879 result = handle_updates(s, m, cfg, dfn);
3880 if (!result) {
3881 ast_include_rename(cfg, sfn, dfn); /* change the include references from dfn to sfn, so things match up */
3882 if (!ast_strlen_zero(preserve_effective_context_string)_ast_strlen_zero(preserve_effective_context_string, "manager.c"
, __PRETTY_FUNCTION__, 3882)
&& !ast_true(preserve_effective_context_string)) {
3883 preserve_effective_context = CONFIG_SAVE_FLAG_NONE;
3884 }
3885 res = ast_config_text_file_save2(dfn, cfg, "Manager", preserve_effective_context);
3886 ast_config_destroy(cfg);
3887 if (res) {
3888 astman_send_error(s, m, "Save of config failed");
3889 return 0;
3890 }
3891 astman_send_ack(s, m, NULL((void*)0));
3892 if (!ast_strlen_zero(rld)_ast_strlen_zero(rld, "manager.c", __PRETTY_FUNCTION__, 3892)) {
3893 if (ast_true(rld)) {
3894 rld = NULL((void*)0);
3895 }
3896 ast_module_reload(rld);
3897 }
3898 } else {
3899 ast_config_destroy(cfg);
3900 switch(result) {
3901 case UNKNOWN_ACTION:
3902 astman_send_error(s, m, "Unknown action command");
3903 break;
3904 case UNKNOWN_CATEGORY:
3905 astman_send_error(s, m, "Given category does not exist");
3906 break;
3907 case UNSPECIFIED_CATEGORY:
3908 astman_send_error(s, m, "Category not specified");
3909 break;
3910 case UNSPECIFIED_ARGUMENT:
3911 astman_send_error(s, m, "Problem with category, value, or line (if required)");
3912 break;
3913 case FAILURE_ALLOCATION:
3914 astman_send_error(s, m, "Memory allocation failure, this should not happen");
3915 break;
3916 case FAILURE_NEWCAT:
3917 astman_send_error(s, m, "Create category did not complete successfully");
3918 break;
3919 case FAILURE_DELCAT:
3920 astman_send_error(s, m, "Delete category did not complete successfully");
3921 break;
3922 case FAILURE_EMPTYCAT:
3923 astman_send_error(s, m, "Empty category did not complete successfully");
3924 break;
3925 case FAILURE_UPDATE:
3926 astman_send_error(s, m, "Update did not complete successfully");
3927 break;
3928 case FAILURE_DELETE:
3929 astman_send_error(s, m, "Delete did not complete successfully");
3930 break;
3931 case FAILURE_APPEND:
3932 astman_send_error(s, m, "Append did not complete successfully");
3933 break;
3934 case FAILURE_TEMPLATE:
3935 astman_send_error(s, m, "Template category not found");
3936 break;
3937 }
3938 }
3939 return 0;
3940}
3941
3942static int action_createconfig(struct mansession *s, const struct message *m)
3943{
3944 int fd;
3945 const char *fn = astman_get_header(m, "Filename");
3946 struct ast_str *filepath = ast_str_alloca(PATH_MAX)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 4096); __ast_str_buf->len = 4096
; __ast_str_buf->used = 0; __ast_str_buf->ts = ((struct
ast_threadstorage *)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf
); })
;
3947 ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
3948 ast_str_append(&filepath, 0, "%s", fn);
3949
3950 if ((fd = open(ast_str_buffer(filepath), O_CREAT0100 | O_EXCL0200, AST_FILE_MODE0666)) != -1) {
3951 close(fd);
3952 astman_send_ack(s, m, "New configuration file created successfully");
3953 } else {
3954 astman_send_error(s, m, strerror(errno(*__errno_location ())));
3955 }
3956
3957 return 0;
3958}
3959
3960static int action_waitevent(struct mansession *s, const struct message *m)
3961{
3962 const char *timeouts = astman_get_header(m, "Timeout");
3963 int timeout = -1;
3964 int x;
3965 int needexit = 0;
3966 const char *id = astman_get_header(m, "ActionID");
3967 char idText[256];
3968
3969 if (!ast_strlen_zero(id)_ast_strlen_zero(id, "manager.c", __PRETTY_FUNCTION__, 3969)) {
3970 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
3971 } else {
3972 idText[0] = '\0';
3973 }
3974
3975 if (!ast_strlen_zero(timeouts)_ast_strlen_zero(timeouts, "manager.c", __PRETTY_FUNCTION__, 3975
)
) {
3976 sscanf(timeouts, "%30i", &timeout);
3977 if (timeout < -1) {
3978 timeout = -1;
3979 }
3980 /* XXX maybe put an upper bound, or prevent the use of 0 ? */
3981 }
3982
3983 ao2_lock(s->session)__ao2_lock(s->session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 3983, "s->session")
;
3984 if (s->session->waiting_thread != AST_PTHREADT_NULL(pthread_t) -1) {
3985 pthread_kill(s->session->waiting_thread, SIGURG23);
3986 }
3987
3988 if (s->session->managerid) { /* AMI-over-HTTP session */
3989 /*
3990 * Make sure the timeout is within the expire time of the session,
3991 * as the client will likely abort the request if it does not see
3992 * data coming after some amount of time.
3993 */
3994 time_t now = time(NULL((void*)0));
3995 int max = s->session->sessiontimeout - now - 10;
3996
3997 if (max < 0) { /* We are already late. Strange but possible. */
3998 max = 0;
3999 }
4000 if (timeout < 0 || timeout > max) {
4001 timeout = max;
4002 }
4003 if (!s->session->send_events) { /* make sure we record events */
4004 s->session->send_events = -1;
4005 }
4006 }
4007 ao2_unlock(s->session)__ao2_unlock(s->session, "manager.c", __PRETTY_FUNCTION__,
4007, "s->session")
;
4008
4009 /* XXX should this go inside the lock ? */
4010 s->session->waiting_thread = pthread_self(); /* let new events wake up this thread */
4011 ast_debug(1, "Starting waiting for an event!\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 4011, __PRETTY_FUNCTION__, "Starting waiting for an event!\n"
); } } while (0)
;
4012
4013 for (x = 0; x < timeout || timeout < 0; x++) {
4014 ao2_lock(s->session)__ao2_lock(s->session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 4014, "s->session")
;
4015 if (AST_RWLIST_NEXT(s->session->last_ev, eq_next)((s->session->last_ev)->eq_next.next)) {
4016 needexit = 1;
4017 }
4018 /* We can have multiple HTTP session point to the same mansession entry.
4019 * The way we deal with it is not very nice: newcomers kick out the previous
4020 * HTTP session. XXX this needs to be improved.
4021 */
4022 if (s->session->waiting_thread != pthread_self()) {
4023 needexit = 1;
4024 }
4025 if (s->session->needdestroy) {
4026 needexit = 1;
4027 }
4028 ao2_unlock(s->session)__ao2_unlock(s->session, "manager.c", __PRETTY_FUNCTION__,
4028, "s->session")
;
4029 if (needexit) {
4030 break;
4031 }
4032 if (s->session->managerid == 0) { /* AMI session */
4033 if (ast_wait_for_input(s->session->fd, 1000)) {
4034 break;
4035 }
4036 } else { /* HTTP session */
4037 sleep(1);
4038 }
4039 }
4040 ast_debug(1, "Finished waiting for an event!\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 4040, __PRETTY_FUNCTION__, "Finished waiting for an event!\n"
); } } while (0)
;
4041
4042 ao2_lock(s->session)__ao2_lock(s->session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 4042, "s->session")
;
4043 if (s->session->waiting_thread == pthread_self()) {
4044 struct eventqent *eqe = s->session->last_ev;
4045 astman_send_response(s, m, "Success", "Waiting for Event completed.");
4046 while ((eqe = advance_event(eqe))) {
4047 if (((s->session->readperm & eqe->category) == eqe->category)
4048 && ((s->session->send_events & eqe->category) == eqe->category)
4049 && match_filter(s, eqe->eventdata)) {
4050 astman_append(s, "%s", eqe->eventdata);
4051 }
4052 s->session->last_ev = eqe;
4053 }
4054 astman_append(s,
4055 "Event: WaitEventComplete\r\n"
4056 "%s"
4057 "\r\n", idText);
4058 s->session->waiting_thread = AST_PTHREADT_NULL(pthread_t) -1;
4059 } else {
4060 ast_debug(1, "Abandoning event request!\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 4060, __PRETTY_FUNCTION__, "Abandoning event request!\n"
); } } while (0)
;
4061 }
4062 ao2_unlock(s->session)__ao2_unlock(s->session, "manager.c", __PRETTY_FUNCTION__,
4062, "s->session")
;
4063
4064 return 0;
4065}
4066
4067static int action_listcommands(struct mansession *s, const struct message *m)
4068{
4069 struct manager_action *cur;
4070 struct ast_str *temp = ast_str_alloca(MAX_AUTH_PERM_STRING)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 150); __ast_str_buf->len = 150; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
4071
4072 astman_start_ack(s, m);
4073 AST_RWLIST_RDLOCK(&actions)__ast_rwlock_rdlock("manager.c", 4073, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
4074 AST_RWLIST_TRAVERSE(&actions, cur, list)for((cur) = (&actions)->first; (cur); (cur) = (cur)->
list.next)
{
4075 if ((s->session->writeperm & cur->authority) || cur->authority == 0) {
4076 astman_append(s, "%s: %s (Priv: %s)\r\n",
4077 cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
4078 }
4079 }
4080 AST_RWLIST_UNLOCK(&actions)__ast_rwlock_unlock("manager.c", 4080, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
4081 astman_append(s, "\r\n");
4082
4083 return 0;
4084}
4085
4086static int action_events(struct mansession *s, const struct message *m)
4087{
4088 const char *mask = astman_get_header(m, "EventMask");
4089 int res, x;
4090 const char *id = astman_get_header(m, "ActionID");
4091 char id_text[256];
4092
4093 if (!ast_strlen_zero(id)_ast_strlen_zero(id, "manager.c", __PRETTY_FUNCTION__, 4093)) {
4094 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
4095 } else {
4096 id_text[0] = '\0';
4097 }
4098
4099 res = set_eventmask(s, mask);
4100 if (broken_events_action) {
4101 /* if this option is set we should not return a response on
4102 * error, or when all events are set */
4103
4104 if (res > 0) {
4105 for (x = 0; x < ARRAY_LEN(perms)(size_t) (sizeof(perms) / sizeof(0[perms])); x++) {
4106 if (!strcasecmp(perms[x].label, "all") && res == perms[x].num) {
4107 return 0;
4108 }
4109 }
4110 astman_append(s, "Response: Success\r\n%s"
4111 "Events: On\r\n\r\n", id_text);
4112 } else if (res == 0)
4113 astman_append(s, "Response: Success\r\n%s"
4114 "Events: Off\r\n\r\n", id_text);
4115 return 0;
4116 }
4117
4118 if (res > 0)
4119 astman_append(s, "Response: Success\r\n%s"
4120 "Events: On\r\n\r\n", id_text);
4121 else if (res == 0)
4122 astman_append(s, "Response: Success\r\n%s"
4123 "Events: Off\r\n\r\n", id_text);
4124 else
4125 astman_send_error(s, m, "Invalid event mask");
4126
4127 return 0;
4128}
4129
4130static int action_logoff(struct mansession *s, const struct message *m)
4131{
4132 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
4133 return -1;
4134}
4135
4136static int action_login(struct mansession *s, const struct message *m)
4137{
4138
4139 /* still authenticated - don't process again */
4140 if (s->session->authenticated) {
4141 astman_send_ack(s, m, "Already authenticated");
4142 return 0;
4143 }
4144
4145 if (authenticate(s, m)) {
4146 sleep(1);
4147 astman_send_error(s, m, "Authentication failed");
4148 return -1;
4149 }
4150 s->session->authenticated = 1;
4151 ast_atomic_fetchadd_int(&unauth_sessions, -1);
4152 if (manager_displayconnects(s->session)) {
4153 ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_sockaddr_stringify_addr(&s->session->addr))do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 4153, __PRETTY_FUNCTION__, 2, "%sManager '%s' logged on from %s\n"
, (s->session->managerid ? "HTTP " : ""), s->session
->username, ast_sockaddr_stringify_addr(&s->session
->addr)); } } while (0)
;
4154 }
4155 astman_send_ack(s, m, "Authentication accepted");
4156 if ((s->session->send_events & EVENT_FLAG_SYSTEM(1 << 0))
4157 && (s->session->readperm & EVENT_FLAG_SYSTEM(1 << 0))
4158 && ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)({ typeof ((&ast_options)->flags) __p = (&ast_options
)->flags; typeof (__unsigned_int_flags_dummy) __x = 0; (void
) (&__p == &__x); ((&ast_options)->flags &
(AST_OPT_FLAG_FULLY_BOOTED)); })
) {
4159 struct ast_str *auth = ast_str_alloca(MAX_AUTH_PERM_STRING)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 150); __ast_str_buf->len = 150; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
4160 const char *cat_str = authority_to_str(EVENT_FLAG_SYSTEM(1 << 0), &auth);
4161 long uptime = 0;
4162 long lastreloaded = 0;
4163 struct timeval tmp;
4164 struct timeval curtime = ast_tvnow();
4165
4166 if (ast_startuptime.tv_sec) {
4167 tmp = ast_tvsub(curtime, ast_startuptime);
4168 uptime = tmp.tv_sec;
4169 }
4170
4171 if (ast_lastreloadtime.tv_sec) {
4172 tmp = ast_tvsub(curtime, ast_lastreloadtime);
4173 lastreloaded = tmp.tv_sec;
4174 }
4175
4176 astman_append(s, "Event: FullyBooted\r\n"
4177 "Privilege: %s\r\n"
4178 "Uptime: %ld\r\n"
4179 "LastReload: %ld\r\n"
4180 "Status: Fully Booted\r\n\r\n", cat_str, uptime, lastreloaded);
4181 }
4182 return 0;
4183}
4184
4185static int action_challenge(struct mansession *s, const struct message *m)
4186{
4187 const char *authtype = astman_get_header(m, "AuthType");
4188
4189 if (!strcasecmp(authtype, "MD5")) {
4190 if (ast_strlen_zero(s->session->challenge)_ast_strlen_zero(s->session->challenge, "manager.c", __PRETTY_FUNCTION__
, 4190)
) {
4191 snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
4192 }
4193 mansession_lock(s);
4194 astman_start_ack(s, m);
4195 astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
4196 mansession_unlock(s);
4197 } else {
4198 astman_send_error(s, m, "Must specify AuthType");
4199 }
4200 return 0;
4201}
4202
4203static int action_hangup(struct mansession *s, const struct message *m)
4204{
4205 struct ast_channel *c = NULL((void*)0);
4206 int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
4207 const char *id = astman_get_header(m, "ActionID");
4208 const char *name_or_regex = astman_get_header(m, "Channel");
4209 const char *cause = astman_get_header(m, "Cause");
4210 char idText[256];
4211 regex_t regexbuf;
4212 struct ast_channel_iterator *iter = NULL((void*)0);
4213 struct ast_str *regex_string;
4214 int channels_matched = 0;
4215
4216 if (ast_strlen_zero(name_or_regex)_ast_strlen_zero(name_or_regex, "manager.c", __PRETTY_FUNCTION__
, 4216)
) {
4217 astman_send_error(s, m, "No channel specified");
4218 return 0;
4219 }
4220
4221 if (!ast_strlen_zero(id)_ast_strlen_zero(id, "manager.c", __PRETTY_FUNCTION__, 4221)) {
4222 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
4223 } else {
4224 idText[0] = '\0';
4225 }
4226
4227 if (!ast_strlen_zero(cause)_ast_strlen_zero(cause, "manager.c", __PRETTY_FUNCTION__, 4227
)
) {
4228 char *endptr;
4229 causecode = strtol(cause, &endptr, 10);
4230 if (causecode < 0 || causecode > 127 || *endptr != '\0') {
4231 ast_log(LOG_NOTICE2, "manager.c", 4231, __PRETTY_FUNCTION__, "Invalid 'Cause: %s' in manager action Hangup\n", cause);
4232 /* keep going, better to hangup without cause than to not hang up at all */
4233 causecode = 0; /* do not set channel's hangupcause */
4234 }
4235 }
4236
4237 /************************************************/
4238 /* Regular explicit match channel byname hangup */
4239
4240 if (name_or_regex[0] != '/') {
4241 if (!(c = ast_channel_get_by_name(name_or_regex))) {
4242 ast_log(LOG_NOTICE2, "manager.c", 4242, __PRETTY_FUNCTION__, "Request to hangup non-existent channel: %s\n",
4243 name_or_regex);
4244 astman_send_error(s, m, "No such channel");
4245 return 0;
4246 }
4247
4248 ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 4252, __PRETTY_FUNCTION__, 3, "%sManager '%s' from %s, hanging up channel: %s\n"
, (s->session->managerid ? "HTTP " : ""), s->session
->username, ast_sockaddr_stringify_addr(&s->session
->addr), ast_channel_name(c)); } } while (0)
4249 (s->session->managerid ? "HTTP " : ""),do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 4252, __PRETTY_FUNCTION__, 3, "%sManager '%s' from %s, hanging up channel: %s\n"
, (s->session->managerid ? "HTTP " : ""), s->session
->username, ast_sockaddr_stringify_addr(&s->session
->addr), ast_channel_name(c)); } } while (0)
4250 s->session->username,do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 4252, __PRETTY_FUNCTION__, 3, "%sManager '%s' from %s, hanging up channel: %s\n"
, (s->session->managerid ? "HTTP " : ""), s->session
->username, ast_sockaddr_stringify_addr(&s->session
->addr), ast_channel_name(c)); } } while (0)
4251 ast_sockaddr_stringify_addr(&s->session->addr),do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 4252, __PRETTY_FUNCTION__, 3, "%sManager '%s' from %s, hanging up channel: %s\n"
, (s->session->managerid ? "HTTP " : ""), s->session
->username, ast_sockaddr_stringify_addr(&s->session
->addr), ast_channel_name(c)); } } while (0)
4252 ast_channel_name(c))do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 4252, __PRETTY_FUNCTION__, 3, "%sManager '%s' from %s, hanging up channel: %s\n"
, (s->session->managerid ? "HTTP " : ""), s->session
->username, ast_sockaddr_stringify_addr(&s->session
->addr), ast_channel_name(c)); } } while (0)
;
4253
4254 ast_channel_softhangup_withcause_locked(c, causecode);
4255 c = ast_channel_unref(c)({ __ao2_ref((c), (-1), "", "manager.c", 4255, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4256
4257 astman_send_ack(s, m, "Channel Hungup");
4258
4259 return 0;
4260 }
4261
4262 /***********************************************/
4263 /* find and hangup any channels matching regex */
4264
4265 regex_string = ast_str_create(strlen(name_or_regex));
4266 if (!regex_string) {
4267 astman_send_error(s, m, "Memory Allocation Failure");
4268 return 0;
4269 }
4270
4271 /* Make "/regex/" into "regex" */
4272 if (ast_regex_string_to_regex_pattern(name_or_regex, &regex_string) != 0) {
4273 astman_send_error(s, m, "Regex format invalid, Channel param should be /regex/");
4274 ast_freefree(regex_string);
4275 return 0;
4276 }
4277
4278 /* if regex compilation fails, hangup fails */
4279 if (regcomp(&regexbuf, ast_str_buffer(regex_string), REG_EXTENDED1 | REG_NOSUB(((1 << 1) << 1) << 1))) {
4280 astman_send_error_va(s, m, "Regex compile failed on: %s", name_or_regex);
4281 ast_freefree(regex_string);
4282 return 0;
4283 }
4284
4285 astman_send_listack(s, m, "Channels hung up will follow", "start");
4286
4287 iter = ast_channel_iterator_all_new();
4288 if (iter) {
4289 for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)({ __ao2_ref((c), (-1), "", "manager.c", 4289, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
) {
4290 if (regexec(&regexbuf, ast_channel_name(c), 0, NULL((void*)0), 0)) {
4291 continue;
4292 }
4293
4294 ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 4298, __PRETTY_FUNCTION__, 3, "%sManager '%s' from %s, hanging up channel: %s\n"
, (s->session->managerid ? "HTTP " : ""), s->session
->username, ast_sockaddr_stringify_addr(&s->session
->addr), ast_channel_name(c)); } } while (0)
4295 (s->session->managerid ? "HTTP " : ""),do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 4298, __PRETTY_FUNCTION__, 3, "%sManager '%s' from %s, hanging up channel: %s\n"
, (s->session->managerid ? "HTTP " : ""), s->session
->username, ast_sockaddr_stringify_addr(&s->session
->addr), ast_channel_name(c)); } } while (0)
4296 s->session->username,do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 4298, __PRETTY_FUNCTION__, 3, "%sManager '%s' from %s, hanging up channel: %s\n"
, (s->session->managerid ? "HTTP " : ""), s->session
->username, ast_sockaddr_stringify_addr(&s->session
->addr), ast_channel_name(c)); } } while (0)
4297 ast_sockaddr_stringify_addr(&s->session->addr),do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 4298, __PRETTY_FUNCTION__, 3, "%sManager '%s' from %s, hanging up channel: %s\n"
, (s->session->managerid ? "HTTP " : ""), s->session
->username, ast_sockaddr_stringify_addr(&s->session
->addr), ast_channel_name(c)); } } while (0)
4298 ast_channel_name(c))do { if (((3) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 4298, __PRETTY_FUNCTION__, 3, "%sManager '%s' from %s, hanging up channel: %s\n"
, (s->session->managerid ? "HTTP " : ""), s->session
->username, ast_sockaddr_stringify_addr(&s->session
->addr), ast_channel_name(c)); } } while (0)
;
4299
4300 ast_channel_softhangup_withcause_locked(c, causecode);
4301 channels_matched++;
4302
4303 astman_append(s,
4304 "Event: ChannelHungup\r\n"
4305 "Channel: %s\r\n"
4306 "%s"
4307 "\r\n", ast_channel_name(c), idText);
4308 }
4309 ast_channel_iterator_destroy(iter);
4310 }
4311
4312 regfree(&regexbuf);
4313 ast_freefree(regex_string);
4314
4315 astman_send_list_complete_start(s, m, "ChannelsHungupListComplete", channels_matched);
4316 astman_send_list_complete_end(s);
4317
4318 return 0;
4319}
4320
4321static int action_setvar(struct mansession *s, const struct message *m)
4322{
4323 struct ast_channel *c = NULL((void*)0);
4324 const char *name = astman_get_header(m, "Channel");
4325 const char *varname = astman_get_header(m, "Variable");
4326 const char *varval = astman_get_header(m, "Value");
4327 int res = 0;
4328
4329 if (ast_strlen_zero(varname)_ast_strlen_zero(varname, "manager.c", __PRETTY_FUNCTION__, 4329
)
) {
4330 astman_send_error(s, m, "No variable specified");
4331 return 0;
4332 }
4333
4334 if (!ast_strlen_zero(name)_ast_strlen_zero(name, "manager.c", __PRETTY_FUNCTION__, 4334
)
) {
4335 if (!(c = ast_channel_get_by_name(name))) {
4336 astman_send_error(s, m, "No such channel");
4337 return 0;
4338 }
4339 }
4340
4341 res = pbx_builtin_setvar_helper(c, varname, S_OR(varval, "")({typeof(&((varval)[0])) __x = (varval); _ast_strlen_zero
(__x, "manager.c", __PRETTY_FUNCTION__, 4341) ? ("") : __x;})
);
4342
4343 if (c) {
4344 c = ast_channel_unref(c)({ __ao2_ref((c), (-1), "", "manager.c", 4344, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4345 }
4346 if (res == 0) {
4347 astman_send_ack(s, m, "Variable Set");
4348 } else {
4349 astman_send_error(s, m, "Variable not set");
4350 }
4351 return 0;
4352}
4353
4354static int action_getvar(struct mansession *s, const struct message *m)
4355{
4356 struct ast_channel *c = NULL((void*)0);
4357 const char *name = astman_get_header(m, "Channel");
4358 const char *varname = astman_get_header(m, "Variable");
4359 char *varval;
4360 char workspace[1024];
4361
4362 if (ast_strlen_zero(varname)_ast_strlen_zero(varname, "manager.c", __PRETTY_FUNCTION__, 4362
)
) {
4363 astman_send_error(s, m, "No variable specified");
4364 return 0;
4365 }
4366
4367 /* We don't want users with insufficient permissions using certain functions. */
4368 if (!(function_capable_string_allowed_with_auths(varname, s->session->writeperm))) {
4369 astman_send_error(s, m, "GetVar Access Forbidden: Variable");
4370 return 0;
4371 }
4372
4373 if (!ast_strlen_zero(name)_ast_strlen_zero(name, "manager.c", __PRETTY_FUNCTION__, 4373
)
) {
4374 if (!(c = ast_channel_get_by_name(name))) {
4375 astman_send_error(s, m, "No such channel");
4376 return 0;
4377 }
4378 }
4379
4380 workspace[0] = '\0';
4381 if (varname[strlen(varname) - 1] == ')') {
4382 if (!c) {
4383 c = ast_dummy_channel_alloc()__ast_dummy_channel_alloc("manager.c", 4383, __PRETTY_FUNCTION__
)
;
4384 if (c) {
4385 ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
4386 } else
4387 ast_log(LOG_ERROR4, "manager.c", 4387, __PRETTY_FUNCTION__, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
4388 } else {
4389 ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
4390 }
4391 varval = workspace;
4392 } else {
4393 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL((void*)0));
4394 }
4395
4396 if (c) {
4397 c = ast_channel_unref(c)({ __ao2_ref((c), (-1), "", "manager.c", 4397, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4398 }
4399
4400 astman_start_ack(s, m);
4401 astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, S_OR(varval, "")({typeof(&((varval)[0])) __x = (varval); _ast_strlen_zero
(__x, "manager.c", __PRETTY_FUNCTION__, 4401) ? ("") : __x;})
);
4402
4403 return 0;
4404}
4405
4406static void generate_status(struct mansession *s, struct ast_channel *chan, char **vars, int varc, int all_variables, char *id_text, int *count)
4407{
4408 struct timeval now;
4409 long elapsed_seconds;
4410 struct ast_bridge *bridge;
4411 RAII_VAR(struct ast_str *, variable_str, NULL, ast_free)_raii_cleanup_block_t _raii_cleanup_variable_str __attribute__
((cleanup(_raii_cleanup_block),unused)) = ((void*)0); __attribute__
((__blocks__(byref))) struct ast_str * variable_str = ((void*
)0); _raii_cleanup_variable_str = ^{ {(void)free(variable_str
);} }
;
4412 struct ast_str *write_transpath = ast_str_alloca(256)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 256); __ast_str_buf->len = 256; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
4413 struct ast_str *read_transpath = ast_str_alloca(256)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 256); __ast_str_buf->len = 256; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
4414 struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 384); __ast_str_buf->len = 384; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
4415 struct ast_party_id effective_id;
4416 int i;
4417 RAII_VAR(struct ast_channel_snapshot *, snapshot,_raii_cleanup_block_t _raii_cleanup_snapshot __attribute__((cleanup
(_raii_cleanup_block),unused)) = ((void*)0); __attribute__((__blocks__
(byref))) struct ast_channel_snapshot * snapshot = ast_channel_snapshot_get_latest
(ast_channel_uniqueid(chan)); _raii_cleanup_snapshot = ^{ {(void
)__ao2_cleanup_debug((snapshot), "", "manager.c", 4419, __PRETTY_FUNCTION__
);} }
4418 ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan)),_raii_cleanup_block_t _raii_cleanup_snapshot __attribute__((cleanup
(_raii_cleanup_block),unused)) = ((void*)0); __attribute__((__blocks__
(byref))) struct ast_channel_snapshot * snapshot = ast_channel_snapshot_get_latest
(ast_channel_uniqueid(chan)); _raii_cleanup_snapshot = ^{ {(void
)__ao2_cleanup_debug((snapshot), "", "manager.c", 4419, __PRETTY_FUNCTION__
);} }
4419 ao2_cleanup)_raii_cleanup_block_t _raii_cleanup_snapshot __attribute__((cleanup
(_raii_cleanup_block),unused)) = ((void*)0); __attribute__((__blocks__
(byref))) struct ast_channel_snapshot * snapshot = ast_channel_snapshot_get_latest
(ast_channel_uniqueid(chan)); _raii_cleanup_snapshot = ^{ {(void
)__ao2_cleanup_debug((snapshot), "", "manager.c", 4419, __PRETTY_FUNCTION__
);} }
;
4420 RAII_VAR(struct ast_str *, snapshot_str, NULL, ast_free)_raii_cleanup_block_t _raii_cleanup_snapshot_str __attribute__
((cleanup(_raii_cleanup_block),unused)) = ((void*)0); __attribute__
((__blocks__(byref))) struct ast_str * snapshot_str = ((void*
)0); _raii_cleanup_snapshot_str = ^{ {(void)free(snapshot_str
);} }
;
4421
4422 if (!snapshot) {
4423 return;
4424 }
4425
4426 snapshot_str = ast_manager_build_channel_state_string(snapshot);
4427 if (!snapshot_str) {
4428 return;
4429 }
4430
4431 if (all_variables) {
4432 variable_str = ast_str_create(2048);
4433 } else {
4434 variable_str = ast_str_create(1024);
4435 }
4436 if (!variable_str) {
4437 return;
4438 }
4439
4440 now = ast_tvnow();
4441 elapsed_seconds = ast_tvdiff_sec(now, ast_channel_creationtime(chan));
4442
4443 /* Even if all_variables has been specified, explicitly requested variables
4444 * may be global variables or dialplan functions */
4445 for (i = 0; i < varc; i++) {
4446 char valbuf[512], *ret = NULL((void*)0);
4447
4448 if (vars[i][strlen(vars[i]) - 1] == ')') {
4449 if (ast_func_read(chan, vars[i], valbuf, sizeof(valbuf)) < 0) {
4450 valbuf[0] = '\0';
4451 }
4452 ret = valbuf;
4453 } else {
4454 pbx_retrieve_variable(chan, vars[i], &ret, valbuf, sizeof(valbuf), NULL((void*)0));
4455 }
4456
4457 ast_str_append(&variable_str, 0, "Variable: %s=%s\r\n", vars[i], ret);
4458 }
4459
4460 /* Walk all channel variables and add them */
4461 if (all_variables) {
4462 struct ast_var_t *variables;
4463
4464 AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries)for((variables) = (ast_channel_varshead(chan))->first; (variables
); (variables) = (variables)->entries.next)
{
4465 ast_str_append(&variable_str, 0, "Variable: %s=%s\r\n",
4466 ast_var_name(variables), ast_var_value(variables));
4467 }
4468 }
4469
4470 bridge = ast_channel_get_bridge(chan);
4471 effective_id = ast_channel_connected_effective_id(chan);
4472
4473 astman_append(s,
4474 "Event: Status\r\n"
4475 "Privilege: Call\r\n"
4476 "%s"
4477 "Type: %s\r\n"
4478 "DNID: %s\r\n"
4479 "EffectiveConnectedLineNum: %s\r\n"
4480 "EffectiveConnectedLineName: %s\r\n"
4481 "TimeToHangup: %ld\r\n"
4482 "BridgeID: %s\r\n"
4483 "Linkedid: %s\r\n"
4484 "Application: %s\r\n"
4485 "Data: %s\r\n"
4486 "Nativeformats: %s\r\n"
4487 "Readformat: %s\r\n"
4488 "Readtrans: %s\r\n"
4489 "Writeformat: %s\r\n"
4490 "Writetrans: %s\r\n"
4491 "Callgroup: %llu\r\n"
4492 "Pickupgroup: %llu\r\n"
4493 "Seconds: %ld\r\n"
4494 "%s"
4495 "%s"
4496 "\r\n",
4497 ast_str_buffer(snapshot_str),
4498 ast_channel_tech(chan)->type,
4499 S_OR(ast_channel_dialed(chan)->number.str, "")({typeof(&((ast_channel_dialed(chan)->number.str)[0]))
__x = (ast_channel_dialed(chan)->number.str); _ast_strlen_zero
(__x, "manager.c", __PRETTY_FUNCTION__, 4499) ? ("") : __x;})
,
4500 S_COR(effective_id.number.valid, effective_id.number.str, "<unknown>")({typeof(&((effective_id.number.str)[0])) __x = (effective_id
.number.str); (effective_id.number.valid) && !_ast_strlen_zero
(__x, "manager.c", __PRETTY_FUNCTION__, 4500) ? (__x) : ("<unknown>"
);})
,
4501 S_COR(effective_id.name.valid, effective_id.name.str, "<unknown>")({typeof(&((effective_id.name.str)[0])) __x = (effective_id
.name.str); (effective_id.name.valid) && !_ast_strlen_zero
(__x, "manager.c", __PRETTY_FUNCTION__, 4501) ? (__x) : ("<unknown>"
);})
,
4502 (long)ast_channel_whentohangup(chan)->tv_sec,
4503 bridge ? bridge->uniqueid : "",
4504 ast_channel_linkedid(chan),
4505 ast_channel_appl(chan),
4506 ast_channel_data(chan),
4507 ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf),
4508 ast_format_get_name(ast_channel_readformat(chan)),
4509 ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath),
4510 ast_format_get_name(ast_channel_writeformat(chan)),
4511 ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath),
4512 ast_channel_callgroup(chan),
4513 ast_channel_pickupgroup(chan),
4514 (long)elapsed_seconds,
4515 ast_str_buffer(variable_str),
4516 id_text);
4517 ++*count;
4518
4519 ao2_cleanup(bridge)__ao2_cleanup_debug((bridge), "", "manager.c", 4519, __PRETTY_FUNCTION__
)
;
4520}
4521
4522/*! \brief Manager "status" command to show channels */
4523static int action_status(struct mansession *s, const struct message *m)
4524{
4525 const char *name = astman_get_header(m, "Channel");
4526 const char *chan_variables = astman_get_header(m, "Variables");
4527 const char *all_chan_variables = astman_get_header(m, "AllVariables");
4528 int all_variables = 0;
4529 const char *id = astman_get_header(m, "ActionID");
4530 char *variables = ast_strdupa(S_OR(chan_variables, ""))(__extension__ ({ const char *__old = (({typeof(&((chan_variables
)[0])) __x = (chan_variables); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 4530) ? ("") : __x;})); size_t __len =
strlen(__old) + 1; char *__new = __builtin_alloca(__len); memcpy
(__new, __old, __len); __new; }))
;
4531 struct ast_channel *chan;
4532 int channels = 0;
4533 int all = ast_strlen_zero(name)_ast_strlen_zero(name, "manager.c", __PRETTY_FUNCTION__, 4533
)
; /* set if we want all channels */
4534 char id_text[256];
4535 struct ast_channel_iterator *it_chans = NULL((void*)0);
4536 AST_DECLARE_APP_ARGS(vars,struct { unsigned int argc; char *argv[0]; char *name[100]; }
vars = { 0, }
4537 AST_APP_ARG(name)[100];struct { unsigned int argc; char *argv[0]; char *name[100]; }
vars = { 0, }
4538 )struct { unsigned int argc; char *argv[0]; char *name[100]; }
vars = { 0, }
;
4539
4540 if (!ast_strlen_zero(all_chan_variables)_ast_strlen_zero(all_chan_variables, "manager.c", __PRETTY_FUNCTION__
, 4540)
) {
4541 all_variables = ast_true(all_chan_variables);
4542 }
4543
4544 if (!(function_capable_string_allowed_with_auths(variables, s->session->writeperm))) {
4545 astman_send_error(s, m, "Status Access Forbidden: Variables");
4546 return 0;
4547 }
4548
4549 if (all) {
4550 if (!(it_chans = ast_channel_iterator_all_new())) {
4551 astman_send_error(s, m, "Memory Allocation Failure");
4552 return 1;
4553 }
4554 chan = ast_channel_iterator_next(it_chans);
4555 } else {
4556 chan = ast_channel_get_by_name(name);
4557 if (!chan) {
4558 astman_send_error(s, m, "No such channel");
4559 return 0;
4560 }
4561 }
4562
4563 astman_send_listack(s, m, "Channel status will follow", "start");
4564
4565 if (!ast_strlen_zero(id)_ast_strlen_zero(id, "manager.c", __PRETTY_FUNCTION__, 4565)) {
4566 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
4567 } else {
4568 id_text[0] = '\0';
4569 }
4570
4571 if (!ast_strlen_zero(chan_variables)_ast_strlen_zero(chan_variables, "manager.c", __PRETTY_FUNCTION__
, 4571)
) {
4572 AST_STANDARD_APP_ARGS(vars, variables)vars.argc = __ast_app_separate_args(variables, ',', 1, vars.argv
, ((sizeof(vars) - __builtin_offsetof(typeof(vars), argv)) / sizeof
(vars.argv[0])))
;
4573 }
4574
4575 /* if we look by name, we break after the first iteration */
4576 for (; chan; all ? chan = ast_channel_iterator_next(it_chans) : 0) {
4577 ast_channel_lock(chan)__ao2_lock(chan, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 4577, "chan")
;
4578
4579 generate_status(s, chan, vars.name, vars.argc, all_variables, id_text, &channels);
4580
4581 ast_channel_unlock(chan)__ao2_unlock(chan, "manager.c", __PRETTY_FUNCTION__, 4581, "chan"
)
;
4582 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "manager.c", 4582, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4583 }
4584
4585 if (it_chans) {
4586 ast_channel_iterator_destroy(it_chans);
4587 }
4588
4589 astman_send_list_complete_start(s, m, "StatusComplete", channels);
4590 astman_append(s, "Items: %d\r\n", channels);
4591 astman_send_list_complete_end(s);
4592
4593 return 0;
4594}
4595
4596static int action_sendtext(struct mansession *s, const struct message *m)
4597{
4598 struct ast_channel *c = NULL((void*)0);
4599 const char *name = astman_get_header(m, "Channel");
4600 const char *textmsg = astman_get_header(m, "Message");
4601 int res = 0;
4602
4603 if (ast_strlen_zero(name)_ast_strlen_zero(name, "manager.c", __PRETTY_FUNCTION__, 4603
)
) {
4604 astman_send_error(s, m, "No channel specified");
4605 return 0;
4606 }
4607
4608 if (ast_strlen_zero(textmsg)_ast_strlen_zero(textmsg, "manager.c", __PRETTY_FUNCTION__, 4608
)
) {
4609 astman_send_error(s, m, "No Message specified");
4610 return 0;
4611 }
4612
4613 if (!(c = ast_channel_get_by_name(name))) {
4614 astman_send_error(s, m, "No such channel");
4615 return 0;
4616 }
4617
4618 res = ast_sendtext(c, textmsg);
4619 c = ast_channel_unref(c)({ __ao2_ref((c), (-1), "", "manager.c", 4619, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4620
4621 if (res >= 0) {
4622 astman_send_ack(s, m, "Success");
4623 } else {
4624 astman_send_error(s, m, "Failure");
4625 }
4626
4627 return 0;
4628}
4629
4630/*! \brief action_redirect: The redirect manager command */
4631static int action_redirect(struct mansession *s, const struct message *m)
4632{
4633 char buf[256];
4634 const char *name = astman_get_header(m, "Channel");
4635 const char *name2 = astman_get_header(m, "ExtraChannel");
4636 const char *exten = astman_get_header(m, "Exten");
4637 const char *exten2 = astman_get_header(m, "ExtraExten");
4638 const char *context = astman_get_header(m, "Context");
4639 const char *context2 = astman_get_header(m, "ExtraContext");
4640 const char *priority = astman_get_header(m, "Priority");
4641 const char *priority2 = astman_get_header(m, "ExtraPriority");
4642 struct ast_channel *chan;
4643 struct ast_channel *chan2;
4644 int pi = 0;
4645 int pi2 = 0;
4646 int res;
4647 int chan1_wait = 0;
4648 int chan2_wait = 0;
4649
4650 if (ast_strlen_zero(name)_ast_strlen_zero(name, "manager.c", __PRETTY_FUNCTION__, 4650
)
) {
4651 astman_send_error(s, m, "Channel not specified");
4652 return 0;
4653 }
4654
4655 if (ast_strlen_zero(context)_ast_strlen_zero(context, "manager.c", __PRETTY_FUNCTION__, 4655
)
) {
4656 astman_send_error(s, m, "Context not specified");
4657 return 0;
4658 }
4659 if (ast_strlen_zero(exten)_ast_strlen_zero(exten, "manager.c", __PRETTY_FUNCTION__, 4659
)
) {
4660 astman_send_error(s, m, "Exten not specified");
4661 return 0;
4662 }
4663 if (ast_strlen_zero(priority)_ast_strlen_zero(priority, "manager.c", __PRETTY_FUNCTION__, 4663
)
) {
4664 astman_send_error(s, m, "Priority not specified");
4665 return 0;
4666 }
4667 if (sscanf(priority, "%30d", &pi) != 1) {
4668 pi = ast_findlabel_extension(NULL((void*)0), context, exten, priority, NULL((void*)0));
4669 }
4670 if (pi < 1) {
4671 astman_send_error(s, m, "Priority is invalid");
4672 return 0;
4673 }
4674
4675 if (!ast_strlen_zero(name2)_ast_strlen_zero(name2, "manager.c", __PRETTY_FUNCTION__, 4675
)
&& !ast_strlen_zero(context2)_ast_strlen_zero(context2, "manager.c", __PRETTY_FUNCTION__, 4675
)
) {
4676 /* We have an ExtraChannel and an ExtraContext */
4677 if (ast_strlen_zero(exten2)_ast_strlen_zero(exten2, "manager.c", __PRETTY_FUNCTION__, 4677
)
) {
4678 astman_send_error(s, m, "ExtraExten not specified");
4679 return 0;
4680 }
4681 if (ast_strlen_zero(priority2)_ast_strlen_zero(priority2, "manager.c", __PRETTY_FUNCTION__,
4681)
) {
4682 astman_send_error(s, m, "ExtraPriority not specified");
4683 return 0;
4684 }
4685 if (sscanf(priority2, "%30d", &pi2) != 1) {
4686 pi2 = ast_findlabel_extension(NULL((void*)0), context2, exten2, priority2, NULL((void*)0));
4687 }
4688 if (pi2 < 1) {
4689 astman_send_error(s, m, "ExtraPriority is invalid");
4690 return 0;
4691 }
4692 }
4693
4694 chan = ast_channel_get_by_name(name);
4695 if (!chan) {
4696 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
4697 astman_send_error(s, m, buf);
4698 return 0;
4699 }
4700 if (ast_check_hangup_locked(chan)) {
4701 astman_send_error(s, m, "Redirect failed, channel not up.");
4702 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "manager.c", 4702, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4703 return 0;
4704 }
4705
4706 if (ast_strlen_zero(name2)_ast_strlen_zero(name2, "manager.c", __PRETTY_FUNCTION__, 4706
)
) {
4707 /* Single channel redirect in progress. */
4708 res = ast_async_goto(chan, context, exten, pi);
4709 if (!res) {
4710 astman_send_ack(s, m, "Redirect successful");
4711 } else {
4712 astman_send_error(s, m, "Redirect failed");
4713 }
4714 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "manager.c", 4714, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4715 return 0;
4716 }
4717
4718 chan2 = ast_channel_get_by_name(name2);
4719 if (!chan2) {
4720 snprintf(buf, sizeof(buf), "ExtraChannel does not exist: %s", name2);
4721 astman_send_error(s, m, buf);
4722 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "manager.c", 4722, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4723 return 0;
4724 }
4725 if (ast_check_hangup_locked(chan2)) {
4726 astman_send_error(s, m, "Redirect failed, extra channel not up.");
4727 chan2 = ast_channel_unref(chan2)({ __ao2_ref((chan2), (-1), "", "manager.c", 4727, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4728 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "manager.c", 4728, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4729 return 0;
4730 }
4731
4732 /* Dual channel redirect in progress. */
4733 ast_channel_lock(chan)__ao2_lock(chan, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 4733, "chan")
;
4734 if (ast_channel_is_bridged(chan)) {
4735 ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)do { typeof ((ast_channel_flags(chan))->flags) __p = (ast_channel_flags
(chan))->flags; typeof (__unsigned_int_flags_dummy) __x = 0
; (void) (&__p == &__x); ((ast_channel_flags(chan))->
flags |= (AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)); } while(0)
;
4736 chan1_wait = 1;
4737 }
4738 ast_channel_unlock(chan)__ao2_unlock(chan, "manager.c", __PRETTY_FUNCTION__, 4738, "chan"
)
;
4739
4740 ast_channel_lock(chan2)__ao2_lock(chan2, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 4740, "chan2")
;
4741 if (ast_channel_is_bridged(chan2)) {
4742 ast_set_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)do { typeof ((ast_channel_flags(chan2))->flags) __p = (ast_channel_flags
(chan2))->flags; typeof (__unsigned_int_flags_dummy) __x =
0; (void) (&__p == &__x); ((ast_channel_flags(chan2)
)->flags |= (AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)); } while
(0)
;
4743 chan2_wait = 1;
4744 }
4745 ast_channel_unlock(chan2)__ao2_unlock(chan2, "manager.c", __PRETTY_FUNCTION__, 4745, "chan2"
)
;
4746
4747 res = ast_async_goto(chan, context, exten, pi);
4748 if (!res) {
4749 if (!ast_strlen_zero(context2)_ast_strlen_zero(context2, "manager.c", __PRETTY_FUNCTION__, 4749
)
) {
4750 res = ast_async_goto(chan2, context2, exten2, pi2);
4751 } else {
4752 res = ast_async_goto(chan2, context, exten, pi);
4753 }
4754 if (!res) {
4755 astman_send_ack(s, m, "Dual Redirect successful");
4756 } else {
4757 astman_send_error(s, m, "Secondary redirect failed");
4758 }
4759 } else {
4760 astman_send_error(s, m, "Redirect failed");
4761 }
4762
4763 /* Release the bridge wait. */
4764 if (chan1_wait) {
4765 ast_channel_lock(chan)__ao2_lock(chan, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 4765, "chan")
;
4766 ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)do { typeof ((ast_channel_flags(chan))->flags) __p = (ast_channel_flags
(chan))->flags; typeof (__unsigned_int_flags_dummy) __x = 0
; (void) (&__p == &__x); ((ast_channel_flags(chan))->
flags &= ~(AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)); } while(
0)
;
4767 ast_channel_unlock(chan)__ao2_unlock(chan, "manager.c", __PRETTY_FUNCTION__, 4767, "chan"
)
;
4768 }
4769 if (chan2_wait) {
4770 ast_channel_lock(chan2)__ao2_lock(chan2, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 4770, "chan2")
;
4771 ast_clear_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)do { typeof ((ast_channel_flags(chan2))->flags) __p = (ast_channel_flags
(chan2))->flags; typeof (__unsigned_int_flags_dummy) __x =
0; (void) (&__p == &__x); ((ast_channel_flags(chan2)
)->flags &= ~(AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)); } while
(0)
;
4772 ast_channel_unlock(chan2)__ao2_unlock(chan2, "manager.c", __PRETTY_FUNCTION__, 4772, "chan2"
)
;
4773 }
4774
4775 chan2 = ast_channel_unref(chan2)({ __ao2_ref((chan2), (-1), "", "manager.c", 4775, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4776 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "manager.c", 4776, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4777 return 0;
4778}
4779
4780static int action_blind_transfer(struct mansession *s, const struct message *m)
4781{
4782 const char *name = astman_get_header(m, "Channel");
4783 const char *exten = astman_get_header(m, "Exten");
4784 const char *context = astman_get_header(m, "Context");
4785 struct ast_channel *chan;
4786
4787 if (ast_strlen_zero(name)_ast_strlen_zero(name, "manager.c", __PRETTY_FUNCTION__, 4787
)
) {
4788 astman_send_error(s, m, "No channel specified");
4789 return 0;
4790 }
4791
4792 if (ast_strlen_zero(exten)_ast_strlen_zero(exten, "manager.c", __PRETTY_FUNCTION__, 4792
)
) {
4793 astman_send_error(s, m, "No extension specified");
4794 return 0;
4795 }
4796
4797 chan = ast_channel_get_by_name(name);
4798 if (!chan) {
4799 astman_send_error(s, m, "Channel specified does not exist");
4800 return 0;
4801 }
4802
4803 if (ast_strlen_zero(context)_ast_strlen_zero(context, "manager.c", __PRETTY_FUNCTION__, 4803
)
) {
4804 context = ast_channel_context(chan);
4805 }
4806
4807 switch (ast_bridge_transfer_blind(1, chan, exten, context, NULL((void*)0), NULL((void*)0))) {
4808 case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
4809 astman_send_error(s, m, "Transfer not permitted");
4810 break;
4811 case AST_BRIDGE_TRANSFER_INVALID:
4812 astman_send_error(s, m, "Transfer invalid");
4813 break;
4814 case AST_BRIDGE_TRANSFER_FAIL:
4815 astman_send_error(s, m, "Transfer failed");
4816 break;
4817 case AST_BRIDGE_TRANSFER_SUCCESS:
4818 astman_send_ack(s, m, "Transfer succeeded");
4819 break;
4820 }
4821
4822 ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "manager.c", 4822, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4823 return 0;
4824}
4825
4826static int action_atxfer(struct mansession *s, const struct message *m)
4827{
4828 const char *name = astman_get_header(m, "Channel");
4829 const char *exten = astman_get_header(m, "Exten");
4830 const char *context = astman_get_header(m, "Context");
4831 struct ast_channel *chan = NULL((void*)0);
4832 char feature_code[AST_FEATURE_MAX_LEN11];
4833 const char *digit;
4834
4835 if (ast_strlen_zero(name)_ast_strlen_zero(name, "manager.c", __PRETTY_FUNCTION__, 4835
)
) {
4836 astman_send_error(s, m, "No channel specified");
4837 return 0;
4838 }
4839 if (ast_strlen_zero(exten)_ast_strlen_zero(exten, "manager.c", __PRETTY_FUNCTION__, 4839
)
) {
4840 astman_send_error(s, m, "No extension specified");
4841 return 0;
4842 }
4843
4844 if (!(chan = ast_channel_get_by_name(name))) {
4845 astman_send_error(s, m, "Channel specified does not exist");
4846 return 0;
4847 }
4848
4849 ast_channel_lock(chan)__ao2_lock(chan, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 4849, "chan")
;
4850 if (ast_get_builtin_feature(chan, "atxfer", feature_code, sizeof(feature_code)) ||
4851 ast_strlen_zero(feature_code)_ast_strlen_zero(feature_code, "manager.c", __PRETTY_FUNCTION__
, 4851)
) {
4852 ast_channel_unlock(chan)__ao2_unlock(chan, "manager.c", __PRETTY_FUNCTION__, 4852, "chan"
)
;
4853 astman_send_error(s, m, "No attended transfer feature code found");
4854 ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "manager.c", 4854, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4855 return 0;
4856 }
4857 ast_channel_unlock(chan)__ao2_unlock(chan, "manager.c", __PRETTY_FUNCTION__, 4857, "chan"
)
;
4858
4859 if (!ast_strlen_zero(context)_ast_strlen_zero(context, "manager.c", __PRETTY_FUNCTION__, 4859
)
) {
4860 pbx_builtin_setvar_helper(chan, "TRANSFER_CONTEXT", context);
4861 }
4862
4863 for (digit = feature_code; *digit; ++digit) {
4864 struct ast_frame f = { AST_FRAME_DTMFAST_FRAME_DTMF_END, .subclass.integer = *digit };
4865 ast_queue_frame(chan, &f);
4866 }
4867
4868 for (digit = exten; *digit; ++digit) {
4869 struct ast_frame f = { AST_FRAME_DTMFAST_FRAME_DTMF_END, .subclass.integer = *digit };
4870 ast_queue_frame(chan, &f);
4871 }
4872
4873 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "manager.c", 4873, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
4874
4875 astman_send_ack(s, m, "Atxfer successfully queued");
4876
4877 return 0;
4878}
4879
4880static int check_blacklist(const char *cmd)
4881{
4882 char *cmd_copy, *cur_cmd;
4883 char *cmd_words[AST_MAX_CMD_LEN16] = { NULL((void*)0), };
4884 int i;
4885
4886 cmd_copy = ast_strdupa(cmd)(__extension__ ({ const char *__old = (cmd); size_t __len = strlen
(__old) + 1; char *__new = __builtin_alloca(__len); memcpy (__new
, __old, __len); __new; }))
;
4887 for (i = 0; i < MAX_BLACKLIST_CMD_LEN2 && (cur_cmd = strsep(&cmd_copy, " ")); i++) {
4888 cur_cmd = ast_strip(cur_cmd);
4889 if (ast_strlen_zero(cur_cmd)_ast_strlen_zero(cur_cmd, "manager.c", __PRETTY_FUNCTION__, 4889
)
) {
4890 i--;
4891 continue;
4892 }
4893
4894 cmd_words[i] = cur_cmd;
4895 }
4896
4897 for (i = 0; i < ARRAY_LEN(command_blacklist)(size_t) (sizeof(command_blacklist) / sizeof(0[command_blacklist
]))
; i++) {
4898 int j, match = 1;
4899
4900 for (j = 0; command_blacklist[i].words[j]; j++) {
4901 if (ast_strlen_zero(cmd_words[j])_ast_strlen_zero(cmd_words[j], "manager.c", __PRETTY_FUNCTION__
, 4901)
|| strcasecmp(cmd_words[j], command_blacklist[i].words[j])) {
4902 match = 0;
4903 break;
4904 }
4905 }
4906
4907 if (match) {
4908 return 1;
4909 }
4910 }
4911
4912 return 0;
4913}
4914
4915/*! \brief Manager command "command" - execute CLI command */
4916static int action_command(struct mansession *s, const struct message *m)
4917{
4918 const char *cmd = astman_get_header(m, "Command");
4919 char *buf = NULL((void*)0), *final_buf = NULL((void*)0), *delim, *output;
4920 char template[] = "/tmp/ast-ami-XXXXXX"; /* template for temporary file */
4921 int fd, ret;
4922 off_t len;
4923
4924 if (ast_strlen_zero(cmd)_ast_strlen_zero(cmd, "manager.c", __PRETTY_FUNCTION__, 4924)) {
4925 astman_send_error(s, m, "No command provided");
4926 return 0;
4927 }
4928
4929 if (check_blacklist(cmd)) {
4930 astman_send_error(s, m, "Command blacklisted");
4931 return 0;
4932 }
4933
4934 if ((fd = mkstemp(template)) < 0) {
4935 astman_send_error_va(s, m, "Failed to create temporary file: %s", strerror(errno(*__errno_location ())));
4936 return 0;
4937 }
4938
4939 ret = ast_cli_command(fd, cmd)ast_cli_command_full(-1, -1, fd, cmd);
4940 astman_send_response_full(s, m, ret == RESULT_SUCCESS0 ? "Success" : "Error", MSG_MOREDATA((char *)astman_send_response), NULL((void*)0));
4941
4942 /* Determine number of characters available */
4943 if ((len = lseek(fd, 0, SEEK_END2)) < 0) {
4944 astman_append(s, "Message: Failed to determine number of characters: %s\r\n", strerror(errno(*__errno_location ())));
4945 goto action_command_cleanup;
4946 }
4947
4948 /* This has a potential to overflow the stack. Hence, use the heap. */
4949 buf = ast_malloc(len + 1)_ast_malloc((len + 1), "manager.c", 4949, __PRETTY_FUNCTION__
)
;
4950 final_buf = ast_malloc(len + 1)_ast_malloc((len + 1), "manager.c", 4950, __PRETTY_FUNCTION__
)
;
4951
4952 if (!buf || !final_buf) {
4953 astman_append(s, "Message: Memory allocation failure\r\n");
4954 goto action_command_cleanup;
4955 }
4956
4957 if (lseek(fd, 0, SEEK_SET0) < 0) {
4958 astman_append(s, "Message: Failed to set position on temporary file: %s\r\n", strerror(errno(*__errno_location ())));
4959 goto action_command_cleanup;
4960 }
4961
4962 if (read(fd, buf, len) < 0) {
4963 astman_append(s, "Message: Failed to read from temporary file: %s\r\n", strerror(errno(*__errno_location ())));
4964 goto action_command_cleanup;
4965 }
4966
4967 buf[len] = '\0';
4968 term_strip(final_buf, buf, len);
4969 final_buf[len] = '\0';
4970
4971 /* Trim trailing newline */
4972 if (len && final_buf[len - 1] == '\n') {
4973 final_buf[len - 1] = '\0';
4974 }
4975
4976 astman_append(s, "Message: Command output follows\r\n");
4977
4978 delim = final_buf;
4979 while ((output = strsep(&delim, "\n"))) {
4980 astman_append(s, "Output: %s\r\n", output);
4981 }
4982
4983action_command_cleanup:
4984 astman_append(s, "\r\n");
4985
4986 close(fd);
4987 unlink(template);
4988
4989 ast_freefree(buf);
4990 ast_freefree(final_buf);
4991
4992 return 0;
4993}
4994
4995/*! \brief helper function for originate */
4996struct fast_originate_helper {
4997 int timeout;
4998 struct ast_format_cap *cap; /*!< Codecs used for a call */
4999 int early_media;
5000 AST_DECLARE_STRING_FIELDS (struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5001 AST_STRING_FIELD(tech);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5002 /*! data can contain a channel name, extension number, username, password, etc. */struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5003 AST_STRING_FIELD(data);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5004 AST_STRING_FIELD(app);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5005 AST_STRING_FIELD(appdata);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5006 AST_STRING_FIELD(cid_name);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5007 AST_STRING_FIELD(cid_num);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5008 AST_STRING_FIELD(context);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5009 AST_STRING_FIELD(exten);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5010 AST_STRING_FIELD(idtext);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5011 AST_STRING_FIELD(account);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5012 AST_STRING_FIELD(channelid);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5013 AST_STRING_FIELD(otherchannelid);struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
5014 )struct ast_string_field_pool *__field_mgr_pool; const ast_string_field
tech; const ast_string_field data; const ast_string_field app
; const ast_string_field appdata; const ast_string_field cid_name
; const ast_string_field cid_num; const ast_string_field context
; const ast_string_field exten; const ast_string_field idtext
; const ast_string_field account; const ast_string_field channelid
; const ast_string_field otherchannelid; struct ast_string_field_mgr
__field_mgr
;
5015 int priority;
5016 struct ast_variable *vars;
5017};
5018
5019/*!
5020 * \internal
5021 *
5022 * \param doomed Struct to destroy.
5023 *
5024 * \return Nothing
5025 */
5026static void destroy_fast_originate_helper(struct fast_originate_helper *doomed)
5027{
5028 ao2_cleanup(doomed->cap)__ao2_cleanup_debug((doomed->cap), "", "manager.c", 5028, __PRETTY_FUNCTION__
)
;
5029 ast_variables_destroy(doomed->vars);
5030 ast_string_field_free_memory(doomed)({ int __res__ = -1; if (((void *)(doomed)) != ((void*)0)) { __res__
= __ast_string_field_free_memory(&(doomed)->__field_mgr
, &(doomed)->__field_mgr_pool, AST_STRINGFIELD_DESTROY
, "manager.c", 5030, __PRETTY_FUNCTION__); } __res__; })
;
5031 ast_freefree(doomed);
5032}
5033
5034static void *fast_originate(void *data)
5035{
5036 struct fast_originate_helper *in = data;
5037 int res;
5038 int reason = 0;
5039 struct ast_channel *chan = NULL((void*)0), *chans[1];
5040 char requested_channel[AST_CHANNEL_NAME80];
5041 struct ast_assigned_ids assignedids = {
5042 .uniqueid = in->channelid,
5043 .uniqueid2 = in->otherchannelid
5044 };
5045
5046 if (!ast_strlen_zero(in->app)_ast_strlen_zero(in->app, "manager.c", __PRETTY_FUNCTION__
, 5046)
) {
5047 res = ast_pbx_outgoing_app(in->tech, in->cap, in->data,
5048 in->timeout, in->app, in->appdata, &reason, 1,
5049 S_OR(in->cid_num, NULL)({typeof(&((in->cid_num)[0])) __x = (in->cid_num); _ast_strlen_zero
(__x, "manager.c", __PRETTY_FUNCTION__, 5049) ? (((void*)0)) :
__x;})
,
5050 S_OR(in->cid_name, NULL)({typeof(&((in->cid_name)[0])) __x = (in->cid_name)
; _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5050
) ? (((void*)0)) : __x;})
,
5051 in->vars, in->account, &chan, &assignedids);
5052 } else {
5053 res = ast_pbx_outgoing_exten(in->tech, in->cap, in->data,
5054 in->timeout, in->context, in->exten, in->priority, &reason, 1,
5055 S_OR(in->cid_num, NULL)({typeof(&((in->cid_num)[0])) __x = (in->cid_num); _ast_strlen_zero
(__x, "manager.c", __PRETTY_FUNCTION__, 5055) ? (((void*)0)) :
__x;})
,
5056 S_OR(in->cid_name, NULL)({typeof(&((in->cid_name)[0])) __x = (in->cid_name)
; _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5056
) ? (((void*)0)) : __x;})
,
5057 in->vars, in->account, &chan, in->early_media, &assignedids);
5058 }
5059
5060 if (!chan) {
5061 snprintf(requested_channel, AST_CHANNEL_NAME80, "%s/%s", in->tech, in->data);
5062 }
5063 /* Tell the manager what happened with the channel */
5064 chans[0] = chan;
5065 if (!ast_strlen_zero(in->app)_ast_strlen_zero(in->app, "manager.c", __PRETTY_FUNCTION__
, 5065)
) {
5066 ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans,__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5067 "%s"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5068 "Response: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5069 "Channel: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5070 "Application: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5071 "Data: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5072 "Reason: %d\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5073 "Uniqueid: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5074 "CallerIDNum: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5075 "CallerIDName: %s\r\n",__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5076 in->idtext, res ? "Failure" : "Success",__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5077 chan ? ast_channel_name(chan) : requested_channel,__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5078 in->app, in->appdata, reason,__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5079 chan ? ast_channel_uniqueid(chan) : S_OR(in->channelid, "<unknown>"),__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5080 S_OR(in->cid_num, "<unknown>"),__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5081 S_OR(in->cid_name, "<unknown>")__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
5082 )__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5082, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n"
"Data: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->app
, in->appdata, reason, chan ? ast_channel_uniqueid(chan) :
({typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5082) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5082
) ? ("<unknown>") : __x;}));
;
5083 } else {
5084 ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans,__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5085 "%s"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5086 "Response: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5087 "Channel: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5088 "Context: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5089 "Exten: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5090 "Reason: %d\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5091 "Uniqueid: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5092 "CallerIDNum: %s\r\n"__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5093 "CallerIDName: %s\r\n",__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5094 in->idtext, res ? "Failure" : "Success",__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5095 chan ? ast_channel_name(chan) : requested_channel,__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5096 in->context, in->exten, reason,__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5097 chan ? ast_channel_uniqueid(chan) : S_OR(in->channelid, "<unknown>"),__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5098 S_OR(in->cid_num, "<unknown>"),__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5099 S_OR(in->cid_name, "<unknown>")__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
5100 )__ast_manager_event_multichan((1 << 1), "OriginateResponse"
, chan ? 1 : 0, chans, "manager.c", 5100, __PRETTY_FUNCTION__
, "%s" "Response: %s\r\n" "Channel: %s\r\n" "Context: %s\r\n"
"Exten: %s\r\n" "Reason: %d\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n" , in->idtext, res ? "Failure" : "Success"
, chan ? ast_channel_name(chan) : requested_channel, in->context
, in->exten, reason, chan ? ast_channel_uniqueid(chan) : (
{typeof(&((in->channelid)[0])) __x = (in->channelid
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}), ({typeof(&((in->cid_num
)[0])) __x = (in->cid_num); _ast_strlen_zero(__x, "manager.c"
, __PRETTY_FUNCTION__, 5100) ? ("<unknown>") : __x;}), (
{typeof(&((in->cid_name)[0])) __x = (in->cid_name);
_ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 5100
) ? ("<unknown>") : __x;}));
;
5101 }
5102
5103 /* Locked and ref'd by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
5104 if (chan) {
5105 ast_channel_unlock(chan)__ao2_unlock(chan, "manager.c", __PRETTY_FUNCTION__, 5105, "chan"
)
;
5106 ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "manager.c", 5106, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
5107 }
5108 destroy_fast_originate_helper(in);
5109 return NULL((void*)0);
5110}
5111
5112static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
5113{
5114 const char *unitamount;
5115 const char *unittype;
5116 struct ast_str *str = ast_str_alloca(32)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 32); __ast_str_buf->len = 32; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
5117
5118 memset(entry, 0, sizeof(*entry));
5119
5120 ast_str_set(&str, 0, "UnitAmount(%u)", entry_num);
5121 unitamount = astman_get_header(m, ast_str_buffer(str));
5122
5123 ast_str_set(&str, 0, "UnitType(%u)", entry_num);
5124 unittype = astman_get_header(m, ast_str_buffer(str));
5125
5126 if (!ast_strlen_zero(unitamount)_ast_strlen_zero(unitamount, "manager.c", __PRETTY_FUNCTION__
, 5126)
&& (sscanf(unitamount, "%30u", &entry->amount) == 1)) {
5127 entry->valid_amount = 1;
5128 }
5129
5130 if (!ast_strlen_zero(unittype)_ast_strlen_zero(unittype, "manager.c", __PRETTY_FUNCTION__, 5130
)
&& sscanf(unittype, "%30u", &entry->type) == 1) {
5131 entry->valid_type = 1;
5132 }
5133
5134 return 0;
5135}
5136
5137static int action_aocmessage(struct mansession *s, const struct message *m)
5138{
5139 const char *channel = astman_get_header(m, "Channel");
5140 const char *pchannel = astman_get_header(m, "ChannelPrefix");
5141 const char *msgtype = astman_get_header(m, "MsgType");
5142 const char *chargetype = astman_get_header(m, "ChargeType");
5143 const char *currencyname = astman_get_header(m, "CurrencyName");
5144 const char *currencyamount = astman_get_header(m, "CurrencyAmount");
5145 const char *mult = astman_get_header(m, "CurrencyMultiplier");
5146 const char *totaltype = astman_get_header(m, "TotalType");
5147 const char *aocbillingid = astman_get_header(m, "AOCBillingId");
5148 const char *association_id= astman_get_header(m, "ChargingAssociationId");
5149 const char *association_num = astman_get_header(m, "ChargingAssociationNumber");
5150 const char *association_plan = astman_get_header(m, "ChargingAssociationPlan");
5151
5152 enum ast_aoc_type _msgtype;
5153 enum ast_aoc_charge_type _chargetype;
5154 enum ast_aoc_currency_multiplier _mult = AST_AOC_MULT_ONE;
5155 enum ast_aoc_total_type _totaltype = AST_AOC_TOTAL;
5156 enum ast_aoc_billing_id _billingid = AST_AOC_BILLING_NA;
5157 unsigned int _currencyamount = 0;
5158 int _association_id = 0;
5159 unsigned int _association_plan = 0;
5160 struct ast_channel *chan = NULL((void*)0);
5161
5162 struct ast_aoc_decoded *decoded = NULL((void*)0);
5163 struct ast_aoc_encoded *encoded = NULL((void*)0);
5164 size_t encoded_size = 0;
5165
5166 if (ast_strlen_zero(channel)_ast_strlen_zero(channel, "manager.c", __PRETTY_FUNCTION__, 5166
)
&& ast_strlen_zero(pchannel)_ast_strlen_zero(pchannel, "manager.c", __PRETTY_FUNCTION__, 5166
)
) {
5167 astman_send_error(s, m, "Channel and PartialChannel are not specified. Specify at least one of these.");
5168 goto aocmessage_cleanup;
5169 }
5170
5171 if (!(chan = ast_channel_get_by_name(channel)) && !ast_strlen_zero(pchannel)_ast_strlen_zero(pchannel, "manager.c", __PRETTY_FUNCTION__, 5171
)
) {
5172 chan = ast_channel_get_by_name_prefix(pchannel, strlen(pchannel));
5173 }
5174
5175 if (!chan) {
5176 astman_send_error(s, m, "No such channel");
5177 goto aocmessage_cleanup;
5178 }
5179
5180 if (ast_strlen_zero(msgtype)_ast_strlen_zero(msgtype, "manager.c", __PRETTY_FUNCTION__, 5180
)
|| (strcasecmp(msgtype, "d") && strcasecmp(msgtype, "e"))) {
5181 astman_send_error(s, m, "Invalid MsgType");
5182 goto aocmessage_cleanup;
5183 }
5184
5185 if (ast_strlen_zero(chargetype)_ast_strlen_zero(chargetype, "manager.c", __PRETTY_FUNCTION__
, 5185)
) {
5186 astman_send_error(s, m, "ChargeType not specified");
5187 goto aocmessage_cleanup;
5188 }
5189
5190 _msgtype = strcasecmp(msgtype, "d") ? AST_AOC_E : AST_AOC_D;
5191
5192 if (!strcasecmp(chargetype, "NA")) {
5193 _chargetype = AST_AOC_CHARGE_NA;
5194 } else if (!strcasecmp(chargetype, "Free")) {
5195 _chargetype = AST_AOC_CHARGE_FREE;
5196 } else if (!strcasecmp(chargetype, "Currency")) {
5197 _chargetype = AST_AOC_CHARGE_CURRENCY;
5198 } else if (!strcasecmp(chargetype, "Unit")) {
5199 _chargetype = AST_AOC_CHARGE_UNIT;
5200 } else {
5201 astman_send_error(s, m, "Invalid ChargeType");
5202 goto aocmessage_cleanup;
5203 }
5204
5205 if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
5206
5207 if (ast_strlen_zero(currencyamount)_ast_strlen_zero(currencyamount, "manager.c", __PRETTY_FUNCTION__
, 5207)
|| (sscanf(currencyamount, "%30u", &_currencyamount) != 1)) {
5208 astman_send_error(s, m, "Invalid CurrencyAmount, CurrencyAmount is a required when ChargeType is Currency");
5209 goto aocmessage_cleanup;
5210 }
5211
5212 if (ast_strlen_zero(mult)_ast_strlen_zero(mult, "manager.c", __PRETTY_FUNCTION__, 5212
)
) {
5213 astman_send_error(s, m, "ChargeMultiplier unspecified, ChargeMultiplier is required when ChargeType is Currency.");
5214 goto aocmessage_cleanup;
5215 } else if (!strcasecmp(mult, "onethousandth")) {
5216 _mult = AST_AOC_MULT_ONETHOUSANDTH;
5217 } else if (!strcasecmp(mult, "onehundredth")) {
5218 _mult = AST_AOC_MULT_ONEHUNDREDTH;
5219 } else if (!strcasecmp(mult, "onetenth")) {
5220 _mult = AST_AOC_MULT_ONETENTH;
5221 } else if (!strcasecmp(mult, "one")) {
5222 _mult = AST_AOC_MULT_ONE;
5223 } else if (!strcasecmp(mult, "ten")) {
5224 _mult = AST_AOC_MULT_TEN;
5225 } else if (!strcasecmp(mult, "hundred")) {
5226 _mult = AST_AOC_MULT_HUNDRED;
5227 } else if (!strcasecmp(mult, "thousand")) {
5228 _mult = AST_AOC_MULT_THOUSAND;
5229 } else {
5230 astman_send_error(s, m, "Invalid ChargeMultiplier");
5231 goto aocmessage_cleanup;
5232 }
5233 }
5234
5235 /* create decoded object and start setting values */
5236 if (!(decoded = ast_aoc_create(_msgtype, _chargetype, 0))) {
5237 astman_send_error(s, m, "Message Creation Failed");
5238 goto aocmessage_cleanup;
5239 }
5240
5241 if (_msgtype == AST_AOC_D) {
5242 if (!ast_strlen_zero(totaltype)_ast_strlen_zero(totaltype, "manager.c", __PRETTY_FUNCTION__,
5242)
&& !strcasecmp(totaltype, "subtotal")) {
5243 _totaltype = AST_AOC_SUBTOTAL;
5244 }
5245
5246 if (ast_strlen_zero(aocbillingid)_ast_strlen_zero(aocbillingid, "manager.c", __PRETTY_FUNCTION__
, 5246)
) {
5247 /* ignore this is optional */
5248 } else if (!strcasecmp(aocbillingid, "Normal")) {
5249 _billingid = AST_AOC_BILLING_NORMAL;
5250 } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
5251 _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
5252 } else if (!strcasecmp(aocbillingid, "CreditCard")) {
5253 _billingid = AST_AOC_BILLING_CREDIT_CARD;
5254 } else {
5255 astman_send_error(s, m, "Invalid AOC-D AOCBillingId");
5256 goto aocmessage_cleanup;
5257 }
5258 } else {
5259 if (ast_strlen_zero(aocbillingid)_ast_strlen_zero(aocbillingid, "manager.c", __PRETTY_FUNCTION__
, 5259)
) {
5260 /* ignore this is optional */
5261 } else if (!strcasecmp(aocbillingid, "Normal")) {
5262 _billingid = AST_AOC_BILLING_NORMAL;
5263 } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
5264 _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
5265 } else if (!strcasecmp(aocbillingid, "CreditCard")) {
5266 _billingid = AST_AOC_BILLING_CREDIT_CARD;
5267 } else if (!strcasecmp(aocbillingid, "CallFwdUnconditional")) {
5268 _billingid = AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL;
5269 } else if (!strcasecmp(aocbillingid, "CallFwdBusy")) {
5270 _billingid = AST_AOC_BILLING_CALL_FWD_BUSY;
5271 } else if (!strcasecmp(aocbillingid, "CallFwdNoReply")) {
5272 _billingid = AST_AOC_BILLING_CALL_FWD_NO_REPLY;
5273 } else if (!strcasecmp(aocbillingid, "CallDeflection")) {
5274 _billingid = AST_AOC_BILLING_CALL_DEFLECTION;
5275 } else if (!strcasecmp(aocbillingid, "CallTransfer")) {
5276 _billingid = AST_AOC_BILLING_CALL_TRANSFER;
5277 } else {
5278 astman_send_error(s, m, "Invalid AOC-E AOCBillingId");
5279 goto aocmessage_cleanup;
5280 }
5281
5282 if (!ast_strlen_zero(association_id)_ast_strlen_zero(association_id, "manager.c", __PRETTY_FUNCTION__
, 5282)
&& (sscanf(association_id, "%30d", &_association_id) != 1)) {
5283 astman_send_error(s, m, "Invalid ChargingAssociationId");
5284 goto aocmessage_cleanup;
5285 }
5286 if (!ast_strlen_zero(association_plan)_ast_strlen_zero(association_plan, "manager.c", __PRETTY_FUNCTION__
, 5286)
&& (sscanf(association_plan, "%30u", &_association_plan) != 1)) {
5287 astman_send_error(s, m, "Invalid ChargingAssociationPlan");
5288 goto aocmessage_cleanup;
5289 }
5290
5291 if (_association_id) {
5292 ast_aoc_set_association_id(decoded, _association_id);
5293 } else if (!ast_strlen_zero(association_num)_ast_strlen_zero(association_num, "manager.c", __PRETTY_FUNCTION__
, 5293)
) {
5294 ast_aoc_set_association_number(decoded, association_num, _association_plan);
5295 }
5296 }
5297
5298 if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
5299 ast_aoc_set_currency_info(decoded, _currencyamount, _mult, ast_strlen_zero(currencyname)_ast_strlen_zero(currencyname, "manager.c", __PRETTY_FUNCTION__
, 5299)
? NULL((void*)0) : currencyname);
5300 } else if (_chargetype == AST_AOC_CHARGE_UNIT) {
5301 struct ast_aoc_unit_entry entry;
5302 int i;
5303
5304 /* multiple unit entries are possible, lets get them all */
5305 for (i = 0; i < 32; i++) {
5306 if (aocmessage_get_unit_entry(m, &entry, i)) {
5307 break; /* that's the end then */
5308 }
5309
5310 ast_aoc_add_unit_entry(decoded, entry.valid_amount, entry.amount, entry.valid_type, entry.type);
5311 }
5312
5313 /* at least one unit entry is required */
5314 if (!i) {
5315 astman_send_error(s, m, "Invalid UnitAmount(0), At least one valid unit entry is required when ChargeType is set to Unit");
5316 goto aocmessage_cleanup;
5317 }
5318
5319 }
5320
5321 ast_aoc_set_billing_id(decoded, _billingid);
5322 ast_aoc_set_total_type(decoded, _totaltype);
5323
5324
5325 if ((encoded = ast_aoc_encode(decoded, &encoded_size, NULL((void*)0))) && !ast_indicate_data(chan, AST_CONTROL_AOC, encoded, encoded_size)) {
5326 astman_send_ack(s, m, "AOC Message successfully queued on channel");
5327 } else {
5328 astman_send_error(s, m, "Error encoding AOC message, could not queue onto channel");
5329 }
5330
5331aocmessage_cleanup:
5332
5333 ast_aoc_destroy_decoded(decoded);
5334 ast_aoc_destroy_encoded(encoded);
5335
5336 if (chan) {
5337 chan = ast_channel_unref(chan)({ __ao2_ref((chan), (-1), "", "manager.c", 5337, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
5338 }
5339 return 0;
5340}
5341
5342static int action_originate(struct mansession *s, const struct message *m)
5343{
5344 const char *name = astman_get_header(m, "Channel");
5345 const char *exten = astman_get_header(m, "Exten");
5346 const char *context = astman_get_header(m, "Context");
5347 const char *priority = astman_get_header(m, "Priority");
5348 const char *timeout = astman_get_header(m, "Timeout");
5349 const char *callerid = astman_get_header(m, "CallerID");
5350 const char *account = astman_get_header(m, "Account");
5351 const char *app = astman_get_header(m, "Application");
5352 const char *appdata = astman_get_header(m, "Data");
5353 const char *async = astman_get_header(m, "Async");
5354 const char *id = astman_get_header(m, "ActionID");
5355 const char *codecs = astman_get_header(m, "Codecs");
5356 const char *early_media = astman_get_header(m, "Earlymedia");
5357 struct ast_assigned_ids assignedids = {
5358 .uniqueid = astman_get_header(m, "ChannelId"),
5359 .uniqueid2 = astman_get_header(m, "OtherChannelId"),
5360 };
5361 struct ast_variable *vars = NULL((void*)0);
5362 char *tech, *data;
5363 char *l = NULL((void*)0), *n = NULL((void*)0);
5364 int pi = 0;
5365 int res;
5366 int to = 30000;
5367 int reason = 0;
5368 char tmp[256];
5369 char tmp2[256];
5370 struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)__ast_format_cap_alloc((AST_FORMAT_CAP_FLAG_DEFAULT), "ast_format_cap_alloc"
, "manager.c", 5370, __PRETTY_FUNCTION__)
;
5371 pthread_t th;
5372 int bridge_early = 0;
5373
5374 if (!cap) {
5375 astman_send_error(s, m, "Internal Error. Memory allocation failure.");
5376 return 0;
5377 }
5378 ast_format_cap_append(cap, ast_format_slin, 0)__ast_format_cap_append((cap), (ast_format_slin), (0), "ast_format_cap_append"
, "manager.c", 5378, __PRETTY_FUNCTION__)
;
5379
5380 if ((assignedids.uniqueid && AST_MAX_PUBLIC_UNIQUEID149 < strlen(assignedids.uniqueid))
5381 || (assignedids.uniqueid2 && AST_MAX_PUBLIC_UNIQUEID149 < strlen(assignedids.uniqueid2))) {
5382 astman_send_error_va(s, m, "Uniqueid length exceeds maximum of %d\n",
5383 AST_MAX_PUBLIC_UNIQUEID149);
5384 res = 0;
5385 goto fast_orig_cleanup;
5386 }
5387
5388 if (ast_strlen_zero(name)_ast_strlen_zero(name, "manager.c", __PRETTY_FUNCTION__, 5388
)
) {
5389 astman_send_error(s, m, "Channel not specified");
5390 res = 0;
5391 goto fast_orig_cleanup;
5392 }
5393 if (!ast_strlen_zero(priority)_ast_strlen_zero(priority, "manager.c", __PRETTY_FUNCTION__, 5393
)
&& (sscanf(priority, "%30d", &pi) != 1)) {
5394 if ((pi = ast_findlabel_extension(NULL((void*)0), context, exten, priority, NULL((void*)0))) < 1) {
5395 astman_send_error(s, m, "Invalid priority");
5396 res = 0;
5397 goto fast_orig_cleanup;
5398 }
5399 }
5400 if (!ast_strlen_zero(timeout)_ast_strlen_zero(timeout, "manager.c", __PRETTY_FUNCTION__, 5400
)
&& (sscanf(timeout, "%30d", &to) != 1)) {
5401 astman_send_error(s, m, "Invalid timeout");
5402 res = 0;
5403 goto fast_orig_cleanup;
5404 }
5405 ast_copy_string(tmp, name, sizeof(tmp));
5406 tech = tmp;
5407 data = strchr(tmp, '/')(__extension__ (__builtin_constant_p ('/') && !__builtin_constant_p
(tmp) && ('/') == '\0' ? (char *) __rawmemchr (tmp, '/'
) : __builtin_strchr (tmp, '/')))
;
5408 if (!data) {
5409 astman_send_error(s, m, "Invalid channel");
5410 res = 0;
5411 goto fast_orig_cleanup;
5412 }
5413 *data++ = '\0';
5414 ast_copy_string(tmp2, callerid, sizeof(tmp2));
5415 ast_callerid_parse(tmp2, &n, &l);
5416 if (n) {
5417 if (ast_strlen_zero(n)_ast_strlen_zero(n, "manager.c", __PRETTY_FUNCTION__, 5417)) {
5418 n = NULL((void*)0);
5419 }
5420 }
5421 if (l) {
5422 ast_shrink_phone_number(l);
5423 if (ast_strlen_zero(l)_ast_strlen_zero(l, "manager.c", __PRETTY_FUNCTION__, 5423)) {
5424 l = NULL((void*)0);
5425 }
5426 }
5427 if (!ast_strlen_zero(codecs)_ast_strlen_zero(codecs, "manager.c", __PRETTY_FUNCTION__, 5427
)
) {
5428 ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
5429 ast_format_cap_update_by_allow_disallow(cap, codecs, 1);
5430 }
5431
5432 if (!ast_strlen_zero(app)_ast_strlen_zero(app, "manager.c", __PRETTY_FUNCTION__, 5432) && s->session) {
5433 int bad_appdata = 0;
5434 /* To run the System application (or anything else that goes to
5435 * shell), you must have the additional System privilege */
5436 if (!(s->session->writeperm & EVENT_FLAG_SYSTEM(1 << 0))
5437 && (
5438 strcasestr(app, "system") || /* System(rm -rf /)
5439 TrySystem(rm -rf /) */
5440 strcasestr(app, "exec") || /* Exec(System(rm -rf /))
5441 TryExec(System(rm -rf /)) */
5442 strcasestr(app, "agi") || /* AGI(/bin/rm,-rf /)
5443 EAGI(/bin/rm,-rf /) */
5444 strcasestr(app, "mixmonitor") || /* MixMonitor(blah,,rm -rf) */
5445 strcasestr(app, "externalivr") || /* ExternalIVR(rm -rf) */
5446 (strstr(appdata, "SHELL") && (bad_appdata = 1)) || /* NoOp(${SHELL(rm -rf /)}) */
5447 (strstr(appdata, "EVAL") && (bad_appdata = 1)) /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
5448 )) {
5449 char error_buf[64];
5450 snprintf(error_buf, sizeof(error_buf), "Originate Access Forbidden: %s", bad_appdata ? "Data" : "Application");
5451 astman_send_error(s, m, error_buf);
5452 res = 0;
5453 goto fast_orig_cleanup;
5454 }
5455 }
5456
5457 /* Check early if the extension exists. If not, we need to bail out here. */
5458 if (exten && context && pi) {
5459 if (! ast_exists_extension(NULL((void*)0), context, exten, pi, l)) {
5460 /* The extension does not exist. */
5461 astman_send_error(s, m, "Extension does not exist.");
5462 res = 0;
5463 goto fast_orig_cleanup;
5464 }
5465 }
5466
5467 /* Allocate requested channel variables */
5468 vars = astman_get_variables(m);
5469 if (s->session && s->session->chanvars) {
5470 struct ast_variable *v, *old;
5471 old = vars;
5472 vars = NULL((void*)0);
5473
5474 /* The variables in the AMI originate action are appended at the end of the list, to override any user variables that apply*/
5475
5476 vars = ast_variables_dup(s->session->chanvars);
5477 if (old) {
5478 for (v = vars; v->next; v = v->next );
5479 if (v->next) {
5480 v->next = old; /* Append originate variables at end of list */
5481 }
5482 }
5483 }
5484
5485 /* For originate async - we can bridge in early media stage */
5486 bridge_early = ast_true(early_media);
5487
5488 if (ast_true(async)) {
5489 struct fast_originate_helper *fast;
5490
5491 fast = ast_calloc(1, sizeof(*fast))_ast_calloc((1), (sizeof(*fast)), "manager.c", 5491, __PRETTY_FUNCTION__
)
;
5492 if (!fast || ast_string_field_init(fast, 252)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= __ast_string_field_init(&(fast)->__field_mgr, &
(fast)->__field_mgr_pool, 252, "manager.c", 5492, __PRETTY_FUNCTION__
); } __res__ ; })
) {
5493 ast_freefree(fast);
5494 ast_variables_destroy(vars);
5495 res = -1;
5496 } else {
5497 if (!ast_strlen_zero(id)_ast_strlen_zero(id, "manager.c", __PRETTY_FUNCTION__, 5497)) {
5498 ast_string_field_build(fast, idtext, "ActionID: %s\r\n", id)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __ast_string_field_ptr_build
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, (ast_string_field *) &(fast)->idtext, "ActionID: %s\r\n"
, id); __res__ = 0; } __res__; })
;
5499 }
5500 ast_string_field_set(fast, tech, tech)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) {
__res__ = ({ int __res__ = 0; const char *__d__ = (tech); size_t
__dlen__ = (__d__) ? strlen(__d__) + 1 : 1; ast_string_field
*__p__ = (ast_string_field *) (&(fast)->tech); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(fast)->__field_mgr, &
(fast)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
5501 ast_string_field_set(fast, data, data)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) {
__res__ = ({ int __res__ = 0; const char *__d__ = (data); size_t
__dlen__ = (__d__) ? strlen(__d__) + 1 : 1; ast_string_field
*__p__ = (ast_string_field *) (&(fast)->data); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(fast)->__field_mgr, &
(fast)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
5502 ast_string_field_set(fast, app, app)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) {
__res__ = ({ int __res__ = 0; const char *__d__ = (app); size_t
__dlen__ = (__d__) ? strlen(__d__) + 1 : 1; ast_string_field
*__p__ = (ast_string_field *) (&(fast)->app); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(fast)->__field_mgr, &
(fast)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
5503 ast_string_field_set(fast, appdata, appdata)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) {
__res__ = ({ int __res__ = 0; const char *__d__ = (appdata);
size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1; ast_string_field
*__p__ = (ast_string_field *) (&(fast)->appdata); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(fast)->__field_mgr, &
(fast)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
5504 ast_string_field_set(fast, cid_num, l)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) {
__res__ = ({ int __res__ = 0; const char *__d__ = (l); size_t
__dlen__ = (__d__) ? strlen(__d__) + 1 : 1; ast_string_field
*__p__ = (ast_string_field *) (&(fast)->cid_num); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(fast)->__field_mgr, &
(fast)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
5505 ast_string_field_set(fast, cid_name, n)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) {
__res__ = ({ int __res__ = 0; const char *__d__ = (n); size_t
__dlen__ = (__d__) ? strlen(__d__) + 1 : 1; ast_string_field
*__p__ = (ast_string_field *) (&(fast)->cid_name); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(fast)->__field_mgr, &
(fast)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
5506 ast_string_field_set(fast, context, context)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) {
__res__ = ({ int __res__ = 0; const char *__d__ = (context);
size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1; ast_string_field
*__p__ = (ast_string_field *) (&(fast)->context); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(fast)->__field_mgr, &
(fast)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
5507 ast_string_field_set(fast, exten, exten)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) {
__res__ = ({ int __res__ = 0; const char *__d__ = (exten); size_t
__dlen__ = (__d__) ? strlen(__d__) + 1 : 1; ast_string_field
*__p__ = (ast_string_field *) (&(fast)->exten); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(fast)->__field_mgr, &
(fast)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
5508 ast_string_field_set(fast, account, account)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) {
__res__ = ({ int __res__ = 0; const char *__d__ = (account);
size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1; ast_string_field
*__p__ = (ast_string_field *) (&(fast)->account); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(fast)->__field_mgr, &
(fast)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
5509 ast_string_field_set(fast, channelid, assignedids.uniqueid)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) {
__res__ = ({ int __res__ = 0; const char *__d__ = (assignedids
.uniqueid); size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1
; ast_string_field *__p__ = (ast_string_field *) (&(fast)
->channelid); ast_string_field target = *__p__; if (__dlen__
== 1) { __ast_string_field_release_active((fast)->__field_mgr_pool
, *__p__); *__p__ = __ast_string_field_empty; } else if ((__dlen__
<= *((ast_string_field_allocation *) (*__p__ - __alignof__
(ast_string_field_allocation)))) || (!__ast_string_field_ptr_grow
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
5510 ast_string_field_set(fast, otherchannelid, assignedids.uniqueid2)({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(fast)) != ((void*)0)) {
__res__ = ({ int __res__ = 0; const char *__d__ = (assignedids
.uniqueid2); size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1
; ast_string_field *__p__ = (ast_string_field *) (&(fast)
->otherchannelid); ast_string_field target = *__p__; if (__dlen__
== 1) { __ast_string_field_release_active((fast)->__field_mgr_pool
, *__p__); *__p__ = __ast_string_field_empty; } else if ((__dlen__
<= *((ast_string_field_allocation *) (*__p__ - __alignof__
(ast_string_field_allocation)))) || (!__ast_string_field_ptr_grow
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(fast)->__field_mgr, &(fast)->__field_mgr_pool
, __dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((fast)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
5511 fast->vars = vars;
5512 fast->cap = cap;
5513 cap = NULL((void*)0); /* transfered originate helper the capabilities structure. It is now responsible for freeing it. */
5514 fast->timeout = to;
5515 fast->early_media = bridge_early;
5516 fast->priority = pi;
5517 if (ast_pthread_create_detached(&th, NULL, fast_originate, fast)ast_pthread_create_detached_stack(&th, ((void*)0), fast_originate
, fast, 0, "manager.c", __FUNCTION__, 5517, "fast_originate")
) {
5518 destroy_fast_originate_helper(fast);
5519 res = -1;
5520 } else {
5521 res = 0;
5522 }
5523 }
5524 } else if (!ast_strlen_zero(app)_ast_strlen_zero(app, "manager.c", __PRETTY_FUNCTION__, 5524)) {
5525 res = ast_pbx_outgoing_app(tech, cap, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL((void*)0), assignedids.uniqueid ? &assignedids : NULL((void*)0));
5526 ast_variables_destroy(vars);
5527 } else {
5528 if (exten && context && pi) {
5529 res = ast_pbx_outgoing_exten(tech, cap, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL((void*)0), bridge_early, assignedids.uniqueid ? &assignedids : NULL((void*)0));
5530 ast_variables_destroy(vars);
5531 } else {
5532 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
5533 ast_variables_destroy(vars);
5534 res = 0;
5535 goto fast_orig_cleanup;
5536 }
5537 }
5538 if (!res) {
5539 astman_send_ack(s, m, "Originate successfully queued");
5540 } else {
5541 astman_send_error(s, m, "Originate failed");
5542 }
5543
5544fast_orig_cleanup:
5545 ao2_cleanup(cap)__ao2_cleanup_debug((cap), "", "manager.c", 5545, __PRETTY_FUNCTION__
)
;
5546 return 0;
5547}
5548
5549static int action_mailboxstatus(struct mansession *s, const struct message *m)
5550{
5551 const char *mailbox = astman_get_header(m, "Mailbox");
5552 int ret;
5553
5554 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "manager.c", __PRETTY_FUNCTION__, 5554
)
) {
5555 astman_send_error(s, m, "Mailbox not specified");
5556 return 0;
5557 }
5558 ret = ast_app_has_voicemail(mailbox, NULL((void*)0));
5559 astman_start_ack(s, m);
5560 astman_append(s, "Message: Mailbox Status\r\n"
5561 "Mailbox: %s\r\n"
5562 "Waiting: %d\r\n\r\n", mailbox, ret);
5563 return 0;
5564}
5565
5566static int action_mailboxcount(struct mansession *s, const struct message *m)
5567{
5568 const char *mailbox = astman_get_header(m, "Mailbox");
5569 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;;
5570
5571 if (ast_strlen_zero(mailbox)_ast_strlen_zero(mailbox, "manager.c", __PRETTY_FUNCTION__, 5571
)
) {
5572 astman_send_error(s, m, "Mailbox not specified");
5573 return 0;
5574 }
5575 ast_app_inboxcount2(mailbox, &urgentmsgs, &newmsgs, &oldmsgs);
5576 astman_start_ack(s, m);
5577 astman_append(s, "Message: Mailbox Message Count\r\n"
5578 "Mailbox: %s\r\n"
5579 "UrgMessages: %d\r\n"
5580 "NewMessages: %d\r\n"
5581 "OldMessages: %d\r\n"
5582 "\r\n",
5583 mailbox, urgentmsgs, newmsgs, oldmsgs);
5584 return 0;
5585}
5586
5587static int action_extensionstate(struct mansession *s, const struct message *m)
5588{
5589 const char *exten = astman_get_header(m, "Exten");
5590 const char *context = astman_get_header(m, "Context");
5591 char hint[256] = "";
5592 int status;
5593 if (ast_strlen_zero(exten)_ast_strlen_zero(exten, "manager.c", __PRETTY_FUNCTION__, 5593
)
) {
5594 astman_send_error(s, m, "Extension not specified");
5595 return 0;
5596 }
5597 if (ast_strlen_zero(context)_ast_strlen_zero(context, "manager.c", __PRETTY_FUNCTION__, 5597
)
) {
5598 context = "default";
5599 }
5600 status = ast_extension_state(NULL((void*)0), context, exten);
5601 ast_get_hint(hint, sizeof(hint) - 1, NULL((void*)0), 0, NULL((void*)0), context, exten);
5602 astman_start_ack(s, m);
5603 astman_append(s, "Message: Extension Status\r\n"
5604 "Exten: %s\r\n"
5605 "Context: %s\r\n"
5606 "Hint: %s\r\n"
5607 "Status: %d\r\n"
5608 "StatusText: %s\r\n\r\n",
5609 exten, context, hint, status,
5610 ast_extension_state2str(status));
5611 return 0;
5612}
5613
5614static int action_presencestate(struct mansession *s, const struct message *m)
5615{
5616 const char *provider = astman_get_header(m, "Provider");
5617 enum ast_presence_state state;
5618 char *subtype;
5619 char *message;
5620
5621 if (ast_strlen_zero(provider)_ast_strlen_zero(provider, "manager.c", __PRETTY_FUNCTION__, 5621
)
) {
5622 astman_send_error(s, m, "No provider specified");
5623 return 0;
5624 }
5625
5626 state = ast_presence_state(provider, &subtype, &message);
5627 if (state == AST_PRESENCE_INVALID) {
5628 astman_send_error_va(s, m, "Invalid provider %s or provider in invalid state", provider);
5629 return 0;
5630 }
5631
5632 astman_start_ack(s, m);
5633 astman_append(s, "Message: Presence State\r\n"
5634 "State: %s\r\n", ast_presence_state2str(state));
5635
5636 if (!ast_strlen_zero(subtype)_ast_strlen_zero(subtype, "manager.c", __PRETTY_FUNCTION__, 5636
)
) {
5637 astman_append(s, "Subtype: %s\r\n", subtype);
5638 }
5639
5640 if (!ast_strlen_zero(message)_ast_strlen_zero(message, "manager.c", __PRETTY_FUNCTION__, 5640
)
) {
5641 /* XXX The Message header here is deprecated as it
5642 * duplicates the action response header 'Message'.
5643 * Remove it in the next major revision of AMI.
5644 */
5645 astman_append(s, "Message: %s\r\n"
5646 "PresenceMessage: %s\r\n",
5647 message, message);
5648 }
5649 astman_append(s, "\r\n");
5650
5651 return 0;
5652}
5653
5654static int action_timeout(struct mansession *s, const struct message *m)
5655{
5656 struct ast_channel *c;
5657 const char *name = astman_get_header(m, "Channel");
5658 double timeout = atof(astman_get_header(m, "Timeout"));
5659 struct timeval when = { timeout, 0 };
5660
5661 if (ast_strlen_zero(name)_ast_strlen_zero(name, "manager.c", __PRETTY_FUNCTION__, 5661
)
) {
5662 astman_send_error(s, m, "No channel specified");
5663 return 0;
5664 }
5665
5666 if (!timeout || timeout < 0) {
5667 astman_send_error(s, m, "No timeout specified");
5668 return 0;
5669 }
5670
5671 if (!(c = ast_channel_get_by_name(name))) {
5672 astman_send_error(s, m, "No such channel");
5673 return 0;
5674 }
5675
5676 when.tv_usec = (timeout - when.tv_sec) * 1000000.0;
5677
5678 ast_channel_lock(c)__ao2_lock(c, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 5678, "c")
;
5679 ast_channel_setwhentohangup_tv(c, when);
5680 ast_channel_unlock(c)__ao2_unlock(c, "manager.c", __PRETTY_FUNCTION__, 5680, "c");
5681 c = ast_channel_unref(c)({ __ao2_ref((c), (-1), "", "manager.c", 5681, __PRETTY_FUNCTION__
); (struct ast_channel *) (((void*)0)); })
;
5682
5683 astman_send_ack(s, m, "Timeout Set");
5684
5685 return 0;
5686}
5687
5688static int whitefilter_cmp_fn(void *obj, void *arg, void *data, int flags)
5689{
5690 regex_t *regex_filter = obj;
5691 const char *eventdata = arg;
5692 int *result = data;
5693
5694 if (!regexec(regex_filter, eventdata, 0, NULL((void*)0), 0)) {
5695 *result = 1;
5696 return (CMP_MATCH | CMP_STOP);
5697 }
5698
5699 return 0;
5700}
5701
5702static int blackfilter_cmp_fn(void *obj, void *arg, void *data, int flags)
5703{
5704 regex_t *regex_filter = obj;
5705 const char *eventdata = arg;
5706 int *result = data;
5707
5708 if (!regexec(regex_filter, eventdata, 0, NULL((void*)0), 0)) {
5709 *result = 0;
5710 return (CMP_MATCH | CMP_STOP);
5711 }
5712
5713 *result = 1;
5714 return 0;
5715}
5716
5717/*!
5718 * \brief Manager command to add an event filter to a manager session
5719 * \see For more details look at manager_add_filter
5720 */
5721static int action_filter(struct mansession *s, const struct message *m)
5722{
5723 const char *filter = astman_get_header(m, "Filter");
5724 const char *operation = astman_get_header(m, "Operation");
5725 int res;
5726
5727 if (!strcasecmp(operation, "Add")) {
5728 res = manager_add_filter(filter, s->session->whitefilters, s->session->blackfilters);
5729
5730 if (res != FILTER_SUCCESS) {
5731 if (res == FILTER_ALLOC_FAILED) {
5732 astman_send_error(s, m, "Internal Error. Failed to allocate regex for filter");
5733 return 0;
5734 } else if (res == FILTER_COMPILE_FAIL) {
5735 astman_send_error(s, m, "Filter did not compile. Check the syntax of the filter given.");
5736 return 0;
5737 } else {
5738 astman_send_error(s, m, "Internal Error. Failed adding filter.");
5739 return 0;
5740 }
5741 }
5742
5743 astman_send_ack(s, m, "Success");
5744 return 0;
5745 }
5746
5747 astman_send_error(s, m, "Unknown operation");
5748 return 0;
5749}
5750
5751/*!
5752 * \brief Add an event filter to a manager session
5753 *
5754 * \param filter_pattern Filter syntax to add, see below for syntax
5755 *
5756 * \return FILTER_ALLOC_FAILED Memory allocation failure
5757 * \return FILTER_COMPILE_FAIL If the filter did not compile
5758 * \return FILTER_SUCCESS Success
5759 *
5760 * Filter will be used to match against each line of a manager event
5761 * Filter can be any valid regular expression
5762 * Filter can be a valid regular expression prefixed with !, which will add the filter as a black filter
5763 *
5764 * Examples:
5765 * \code
5766 * filter_pattern = "Event: Newchannel"
5767 * filter_pattern = "Event: New.*"
5768 * filter_pattern = "!Channel: DAHDI.*"
5769 * \endcode
5770 *
5771 */
5772static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters) {
5773 regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation")__ao2_alloc((sizeof(*new_filter)), (event_filter_destructor),
AO2_ALLOC_OPT_LOCK_MUTEX, ("event_filter allocation"), "manager.c"
, 5773, __PRETTY_FUNCTION__)
;
5774 int is_blackfilter;
5775
5776 if (!new_filter) {
5777 return FILTER_ALLOC_FAILED;
5778 }
5779
5780 if (filter_pattern[0] == '!') {
5781 is_blackfilter = 1;
5782 filter_pattern++;
5783 } else {
5784 is_blackfilter = 0;
5785 }
5786
5787 if (regcomp(new_filter, filter_pattern, REG_EXTENDED1 | REG_NOSUB(((1 << 1) << 1) << 1))) {
5788 ao2_t_ref(new_filter, -1, "failed to make regex")__ao2_ref((new_filter), (-1), ("failed to make regex"), "manager.c"
, 5788, __PRETTY_FUNCTION__)
;
5789 return FILTER_COMPILE_FAIL;
5790 }
5791
5792 if (is_blackfilter) {
5793 ao2_t_link(blackfilters, new_filter, "link new filter into black user container")__ao2_link((blackfilters), (new_filter), 0, ("link new filter into black user container"
), "manager.c", 5793, __PRETTY_FUNCTION__)
;
5794 } else {
5795 ao2_t_link(whitefilters, new_filter, "link new filter into white user container")__ao2_link((whitefilters), (new_filter), 0, ("link new filter into white user container"
), "manager.c", 5795, __PRETTY_FUNCTION__)
;
5796 }
5797
5798 ao2_ref(new_filter, -1)__ao2_ref((new_filter), (-1), "", "manager.c", 5798, __PRETTY_FUNCTION__
)
;
5799
5800 return FILTER_SUCCESS;
5801}
5802
5803static int match_filter(struct mansession *s, char *eventdata)
5804{
5805 int result = 0;
5806
5807 ast_debug(3, "Examining AMI event:\n%s\n", eventdata)do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (3)))) { ast_log(0,
"manager.c", 5807, __PRETTY_FUNCTION__, "Examining AMI event:\n%s\n"
, eventdata); } } while (0)
;
5808 if (!ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
5809 return 1; /* no filtering means match all */
5810 } else if (ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
5811 /* white filters only: implied black all filter processed first, then white filters */
5812 ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container")__ao2_callback_data((s->session->whitefilters), (OBJ_NODATA
), (whitefilter_cmp_fn), (eventdata), (&result), ("find filter in session filter container"
), "manager.c", 5812, __PRETTY_FUNCTION__)
;
5813 } else if (!ao2_container_count(s->session->whitefilters) && ao2_container_count(s->session->blackfilters)) {
5814 /* black filters only: implied white all filter processed first, then black filters */
5815 ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container")__ao2_callback_data((s->session->blackfilters), (OBJ_NODATA
), (blackfilter_cmp_fn), (eventdata), (&result), ("find filter in session filter container"
), "manager.c", 5815, __PRETTY_FUNCTION__)
;
5816 } else {
5817 /* white and black filters: implied black all filter processed first, then white filters, and lastly black filters */
5818 ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container")__ao2_callback_data((s->session->whitefilters), (OBJ_NODATA
), (whitefilter_cmp_fn), (eventdata), (&result), ("find filter in session filter container"
), "manager.c", 5818, __PRETTY_FUNCTION__)
;
5819 if (result) {
5820 result = 0;
5821 ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container")__ao2_callback_data((s->session->blackfilters), (OBJ_NODATA
), (blackfilter_cmp_fn), (eventdata), (&result), ("find filter in session filter container"
), "manager.c", 5821, __PRETTY_FUNCTION__)
;
5822 }
5823 }
5824
5825 return result;
5826}
5827
5828/*!
5829 * Send any applicable events to the client listening on this socket.
5830 * Wait only for a finite time on each event, and drop all events whether
5831 * they are successfully sent or not.
5832 */
5833static int process_events(struct mansession *s)
5834{
5835 int ret = 0;
5836
5837 ao2_lock(s->session)__ao2_lock(s->session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 5837, "s->session")
;
5838 if (s->session->f != NULL((void*)0)) {
5839 struct eventqent *eqe = s->session->last_ev;
5840
5841 while ((eqe = advance_event(eqe))) {
5842 if (eqe->category == EVENT_FLAG_SHUTDOWN-1) {
5843 ast_debug(3, "Received CloseSession event\n")do { if ((option_debug >= (3) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (3)))) { ast_log(0,
"manager.c", 5843, __PRETTY_FUNCTION__, "Received CloseSession event\n"
); } } while (0)
;
5844 ret = -1;
5845 }
5846 if (!ret && s->session->authenticated &&
5847 (s->session->readperm & eqe->category) == eqe->category &&
5848 (s->session->send_events & eqe->category) == eqe->category) {
5849 if (match_filter(s, eqe->eventdata)) {
5850 if (send_string(s, eqe->eventdata) < 0)
5851 ret = -1; /* don't send more */
5852 }
5853 }
5854 s->session->last_ev = eqe;
5855 }
5856 }
5857 ao2_unlock(s->session)__ao2_unlock(s->session, "manager.c", __PRETTY_FUNCTION__,
5857, "s->session")
;
5858 return ret;
5859}
5860
5861static int action_userevent(struct mansession *s, const struct message *m)
5862{
5863 const char *event = astman_get_header(m, "UserEvent");
5864 struct ast_str *body = ast_str_thread_get(&userevent_buf, 16);
5865 int x;
5866
5867 ast_str_reset(body);
5868
5869 for (x = 0; x < m->hdrcount; x++) {
5870 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:")) &&
5871 strncasecmp("Action:", m->headers[x], strlen("Action:"))) {
5872 ast_str_append(&body, 0, "%s\r\n", m->headers[x]);
5873 }
5874 }
5875
5876 astman_send_ack(s, m, "Event Sent");
5877 manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, ast_str_buffer(body))__ast_manager_event_multichan((1 << 6), "UserEvent", 0,
((void*)0), "manager.c", 5877, __PRETTY_FUNCTION__, "UserEvent: %s\r\n%s"
, event, ast_str_buffer(body))
;
5878 return 0;
5879}
5880
5881/*! \brief Show PBX core settings information */
5882static int action_coresettings(struct mansession *s, const struct message *m)
5883{
5884 const char *actionid = astman_get_header(m, "ActionID");
5885 char idText[150];
5886
5887 if (!ast_strlen_zero(actionid)_ast_strlen_zero(actionid, "manager.c", __PRETTY_FUNCTION__, 5887
)
) {
5888 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5889 } else {
5890 idText[0] = '\0';
5891 }
5892
5893 astman_append(s, "Response: Success\r\n"
5894 "%s"
5895 "AMIversion: %s\r\n"
5896 "AsteriskVersion: %s\r\n"
5897 "SystemName: %s\r\n"
5898 "CoreMaxCalls: %d\r\n"
5899 "CoreMaxLoadAvg: %f\r\n"
5900 "CoreRunUser: %s\r\n"
5901 "CoreRunGroup: %s\r\n"
5902 "CoreMaxFilehandles: %d\r\n"
5903 "CoreRealTimeEnabled: %s\r\n"
5904 "CoreCDRenabled: %s\r\n"
5905 "CoreHTTPenabled: %s\r\n"
5906 "\r\n",
5907 idText,
5908 AMI_VERSION"2.8.0",
5909 ast_get_version(),
5910 ast_config_AST_SYSTEM_NAME,
5911 ast_option_maxcalls,
5912 ast_option_maxload,
5913 ast_config_AST_RUN_USER,
5914 ast_config_AST_RUN_GROUP,
5915 ast_option_maxfiles,
5916 AST_CLI_YESNO(ast_realtime_enabled())((ast_realtime_enabled()) ? "Yes" : "No"),
5917 AST_CLI_YESNO(ast_cdr_is_enabled())((ast_cdr_is_enabled()) ? "Yes" : "No"),
5918 AST_CLI_YESNO(check_webmanager_enabled())((check_webmanager_enabled()) ? "Yes" : "No")
5919 );
5920 return 0;
5921}
5922
5923/*! \brief Show PBX core status information */
5924static int action_corestatus(struct mansession *s, const struct message *m)
5925{
5926 const char *actionid = astman_get_header(m, "ActionID");
5927 char idText[150];
5928 char startuptime[150], startupdate[150];
5929 char reloadtime[150], reloaddate[150];
5930 struct ast_tm tm;
5931
5932 if (!ast_strlen_zero(actionid)_ast_strlen_zero(actionid, "manager.c", __PRETTY_FUNCTION__, 5932
)
) {
5933 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5934 } else {
5935 idText[0] = '\0';
5936 }
5937
5938 ast_localtime(&ast_startuptime, &tm, NULL((void*)0));
5939 ast_strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
5940 ast_strftime(startupdate, sizeof(startupdate), "%Y-%m-%d", &tm);
5941 ast_localtime(&ast_lastreloadtime, &tm, NULL((void*)0));
5942 ast_strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
5943 ast_strftime(reloaddate, sizeof(reloaddate), "%Y-%m-%d", &tm);
5944
5945 astman_append(s, "Response: Success\r\n"
5946 "%s"
5947 "CoreStartupDate: %s\r\n"
5948 "CoreStartupTime: %s\r\n"
5949 "CoreReloadDate: %s\r\n"
5950 "CoreReloadTime: %s\r\n"
5951 "CoreCurrentCalls: %d\r\n"
5952 "\r\n",
5953 idText,
5954 startupdate,
5955 startuptime,
5956 reloaddate,
5957 reloadtime,
5958 ast_active_channels()
5959 );
5960 return 0;
5961}
5962
5963/*! \brief Send a reload event */
5964static int action_reload(struct mansession *s, const struct message *m)
5965{
5966 const char *module = astman_get_header(m, "Module");
5967 enum ast_module_reload_result res = ast_module_reload(S_OR(module, NULL)({typeof(&((module)[0])) __x = (module); _ast_strlen_zero
(__x, "manager.c", __PRETTY_FUNCTION__, 5967) ? (((void*)0)) :
__x;})
);
5968
5969 switch (res) {
5970 case AST_MODULE_RELOAD_NOT_FOUND:
5971 astman_send_error(s, m, "No such module");
5972 break;
5973 case AST_MODULE_RELOAD_NOT_IMPLEMENTED:
5974 astman_send_error(s, m, "Module does not support reload");
5975 break;
5976 case AST_MODULE_RELOAD_ERROR:
5977 astman_send_error(s, m, "An unknown error occurred");
5978 break;
5979 case AST_MODULE_RELOAD_IN_PROGRESS:
5980 astman_send_error(s, m, "A reload is in progress");
5981 break;
5982 case AST_MODULE_RELOAD_UNINITIALIZED:
5983 astman_send_error(s, m, "Module not initialized");
5984 break;
5985 case AST_MODULE_RELOAD_QUEUED:
5986 case AST_MODULE_RELOAD_SUCCESS:
5987 /* Treat a queued request as success */
5988 astman_send_ack(s, m, "Module Reloaded");
5989 break;
5990 }
5991 return 0;
5992}
5993
5994/*! \brief Manager command "CoreShowChannels" - List currently defined channels
5995 * and some information about them. */
5996static int action_coreshowchannels(struct mansession *s, const struct message *m)
5997{
5998 const char *actionid = astman_get_header(m, "ActionID");
5999 char idText[256];
6000 int numchans = 0;
6001 struct ao2_container *channels;
6002 struct ao2_iterator it_chans;
6003 struct stasis_message *msg;
6004
6005 if (!ast_strlen_zero(actionid)_ast_strlen_zero(actionid, "manager.c", __PRETTY_FUNCTION__, 6005
)
) {
6006 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
6007 } else {
6008 idText[0] = '\0';
6009 }
6010
6011 channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type());
6012 if (!channels) {
6013 astman_send_error(s, m, "Could not get cached channels");
6014 return 0;
6015 }
6016
6017 astman_send_listack(s, m, "Channels will follow", "start");
6018
6019 it_chans = ao2_iterator_init(channels, 0);
6020 for (; (msg = ao2_iterator_next(&it_chans)__ao2_iterator_next((&it_chans), "", "manager.c", 6020, __PRETTY_FUNCTION__
)
); ao2_ref(msg, -1)__ao2_ref((msg), (-1), "", "manager.c", 6020, __PRETTY_FUNCTION__
)
) {
6021 struct ast_channel_snapshot *cs = stasis_message_data(msg);
6022 struct ast_str *built = ast_manager_build_channel_state_string_prefix(cs, "");
6023 char durbuf[10] = "";
6024
6025 if (!built) {
6026 continue;
6027 }
6028
6029 if (!ast_tvzero(cs->creationtime)) {
6030 int duration, durh, durm, durs;
6031
6032 duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->creationtime) / 1000);
6033 durh = duration / 3600;
6034 durm = (duration % 3600) / 60;
6035 durs = duration % 60;
6036 snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
6037 }
6038
6039 astman_append(s,
6040 "Event: CoreShowChannel\r\n"
6041 "%s"
6042 "%s"
6043 "Application: %s\r\n"
6044 "ApplicationData: %s\r\n"
6045 "Duration: %s\r\n"
6046 "BridgeId: %s\r\n"
6047 "\r\n",
6048 idText,
6049 ast_str_buffer(built),
6050 cs->appl,
6051 cs->data,
6052 durbuf,
6053 cs->bridgeid);
6054
6055 numchans++;
6056
6057 ast_freefree(built);
6058 }
6059 ao2_iterator_destroy(&it_chans);
6060
6061 astman_send_list_complete_start(s, m, "CoreShowChannelsComplete", numchans);
6062 astman_send_list_complete_end(s);
6063
6064 ao2_ref(channels, -1)__ao2_ref((channels), (-1), "", "manager.c", 6064, __PRETTY_FUNCTION__
)
;
6065 return 0;
6066}
6067
6068/*! \brief Manager command "LoggerRotate" - reloads and rotates the logger in
6069 * the same manner as the CLI command 'logger rotate'. */
6070static int action_loggerrotate(struct mansession *s, const struct message *m)
6071{
6072 if (ast_logger_rotate()) {
6073 astman_send_error(s, m, "Failed to reload the logger and rotate log files");
6074 return 0;
6075 }
6076
6077 astman_send_ack(s, m, "Reloaded the logger and rotated log files");
6078 return 0;
6079}
6080
6081/*! \brief Manager function to check if module is loaded */
6082static int manager_modulecheck(struct mansession *s, const struct message *m)
6083{
6084 int res;
6085 const char *module = astman_get_header(m, "Module");
6086 const char *id = astman_get_header(m, "ActionID");
6087 char idText[256];
6088 char filename[PATH_MAX4096];
6089 char *cut;
6090
6091 ast_copy_string(filename, module, sizeof(filename));
6092 if ((cut = strchr(filename, '.')(__extension__ (__builtin_constant_p ('.') && !__builtin_constant_p
(filename) && ('.') == '\0' ? (char *) __rawmemchr (
filename, '.') : __builtin_strchr (filename, '.')))
)) {
6093 *cut = '\0';
6094 } else {
6095 cut = filename + strlen(filename);
6096 }
6097 snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".so");
6098 ast_debug(1, "**** ModuleCheck .so file %s\n", filename)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 6098, __PRETTY_FUNCTION__, "**** ModuleCheck .so file %s\n"
, filename); } } while (0)
;
6099 res = ast_module_check(filename);
6100 if (!res) {
6101 astman_send_error(s, m, "Module not loaded");
6102 return 0;
6103 }
6104
6105 if (!ast_strlen_zero(id)_ast_strlen_zero(id, "manager.c", __PRETTY_FUNCTION__, 6105)) {
6106 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
6107 } else {
6108 idText[0] = '\0';
6109 }
6110 astman_append(s, "Response: Success\r\n%s", idText);
6111#if !defined(LOW_MEMORY)
6112 astman_append(s, "Version: %s\r\n\r\n", "");
6113#endif
6114 return 0;
6115}
6116
6117static int manager_moduleload(struct mansession *s, const struct message *m)
6118{
6119 int res;
6120 const char *module = astman_get_header(m, "Module");
6121 const char *loadtype = astman_get_header(m, "LoadType");
6122
6123 if (!loadtype || strlen(loadtype) == 0) {
6124 astman_send_error(s, m, "Incomplete ModuleLoad action.");
6125 }
6126 if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0) {
6127 astman_send_error(s, m, "Need module name");
6128 }
6129
6130 if (!strcasecmp(loadtype, "load")) {
6131 res = ast_load_resource(module);
6132 if (res) {
6133 astman_send_error(s, m, "Could not load module.");
6134 } else {
6135 astman_send_ack(s, m, "Module loaded.");
6136 }
6137 } else if (!strcasecmp(loadtype, "unload")) {
6138 res = ast_unload_resource(module, AST_FORCE_SOFT);
6139 if (res) {
6140 astman_send_error(s, m, "Could not unload module.");
6141 } else {
6142 astman_send_ack(s, m, "Module unloaded.");
6143 }
6144 } else if (!strcasecmp(loadtype, "reload")) {
6145 /* TODO: Unify the ack/error messages here with action_reload */
6146 if (!ast_strlen_zero(module)_ast_strlen_zero(module, "manager.c", __PRETTY_FUNCTION__, 6146
)
) {
6147 enum ast_module_reload_result reload_res = ast_module_reload(module);
6148
6149 switch (reload_res) {
6150 case AST_MODULE_RELOAD_NOT_FOUND:
6151 astman_send_error(s, m, "No such module.");
6152 break;
6153 case AST_MODULE_RELOAD_NOT_IMPLEMENTED:
6154 astman_send_error(s, m, "Module does not support reload action.");
6155 break;
6156 case AST_MODULE_RELOAD_ERROR:
6157 astman_send_error(s, m, "An unknown error occurred");
6158 break;
6159 case AST_MODULE_RELOAD_IN_PROGRESS:
6160 astman_send_error(s, m, "A reload is in progress");
6161 break;
6162 case AST_MODULE_RELOAD_UNINITIALIZED:
6163 astman_send_error(s, m, "Module not initialized");
6164 break;
6165 case AST_MODULE_RELOAD_QUEUED:
6166 case AST_MODULE_RELOAD_SUCCESS:
6167 /* Treat a queued request as success */
6168 astman_send_ack(s, m, "Module reloaded.");
6169 break;
6170 }
6171 } else {
6172 ast_module_reload(NULL((void*)0)); /* Reload all modules */
6173 astman_send_ack(s, m, "All modules reloaded");
6174 }
6175 } else
6176 astman_send_error(s, m, "Incomplete ModuleLoad action.");
6177 return 0;
6178}
6179
6180/*
6181 * Done with the action handlers here, we start with the code in charge
6182 * of accepting connections and serving them.
6183 * accept_thread() forks a new thread for each connection, session_do(),
6184 * which in turn calls get_input() repeatedly until a full message has
6185 * been accumulated, and then invokes process_message() to pass it to
6186 * the appropriate handler.
6187 */
6188
6189/*! \brief
6190 * Process an AMI message, performing desired action.
6191 * Return 0 on success, -1 on error that require the session to be destroyed.
6192 */
6193static int process_message(struct mansession *s, const struct message *m)
6194{
6195 int ret = 0;
6196 struct manager_action *act_found;
6197 struct ast_manager_user *user = NULL((void*)0);
6198 const char *username;
6199 const char *action;
6200
6201 action = __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY2);
6202 if (ast_strlen_zero(action)_ast_strlen_zero(action, "manager.c", __PRETTY_FUNCTION__, 6202
)
) {
6203 report_req_bad_format(s, "NONE");
6204 mansession_lock(s);
6205 astman_send_error(s, m, "Missing action in request");
6206 mansession_unlock(s);
6207 return 0;
6208 }
6209
6210 if (ast_shutting_down()) {
6211 ast_log(LOG_ERROR4, "manager.c", 6211, __PRETTY_FUNCTION__, "Unable to process manager action '%s'. Asterisk is shutting down.\n", action);
6212 mansession_lock(s);
6213 astman_send_error(s, m, "Asterisk is shutting down");
6214 mansession_unlock(s);
6215 return 0;
6216 }
6217
6218 if (!s->session->authenticated
6219 && strcasecmp(action, "Login")
6220 && strcasecmp(action, "Logoff")
6221 && strcasecmp(action, "Challenge")) {
6222 if (!s->session->authenticated) {
6223 report_req_not_allowed(s, action);
6224 }
6225 mansession_lock(s);
6226 astman_send_error(s, m, "Permission denied");
6227 mansession_unlock(s);
6228 return 0;
6229 }
6230
6231 if (!s->session->authenticated
6232 && (!strcasecmp(action, "Login")
6233 || !strcasecmp(action, "Challenge"))) {
6234 username = astman_get_header(m, "Username");
6235
6236 if (!ast_strlen_zero(username)_ast_strlen_zero(username, "manager.c", __PRETTY_FUNCTION__, 6236
)
&& check_manager_session_inuse(username)) {
6237 AST_RWLIST_WRLOCK(&users)__ast_rwlock_wrlock("manager.c", 6237, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
6238 user = get_manager_by_name_locked(username);
6239 if (user && !user->allowmultiplelogin) {
6240 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 6240, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
6241 report_session_limit(s);
6242 sleep(1);
6243 mansession_lock(s);
6244 astman_send_error(s, m, "Login Already In Use");
6245 mansession_unlock(s);
6246 return -1;
6247 }
6248 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 6248, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
6249 }
6250 }
6251
6252 act_found = action_find(action);
6253 if (act_found) {
6254 /* Found the requested AMI action. */
6255 int acted = 0;
6256
6257 if ((s->session->writeperm & act_found->authority)
6258 || act_found->authority == 0) {
6259 /* We have the authority to execute the action. */
6260 ao2_lock(act_found)__ao2_lock(act_found, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 6260, "act_found")
;
6261 if (act_found->registered && act_found->func) {
6262 ast_debug(1, "Running action '%s'\n", act_found->action)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 6262, __PRETTY_FUNCTION__, "Running action '%s'\n"
, act_found->action); } } while (0)
;
6263 if (act_found->module) {
6264 ast_module_ref(act_found->module)__ast_module_ref(act_found->module, "manager.c", 6264, __PRETTY_FUNCTION__
)
;
6265 }
6266 ao2_unlock(act_found)__ao2_unlock(act_found, "manager.c", __PRETTY_FUNCTION__, 6266
, "act_found")
;
6267 ret = act_found->func(s, m);
6268 acted = 1;
6269 ao2_lock(act_found)__ao2_lock(act_found, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 6269, "act_found")
;
6270 if (act_found->module) {
6271 ast_module_unref(act_found->module)__ast_module_unref(act_found->module, "manager.c", 6271, __PRETTY_FUNCTION__
)
;
6272 }
6273 }
6274 ao2_unlock(act_found)__ao2_unlock(act_found, "manager.c", __PRETTY_FUNCTION__, 6274
, "act_found")
;
6275 }
6276 if (!acted) {
6277 /*
6278 * We did not execute the action because access was denied, it
6279 * was no longer registered, or no action was really registered.
6280 * Complain about it and leave.
6281 */
6282 report_req_not_allowed(s, action);
6283 mansession_lock(s);
6284 astman_send_error(s, m, "Permission denied");
6285 mansession_unlock(s);
6286 }
6287 ao2_t_ref(act_found, -1, "done with found action object")__ao2_ref((act_found), (-1), ("done with found action object"
), "manager.c", 6287, __PRETTY_FUNCTION__)
;
6288 } else {
6289 char buf[512];
6290
6291 report_req_bad_format(s, action);
6292 snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
6293 mansession_lock(s);
6294 astman_send_error(s, m, buf);
6295 mansession_unlock(s);
6296 }
6297 if (ret) {
6298 return ret;
6299 }
6300 /* Once done with our message, deliver any pending events unless the
6301 requester doesn't want them as part of this response.
6302 */
6303 if (ast_strlen_zero(astman_get_header(m, "SuppressEvents"))_ast_strlen_zero(astman_get_header(m, "SuppressEvents"), "manager.c"
, __PRETTY_FUNCTION__, 6303)
) {
6304 return process_events(s);
6305 } else {
6306 return ret;
6307 }
6308}
6309
6310/*!
6311 * Read one full line (including crlf) from the manager socket.
6312 * \note \verbatim
6313 * \r\n is the only valid terminator for the line.
6314 * (Note that, later, '\0' will be considered as the end-of-line marker,
6315 * so everything between the '\0' and the '\r\n' will not be used).
6316 * Also note that we assume output to have at least "maxlen" space.
6317 * \endverbatim
6318 */
6319static int get_input(struct mansession *s, char *output)
6320{
6321 int res, x;
6322 int maxlen = sizeof(s->session->inbuf) - 1;
6323 char *src = s->session->inbuf;
6324 int timeout = -1;
6325 time_t now;
6326
6327 /*
6328 * Look for \r\n within the buffer. If found, copy to the output
6329 * buffer and return, trimming the \r\n (not used afterwards).
6330 */
6331 for (x = 0; x < s->session->inlen; x++) {
6332 int cr; /* set if we have \r */
6333 if (src[x] == '\r' && x+1 < s->session->inlen && src[x + 1] == '\n') {
6334 cr = 2; /* Found. Update length to include \r\n */
6335 } else if (src[x] == '\n') {
6336 cr = 1; /* also accept \n only */
6337 } else {
6338 continue;
6339 }
6340 memmove(output, src, x); /*... but trim \r\n */
6341 output[x] = '\0'; /* terminate the string */
6342 x += cr; /* number of bytes used */
6343 s->session->inlen -= x; /* remaining size */
6344 memmove(src, src + x, s->session->inlen); /* remove used bytes */
6345 return 1;
6346 }
6347 if (s->session->inlen >= maxlen) {
6348 /* no crlf found, and buffer full - sorry, too long for us
6349 * keep the last character in case we are in the middle of a CRLF. */
6350 ast_log(LOG_WARNING3, "manager.c", 6350, __PRETTY_FUNCTION__, "Discarding message from %s. Line too long: %.25s...\n", ast_sockaddr_stringify_addr(&s->session->addr), src);
6351 src[0] = src[s->session->inlen - 1];
6352 s->session->inlen = 1;
6353 s->parsing = MESSAGE_LINE_TOO_LONG;
6354 }
6355 res = 0;
6356 while (res == 0) {
6357 /* calculate a timeout if we are not authenticated */
6358 if (!s->session->authenticated) {
6359 if(time(&now) == -1) {
6360 ast_log(LOG_ERROR4, "manager.c", 6360, __PRETTY_FUNCTION__, "error executing time(): %s\n", strerror(errno(*__errno_location ())));
6361 return -1;
6362 }
6363
6364 timeout = (authtimeout - (now - s->session->authstart)) * 1000;
6365 if (timeout < 0) {
6366 /* we have timed out */
6367 return 0;
6368 }
6369 }
6370
6371 ao2_lock(s->session)__ao2_lock(s->session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 6371, "s->session")
;
6372 if (s->session->pending_event) {
6373 s->session->pending_event = 0;
6374 ao2_unlock(s->session)__ao2_unlock(s->session, "manager.c", __PRETTY_FUNCTION__,
6374, "s->session")
;
6375 return 0;
6376 }
6377 s->session->waiting_thread = pthread_self();
6378 ao2_unlock(s->session)__ao2_unlock(s->session, "manager.c", __PRETTY_FUNCTION__,
6378, "s->session")
;
6379
6380 res = ast_wait_for_input(s->session->fd, timeout);
6381
6382 ao2_lock(s->session)__ao2_lock(s->session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 6382, "s->session")
;
6383 s->session->waiting_thread = AST_PTHREADT_NULL(pthread_t) -1;
6384 ao2_unlock(s->session)__ao2_unlock(s->session, "manager.c", __PRETTY_FUNCTION__,
6384, "s->session")
;
6385 }
6386 if (res < 0) {
6387 /* If we get a signal from some other thread (typically because
6388 * there are new events queued), return 0 to notify the caller.
6389 */
6390 if (errno(*__errno_location ()) == EINTR4 || errno(*__errno_location ()) == EAGAIN11) {
6391 return 0;
6392 }
6393 ast_log(LOG_WARNING3, "manager.c", 6393, __PRETTY_FUNCTION__, "poll() returned error: %s\n", strerror(errno(*__errno_location ())));
6394 return -1;
6395 }
6396
6397 ao2_lock(s->session)__ao2_lock(s->session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 6397, "s->session")
;
6398 res = fread(src + s->session->inlen, 1, maxlen - s->session->inlen, s->session->f);
6399 if (res < 1) {
6400 res = -1; /* error return */
6401 } else {
6402 s->session->inlen += res;
6403 src[s->session->inlen] = '\0';
6404 res = 0;
6405 }
6406 ao2_unlock(s->session)__ao2_unlock(s->session, "manager.c", __PRETTY_FUNCTION__,
6406, "s->session")
;
6407 return res;
6408}
6409
6410/*!
6411 * \internal
6412 * \brief Error handling for sending parse errors. This function handles locking, and clearing the
6413 * parse error flag.
6414 *
6415 * \param s AMI session to process action request.
6416 * \param m Message that's in error.
6417 * \param error Error message to send.
6418 */
6419static void handle_parse_error(struct mansession *s, struct message *m, char *error)
6420{
6421 mansession_lock(s);
6422 astman_send_error(s, m, error);
6423 s->parsing = MESSAGE_OKAY;
6424 mansession_unlock(s);
6425}
6426
6427/*!
6428 * \internal
6429 * \brief Read and process an AMI action request.
6430 *
6431 * \param s AMI session to process action request.
6432 *
6433 * \retval 0 Retain AMI connection for next command.
6434 * \retval -1 Drop AMI connection due to logoff or connection error.
6435 */
6436static int do_message(struct mansession *s)
6437{
6438 struct message m = { 0 };
6439 char header_buf[sizeof(s->session->inbuf)] = { '\0' };
6440 int res;
6441 int idx;
6442 int hdr_loss;
6443 time_t now;
6444
6445 hdr_loss = 0;
6446 for (;;) {
6447 /* Check if any events are pending and do them if needed */
6448 if (process_events(s)) {
6449 res = -1;
6450 break;
6451 }
6452 res = get_input(s, header_buf);
6453 if (res == 0) {
6454 /* No input line received. */
6455 if (!s->session->authenticated) {
6456 if (time(&now) == -1) {
6457 ast_log(LOG_ERROR4, "manager.c", 6457, __PRETTY_FUNCTION__, "error executing time(): %s\n", strerror(errno(*__errno_location ())));
6458 res = -1;
6459 break;
6460 }
6461
6462 if (now - s->session->authstart > authtimeout) {
6463 if (displayconnects) {
6464 ast_verb(2, "Client from %s, failed to authenticate in %d seconds\n", ast_sockaddr_stringify_addr(&s->session->addr), authtimeout)do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 6464, __PRETTY_FUNCTION__, 2, "Client from %s, failed to authenticate in %d seconds\n"
, ast_sockaddr_stringify_addr(&s->session->addr), authtimeout
); } } while (0)
;
6465 }
6466 res = -1;
6467 break;
6468 }
6469 }
6470 continue;
6471 } else if (res > 0) {
6472 /* Input line received. */
6473 if (ast_strlen_zero(header_buf)_ast_strlen_zero(header_buf, "manager.c", __PRETTY_FUNCTION__
, 6473)
) {
6474 if (hdr_loss) {
6475 mansession_lock(s);
6476 astman_send_error(s, &m, "Too many lines in message or allocation failure");
6477 mansession_unlock(s);
6478 res = 0;
6479 } else {
6480 switch (s->parsing) {
6481 case MESSAGE_OKAY:
6482 res = process_message(s, &m) ? -1 : 0;
6483 break;
6484 case MESSAGE_LINE_TOO_LONG:
6485 handle_parse_error(s, &m, "Failed to parse message: line too long");
6486 res = 0;
6487 break;
6488 }
6489 }
6490 break;
6491 } else if (m.hdrcount < ARRAY_LEN(m.headers)(size_t) (sizeof(m.headers) / sizeof(0[m.headers]))) {
6492 m.headers[m.hdrcount] = ast_strdup(header_buf)_ast_strdup((header_buf), "manager.c", 6492, __PRETTY_FUNCTION__
)
;
6493 if (!m.headers[m.hdrcount]) {
6494 /* Allocation failure. */
6495 hdr_loss = 1;
6496 } else {
6497 ++m.hdrcount;
6498 }
6499 } else {
6500 /* Too many lines in message. */
6501 hdr_loss = 1;
6502 }
6503 } else {
6504 /* Input error. */
6505 break;
6506 }
6507 }
6508
6509 /* Free AMI request headers. */
6510 for (idx = 0; idx < m.hdrcount; ++idx) {
6511 ast_freefree((void *) m.headers[idx]);
6512 }
6513 return res;
6514}
6515
6516/*! \brief The body of the individual manager session.
6517 * Call get_input() to read one line at a time
6518 * (or be woken up on new events), collect the lines in a
6519 * message until found an empty line, and execute the request.
6520 * In any case, deliver events asynchronously through process_events()
6521 * (called from here if no line is available, or at the end of
6522 * process_message(). )
6523 */
6524static void *session_do(void *data)
6525{
6526 struct ast_tcptls_session_instance *ser = data;
6527 struct mansession_session *session;
6528 struct mansession s = {
6529 .tcptls_session = data,
6530 };
6531 int flags;
6532 int res;
6533 struct ast_sockaddr ser_remote_address_tmp;
6534 struct protoent *p;
6535
6536 if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= authlimit) {
6537 fclose(ser->f);
6538 ast_atomic_fetchadd_int(&unauth_sessions, -1);
6539 goto done;
6540 }
6541
6542 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
6543 session = build_mansession(&ser_remote_address_tmp);
6544
6545 if (session == NULL((void*)0)) {
6546 fclose(ser->f);
6547 ast_atomic_fetchadd_int(&unauth_sessions, -1);
6548 goto done;
6549 }
6550
6551 /* here we set TCP_NODELAY on the socket to disable Nagle's algorithm.
6552 * This is necessary to prevent delays (caused by buffering) as we
6553 * write to the socket in bits and pieces. */
6554 p = getprotobyname("tcp");
6555 if (p) {
6556 int arg = 1;
6557 if( setsockopt(ser->fd, p->p_proto, TCP_NODELAY1, (char *)&arg, sizeof(arg) ) < 0 ) {
6558 ast_log(LOG_WARNING3, "manager.c", 6558, __PRETTY_FUNCTION__, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\nSome manager actions may be slow to respond.\n", strerror(errno(*__errno_location ())));
6559 }
6560 } else {
6561 ast_log(LOG_WARNING3, "manager.c", 6561, __PRETTY_FUNCTION__, "Failed to set manager tcp connection to TCP_NODELAY, getprotobyname(\"tcp\") failed\nSome manager actions may be slow to respond.\n");
6562 }
6563
6564 /* make sure socket is non-blocking */
6565 flags = fcntl(ser->fd, F_GETFL3);
6566 flags |= O_NONBLOCK04000;
6567 fcntl(ser->fd, F_SETFL4, flags);
6568
6569 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 6569, "session")
;
6570 /* Hook to the tail of the event queue */
6571 session->last_ev = grab_last();
6572
6573 ast_mutex_init(&s.lock)__ast_pthread_mutex_init(1, "manager.c", 6573, __PRETTY_FUNCTION__
, "&s.lock", &s.lock)
;
6574
6575 /* these fields duplicate those in the 'ser' structure */
6576 session->fd = s.fd = ser->fd;
6577 session->f = s.f = ser->f;
6578 ast_sockaddr_copy(&session->addr, &ser_remote_address_tmp);
6579 s.session = session;
6580
6581 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores){ (&session->datastores)->first = ((void*)0); (&
session->datastores)->last = ((void*)0); }
;
6582
6583 if(time(&session->authstart) == -1) {
6584 ast_log(LOG_ERROR4, "manager.c", 6584, __PRETTY_FUNCTION__, "error executing time(): %s; disconnecting client\n", strerror(errno(*__errno_location ())));
6585 ast_atomic_fetchadd_int(&unauth_sessions, -1);
6586 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 6586,
"session")
;
6587 session_destroy(session);
6588 goto done;
6589 }
6590 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 6590,
"session")
;
6591
6592 /*
6593 * We cannot let the stream exclusively wait for data to arrive.
6594 * We have to wake up the task to send async events.
6595 */
6596 ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 0);
6597
6598 ast_tcptls_stream_set_timeout_sequence(ser->stream_cookie,
6599 ast_tvnow(), authtimeout * 1000);
6600
6601 astman_append(&s, "Asterisk Call Manager/%s\r\n", AMI_VERSION"2.8.0"); /* welcome prompt */
6602 for (;;) {
6603 if ((res = do_message(&s)) < 0 || s.write_error) {
6604 break;
6605 }
6606 if (session->authenticated) {
6607 ast_tcptls_stream_set_timeout_disable(ser->stream_cookie);
6608 }
6609 }
6610 /* session is over, explain why and terminate */
6611 if (session->authenticated) {
6612 if (manager_displayconnects(session)) {
6613 ast_verb(2, "Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr))do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 6613, __PRETTY_FUNCTION__, 2, "Manager '%s' logged off from %s\n"
, session->username, ast_sockaddr_stringify_addr(&session
->addr)); } } while (0)
;
6614 }
6615 } else {
6616 ast_atomic_fetchadd_int(&unauth_sessions, -1);
6617 if (displayconnects) {
6618 ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_sockaddr_stringify_addr(&session->addr))do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 6618, __PRETTY_FUNCTION__, 2, "Connect attempt from '%s' unable to authenticate\n"
, ast_sockaddr_stringify_addr(&session->addr)); } } while
(0)
;
6619 }
6620 }
6621
6622 session_destroy(session);
6623
6624 ast_mutex_destroy(&s.lock)__ast_pthread_mutex_destroy("manager.c", 6624, __PRETTY_FUNCTION__
, "&s.lock", &s.lock)
;
6625done:
6626 ao2_ref(ser, -1)__ao2_ref((ser), (-1), "", "manager.c", 6626, __PRETTY_FUNCTION__
)
;
6627 ser = NULL((void*)0);
6628 return NULL((void*)0);
6629}
6630
6631/*! \brief remove at most n_max stale session from the list. */
6632static void purge_sessions(int n_max)
6633{
6634 struct ao2_container *sessions;
6635 struct mansession_session *session;
6636 time_t now = time(NULL((void*)0));
6637 struct ao2_iterator i;
6638
6639 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 6639
, __PRETTY_FUNCTION__, "mgr_sessions")
;
6640 if (!sessions) {
6641 return;
6642 }
6643 i = ao2_iterator_init(sessions, 0);
6644 ao2_ref(sessions, -1)__ao2_ref((sessions), (-1), "", "manager.c", 6644, __PRETTY_FUNCTION__
)
;
6645 while ((session = ao2_iterator_next(&i)__ao2_iterator_next((&i), "", "manager.c", 6645, __PRETTY_FUNCTION__
)
) && n_max > 0) {
6646 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 6646, "session")
;
6647 if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
6648 if (session->authenticated
6649 && VERBOSITY_ATLEAST(2)((2) <= ast_verb_sys_level)
6650 && manager_displayconnects(session)) {
6651 ast_verb(2, "HTTP Manager '%s' timed out from %s\n",do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 6652, __PRETTY_FUNCTION__, 2, "HTTP Manager '%s' timed out from %s\n"
, session->username, ast_sockaddr_stringify_addr(&session
->addr)); } } while (0)
6652 session->username, ast_sockaddr_stringify_addr(&session->addr))do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 6652, __PRETTY_FUNCTION__, 2, "HTTP Manager '%s' timed out from %s\n"
, session->username, ast_sockaddr_stringify_addr(&session
->addr)); } } while (0)
;
6653 }
6654 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 6654,
"session")
;
6655 session_destroy(session);
6656 n_max--;
6657 } else {
6658 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 6658,
"session")
;
6659 unref_mansession(session);
6660 }
6661 }
6662 ao2_iterator_destroy(&i);
6663}
6664
6665/*! \brief
6666 * events are appended to a queue from where they
6667 * can be dispatched to clients.
6668 */
6669static int append_event(const char *str, int category)
6670{
6671 struct eventqent *tmp = ast_malloc(sizeof(*tmp) + strlen(str))_ast_malloc((sizeof(*tmp) + strlen(str)), "manager.c", 6671, __PRETTY_FUNCTION__
)
;
6672 static int seq; /* sequence number */
6673
6674 if (!tmp) {
6
Taking false branch
6675 return -1;
6676 }
6677
6678 /* need to init all fields, because ast_malloc() does not */
6679 tmp->usecount = 0;
6680 tmp->category = category;
6681 tmp->seq = ast_atomic_fetchadd_int(&seq, 1);
6682 tmp->tv = ast_tvnow();
6683 AST_RWLIST_NEXT(tmp, eq_next)((tmp)->eq_next.next) = NULL((void*)0);
6684 strcpy(tmp->eventdata, str);
7
String copy function overflows destination buffer
6685
6686 AST_RWLIST_WRLOCK(&all_events)__ast_rwlock_wrlock("manager.c", 6686, __PRETTY_FUNCTION__, &
(&all_events)->lock, "&(&all_events)->lock"
)
;
6687 AST_RWLIST_INSERT_TAIL(&all_events, tmp, eq_next)do { if (!(&all_events)->first) { (&all_events)->
first = (tmp); (&all_events)->last = (tmp); } else { (
&all_events)->last->eq_next.next = (tmp); (&all_events
)->last = (tmp); } } while (0)
;
6688 AST_RWLIST_UNLOCK(&all_events)__ast_rwlock_unlock("manager.c", 6688, __PRETTY_FUNCTION__, &
(&all_events)->lock, "&(&all_events)->lock"
)
;
6689
6690 return 0;
6691}
6692
6693static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
6694{
6695 struct varshead *vars;
6696 struct ast_var_t *var;
6697
6698 vars = ast_channel_get_manager_vars(chan);
6699 if (!vars) {
6700 return;
6701 }
6702
6703 AST_LIST_TRAVERSE(vars, var, entries)for((var) = (vars)->first; (var); (var) = (var)->entries
.next)
{
6704 ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", ast_channel_name(chan), var->name, var->value);
6705 }
6706 ao2_ref(vars, -1)__ao2_ref((vars), (-1), "", "manager.c", 6706, __PRETTY_FUNCTION__
)
;
6707}
6708
6709/* XXX see if can be moved inside the function */
6710AST_THREADSTORAGE(manager_event_buf)static void __init_manager_event_buf(void); static struct ast_threadstorage
manager_event_buf = { .once = 0, .key_init = __init_manager_event_buf
, .custom_init = ((void*)0), }; static void __init_manager_event_buf
(void) { pthread_key_create(&(manager_event_buf).key, free
); }
;
6711#define MANAGER_EVENT_BUF_INITSIZE256 256
6712
6713static int __attribute__((format(printf, 9, 0))) __manager_event_sessions_va(
6714 struct ao2_container *sessions,
6715 int category,
6716 const char *event,
6717 int chancount,
6718 struct ast_channel **chans,
6719 const char *file,
6720 int line,
6721 const char *func,
6722 const char *fmt,
6723 va_list ap)
6724{
6725 struct ast_str *auth = ast_str_alloca(MAX_AUTH_PERM_STRING)({ struct ast_str *__ast_str_buf; __ast_str_buf = __builtin_alloca
(sizeof(*__ast_str_buf) + 150); __ast_str_buf->len = 150; __ast_str_buf
->used = 0; __ast_str_buf->ts = ((struct ast_threadstorage
*)2); __ast_str_buf->str[0] = '\0'; (__ast_str_buf); })
;
6726 const char *cat_str;
6727 struct timeval now;
6728 struct ast_str *buf;
6729 int i;
6730
6731 buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE256);
6732 if (!buf) {
6733 return -1;
6734 }
6735
6736 cat_str = authority_to_str(category, &auth);
6737 ast_str_set(&buf, 0,
6738 "Event: %s\r\n"
6739 "Privilege: %s\r\n",
6740 event, cat_str);
6741
6742 if (timestampevents) {
6743 now = ast_tvnow();
6744 ast_str_append(&buf, 0,
6745 "Timestamp: %ld.%06lu\r\n",
6746 (long)now.tv_sec, (unsigned long) now.tv_usec);
6747 }
6748 if (manager_debug) {
6749 static int seq;
6750
6751 ast_str_append(&buf, 0,
6752 "SequenceNumber: %d\r\n",
6753 ast_atomic_fetchadd_int(&seq, 1));
6754 ast_str_append(&buf, 0,
6755 "File: %s\r\n"
6756 "Line: %d\r\n"
6757 "Func: %s\r\n",
6758 file, line, func);
6759 }
6760 if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)_ast_strlen_zero(ast_config_AST_SYSTEM_NAME, "manager.c", __PRETTY_FUNCTION__
, 6760)
) {
6761 ast_str_append(&buf, 0,
6762 "SystemName: %s\r\n",
6763 ast_config_AST_SYSTEM_NAME);
6764 }
6765
6766 ast_str_append_va(&buf, 0, fmt, ap);
6767 for (i = 0; i < chancount; i++) {
6768 append_channel_vars(&buf, chans[i]);
6769 }
6770
6771 ast_str_append(&buf, 0, "\r\n");
6772
6773 append_event(ast_str_buffer(buf), category);
6774
6775 /* Wake up any sleeping sessions */
6776 if (sessions) {
6777 struct ao2_iterator iter;
6778 struct mansession_session *session;
6779
6780 iter = ao2_iterator_init(sessions, 0);
6781 while ((session = ao2_iterator_next(&iter)__ao2_iterator_next((&iter), "", "manager.c", 6781, __PRETTY_FUNCTION__
)
)) {
6782 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 6782, "session")
;
6783 if (session->waiting_thread != AST_PTHREADT_NULL(pthread_t) -1) {
6784 pthread_kill(session->waiting_thread, SIGURG23);
6785 } else {
6786 /* We have an event to process, but the mansession is
6787 * not waiting for it. We still need to indicate that there
6788 * is an event waiting so that get_input processes the pending
6789 * event instead of polling.
6790 */
6791 session->pending_event = 1;
6792 }
6793 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 6793,
"session")
;
6794 unref_mansession(session);
6795 }
6796 ao2_iterator_destroy(&iter);
6797 }
6798
6799 if (category != EVENT_FLAG_SHUTDOWN-1 && !AST_RWLIST_EMPTY(&manager_hooks)(((&manager_hooks)->first) == ((void*)0))) {
6800 struct manager_custom_hook *hook;
6801
6802 AST_RWLIST_RDLOCK(&manager_hooks)__ast_rwlock_rdlock("manager.c", 6802, __PRETTY_FUNCTION__, &
(&manager_hooks)->lock, "&(&manager_hooks)->lock"
)
;
6803 AST_RWLIST_TRAVERSE(&manager_hooks, hook, list)for((hook) = (&manager_hooks)->first; (hook); (hook) =
(hook)->list.next)
{
6804 hook->helper(category, event, ast_str_buffer(buf));
6805 }
6806 AST_RWLIST_UNLOCK(&manager_hooks)__ast_rwlock_unlock("manager.c", 6806, __PRETTY_FUNCTION__, &
(&manager_hooks)->lock, "&(&manager_hooks)->lock"
)
;
6807 }
6808
6809 return 0;
6810}
6811
6812static int __attribute__((format(printf, 9, 0))) __manager_event_sessions(
6813 struct ao2_container *sessions,
6814 int category,
6815 const char *event,
6816 int chancount,
6817 struct ast_channel **chans,
6818 const char *file,
6819 int line,
6820 const char *func,
6821 const char *fmt,
6822 ...)
6823{
6824 va_list ap;
6825 int res;
6826
6827 va_start(ap, fmt)__builtin_va_start(ap, fmt);
6828 res = __manager_event_sessions_va(sessions, category, event, chancount, chans,
6829 file, line, func, fmt, ap);
6830 va_end(ap)__builtin_va_end(ap);
6831 return res;
6832}
6833
6834int __ast_manager_event_multichan(int category, const char *event, int chancount,
6835 struct ast_channel **chans, const char *file, int line, const char *func,
6836 const char *fmt, ...)
6837{
6838 struct ao2_container *sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 6838
, __PRETTY_FUNCTION__, "mgr_sessions")
;
6839 va_list ap;
6840 int res;
6841
6842 if (!any_manager_listeners(sessions)((sessions && ao2_container_count(sessions)) || !(((&
manager_hooks)->first) == ((void*)0)))
) {
6843 /* Nobody is listening */
6844 ao2_cleanup(sessions)__ao2_cleanup_debug((sessions), "", "manager.c", 6844, __PRETTY_FUNCTION__
)
;
6845 return 0;
6846 }
6847
6848 va_start(ap, fmt)__builtin_va_start(ap, fmt);
6849 res = __manager_event_sessions_va(sessions, category, event, chancount, chans,
6850 file, line, func, fmt, ap);
6851 va_end(ap)__builtin_va_end(ap);
6852 ao2_cleanup(sessions)__ao2_cleanup_debug((sessions), "", "manager.c", 6852, __PRETTY_FUNCTION__
)
;
6853 return res;
6854}
6855
6856/*! \brief
6857 * support functions to register/unregister AMI action handlers,
6858 */
6859int ast_manager_unregister(const char *action)
6860{
6861 struct manager_action *cur;
6862
6863 AST_RWLIST_WRLOCK(&actions)__ast_rwlock_wrlock("manager.c", 6863, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
6864 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&actions, cur, list){ typeof((&actions)) __list_head = &actions; typeof(__list_head
->first) __list_next; typeof(__list_head->first) __list_prev
= ((void*)0); typeof(__list_head->first) __list_current; for
((cur) = __list_head->first, __list_current = (cur), __list_next
= (cur) ? (cur)->list.next : ((void*)0); (cur); __list_prev
= __list_current, (cur) = __list_next, __list_current = (cur
), __list_next = (cur) ? (cur)->list.next : ((void*)0), (void
) __list_prev )
{
6865 if (!strcasecmp(action, cur->action)) {
6866 AST_RWLIST_REMOVE_CURRENT(list)do { __list_current->list.next = ((void*)0); __list_current
= __list_prev; if (__list_prev) { __list_prev->list.next =
__list_next; } else { __list_head->first = __list_next; }
if (!__list_next) { __list_head->last = __list_prev; } } while
(0)
;
6867 break;
6868 }
6869 }
6870 AST_RWLIST_TRAVERSE_SAFE_END};
6871 AST_RWLIST_UNLOCK(&actions)__ast_rwlock_unlock("manager.c", 6871, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
6872
6873 if (cur) {
6874 /*
6875 * We have removed the action object from the container so we
6876 * are no longer in a hurry.
6877 */
6878 ao2_lock(cur)__ao2_lock(cur, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 6878, "cur")
;
6879 cur->registered = 0;
6880 ao2_unlock(cur)__ao2_unlock(cur, "manager.c", __PRETTY_FUNCTION__, 6880, "cur"
)
;
6881
6882 ao2_t_ref(cur, -1, "action object removed from list")__ao2_ref((cur), (-1), ("action object removed from list"), "manager.c"
, 6882, __PRETTY_FUNCTION__)
;
6883 ast_verb(2, "Manager unregistered action %s\n", action)do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 6883, __PRETTY_FUNCTION__, 2, "Manager unregistered action %s\n"
, action); } } while (0)
;
6884 }
6885
6886 return 0;
6887}
6888
6889static int manager_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
6890{
6891 /* Notify managers of change */
6892 char hint[512];
6893
6894 ast_get_hint(hint, sizeof(hint), NULL((void*)0), 0, NULL((void*)0), context, exten);
6895
6896 switch(info->reason) {
6897 case AST_HINT_UPDATE_DEVICE:
6898 manager_event(EVENT_FLAG_CALL, "ExtensionStatus",__ast_manager_event_multichan((1 << 1), "ExtensionStatus"
, 0, ((void*)0), "manager.c", 6908, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %d\r\n" "StatusText: %s\r\n"
, exten, context, hint, info->exten_state, ast_extension_state2str
(info->exten_state))
6899 "Exten: %s\r\n"__ast_manager_event_multichan((1 << 1), "ExtensionStatus"
, 0, ((void*)0), "manager.c", 6908, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %d\r\n" "StatusText: %s\r\n"
, exten, context, hint, info->exten_state, ast_extension_state2str
(info->exten_state))
6900 "Context: %s\r\n"__ast_manager_event_multichan((1 << 1), "ExtensionStatus"
, 0, ((void*)0), "manager.c", 6908, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %d\r\n" "StatusText: %s\r\n"
, exten, context, hint, info->exten_state, ast_extension_state2str
(info->exten_state))
6901 "Hint: %s\r\n"__ast_manager_event_multichan((1 << 1), "ExtensionStatus"
, 0, ((void*)0), "manager.c", 6908, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %d\r\n" "StatusText: %s\r\n"
, exten, context, hint, info->exten_state, ast_extension_state2str
(info->exten_state))
6902 "Status: %d\r\n"__ast_manager_event_multichan((1 << 1), "ExtensionStatus"
, 0, ((void*)0), "manager.c", 6908, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %d\r\n" "StatusText: %s\r\n"
, exten, context, hint, info->exten_state, ast_extension_state2str
(info->exten_state))
6903 "StatusText: %s\r\n",__ast_manager_event_multichan((1 << 1), "ExtensionStatus"
, 0, ((void*)0), "manager.c", 6908, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %d\r\n" "StatusText: %s\r\n"
, exten, context, hint, info->exten_state, ast_extension_state2str
(info->exten_state))
6904 exten,__ast_manager_event_multichan((1 << 1), "ExtensionStatus"
, 0, ((void*)0), "manager.c", 6908, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %d\r\n" "StatusText: %s\r\n"
, exten, context, hint, info->exten_state, ast_extension_state2str
(info->exten_state))
6905 context,__ast_manager_event_multichan((1 << 1), "ExtensionStatus"
, 0, ((void*)0), "manager.c", 6908, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %d\r\n" "StatusText: %s\r\n"
, exten, context, hint, info->exten_state, ast_extension_state2str
(info->exten_state))
6906 hint,__ast_manager_event_multichan((1 << 1), "ExtensionStatus"
, 0, ((void*)0), "manager.c", 6908, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %d\r\n" "StatusText: %s\r\n"
, exten, context, hint, info->exten_state, ast_extension_state2str
(info->exten_state))
6907 info->exten_state,__ast_manager_event_multichan((1 << 1), "ExtensionStatus"
, 0, ((void*)0), "manager.c", 6908, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %d\r\n" "StatusText: %s\r\n"
, exten, context, hint, info->exten_state, ast_extension_state2str
(info->exten_state))
6908 ast_extension_state2str(info->exten_state))__ast_manager_event_multichan((1 << 1), "ExtensionStatus"
, 0, ((void*)0), "manager.c", 6908, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %d\r\n" "StatusText: %s\r\n"
, exten, context, hint, info->exten_state, ast_extension_state2str
(info->exten_state))
;
6909 break;
6910 case AST_HINT_UPDATE_PRESENCE:
6911 manager_event(EVENT_FLAG_CALL, "PresenceStatus",__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6912 "Exten: %s\r\n"__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6913 "Context: %s\r\n"__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6914 "Hint: %s\r\n"__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6915 "Status: %s\r\n"__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6916 "Subtype: %s\r\n"__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6917 "Message: %s\r\n",__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6918 exten,__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6919 context,__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6920 hint,__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6921 ast_presence_state2str(info->presence_state),__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6922 info->presence_subtype,__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
6923 info->presence_message)__ast_manager_event_multichan((1 << 1), "PresenceStatus"
, 0, ((void*)0), "manager.c", 6923, __PRETTY_FUNCTION__, "Exten: %s\r\n"
"Context: %s\r\n" "Hint: %s\r\n" "Status: %s\r\n" "Subtype: %s\r\n"
"Message: %s\r\n" , exten, context, hint, ast_presence_state2str
(info->presence_state), info->presence_subtype, info->
presence_message)
;
6924 break;
6925 }
6926 return 0;
6927}
6928
6929static int ast_manager_register_struct(struct manager_action *act)
6930{
6931 struct manager_action *cur, *prev = NULL((void*)0);
6932
6933 AST_RWLIST_WRLOCK(&actions)__ast_rwlock_wrlock("manager.c", 6933, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
6934 AST_RWLIST_TRAVERSE(&actions, cur, list)for((cur) = (&actions)->first; (cur); (cur) = (cur)->
list.next)
{
6935 int ret;
6936
6937 ret = strcasecmp(cur->action, act->action);
6938 if (ret == 0) {
6939 ast_log(LOG_WARNING3, "manager.c", 6939, __PRETTY_FUNCTION__, "Manager: Action '%s' already registered\n", act->action);
6940 AST_RWLIST_UNLOCK(&actions)__ast_rwlock_unlock("manager.c", 6940, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
6941 return -1;
6942 }
6943 if (ret > 0) { /* Insert these alphabetically */
6944 break;
6945 }
6946 prev = cur;
6947 }
6948
6949 ao2_t_ref(act, +1, "action object added to list")__ao2_ref((act), (+1), ("action object added to list"), "manager.c"
, 6949, __PRETTY_FUNCTION__)
;
6950 act->registered = 1;
6951 if (prev) {
6952 AST_RWLIST_INSERT_AFTER(&actions, prev, act, list)do { (act)->list.next = (prev)->list.next; (prev)->list
.next = (act); if ((&actions)->last == (prev)) (&actions
)->last = (act); } while (0)
;
6953 } else {
6954 AST_RWLIST_INSERT_HEAD(&actions, act, list)do { (act)->list.next = (&actions)->first; (&actions
)->first = (act); if (!(&actions)->last) (&actions
)->last = (act); } while (0)
;
6955 }
6956
6957 ast_verb(2, "Manager registered action %s\n", act->action)do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 6957, __PRETTY_FUNCTION__, 2, "Manager registered action %s\n"
, act->action); } } while (0)
;
6958
6959 AST_RWLIST_UNLOCK(&actions)__ast_rwlock_unlock("manager.c", 6959, __PRETTY_FUNCTION__, &
(&actions)->lock, "&(&actions)->lock")
;
6960
6961 return 0;
6962}
6963
6964/*!
6965 * \internal
6966 * \brief Destroy the registered AMI action object.
6967 *
6968 * \param obj Object to destroy.
6969 *
6970 * \return Nothing
6971 */
6972static void action_destroy(void *obj)
6973{
6974 struct manager_action *doomed = obj;
6975
6976 if (doomed->synopsis) {
6977 /* The string fields were initialized. */
6978 ast_string_field_free_memory(doomed)({ int __res__ = -1; if (((void *)(doomed)) != ((void*)0)) { __res__
= __ast_string_field_free_memory(&(doomed)->__field_mgr
, &(doomed)->__field_mgr_pool, AST_STRINGFIELD_DESTROY
, "manager.c", 6978, __PRETTY_FUNCTION__); } __res__; })
;
6979 }
6980 ao2_cleanup(doomed->final_response)__ao2_cleanup_debug((doomed->final_response), "", "manager.c"
, 6980, __PRETTY_FUNCTION__)
;
6981 ao2_cleanup(doomed->list_responses)__ao2_cleanup_debug((doomed->list_responses), "", "manager.c"
, 6981, __PRETTY_FUNCTION__)
;
6982}
6983
6984/*! \brief register a new command with manager, including online help. This is
6985 the preferred way to register a manager command */
6986int 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)
6987{
6988 struct manager_action *cur;
6989
6990 cur = ao2_t_alloc(sizeof(*cur), action_destroy, action)__ao2_alloc((sizeof(*cur)), (action_destroy), AO2_ALLOC_OPT_LOCK_MUTEX
, (action), "manager.c", 6990, __PRETTY_FUNCTION__)
;
6991 if (!cur) {
6992 return -1;
6993 }
6994 if (ast_string_field_init(cur, 128)({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= __ast_string_field_init(&(cur)->__field_mgr, &(
cur)->__field_mgr_pool, 128, "manager.c", 6994, __PRETTY_FUNCTION__
); } __res__ ; })
) {
6995 ao2_t_ref(cur, -1, "action object creation failed")__ao2_ref((cur), (-1), ("action object creation failed"), "manager.c"
, 6995, __PRETTY_FUNCTION__)
;
6996 return -1;
6997 }
6998
6999 cur->action = action;
7000 cur->authority = auth;
7001 cur->func = func;
7002 cur->module = module;
7003#ifdef AST_XML_DOCS
7004 if (ast_strlen_zero(synopsis)_ast_strlen_zero(synopsis, "manager.c", __PRETTY_FUNCTION__, 7004
)
&& ast_strlen_zero(description)_ast_strlen_zero(description, "manager.c", __PRETTY_FUNCTION__
, 7004)
) {
7005 char *tmpxml;
7006
7007 tmpxml = ast_xmldoc_build_synopsis("manager", action, NULL((void*)0));
7008 ast_string_field_set(cur, synopsis, tmpxml)({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = 0; const char *__d__ = (tmpxml); size_t __dlen__
= (__d__) ? strlen(__d__) + 1 : 1; ast_string_field *__p__ =
(ast_string_field *) (&(cur)->synopsis); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(cur)->__field_mgr, &
(cur)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(cur)->__field_mgr, &(cur)->__field_mgr_pool,
__dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
7009 ast_freefree(tmpxml);
7010
7011 tmpxml = ast_xmldoc_build_syntax("manager", action, NULL((void*)0));
7012 ast_string_field_set(cur, syntax, tmpxml)({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = 0; const char *__d__ = (tmpxml); size_t __dlen__
= (__d__) ? strlen(__d__) + 1 : 1; ast_string_field *__p__ =
(ast_string_field *) (&(cur)->syntax); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(cur)->__field_mgr, &
(cur)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(cur)->__field_mgr, &(cur)->__field_mgr_pool,
__dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
7013 ast_freefree(tmpxml);
7014
7015 tmpxml = ast_xmldoc_build_description("manager", action, NULL((void*)0));
7016 ast_string_field_set(cur, description, tmpxml)({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = 0; const char *__d__ = (tmpxml); size_t __dlen__
= (__d__) ? strlen(__d__) + 1 : 1; ast_string_field *__p__ =
(ast_string_field *) (&(cur)->description); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(cur)->__field_mgr, &
(cur)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(cur)->__field_mgr, &(cur)->__field_mgr_pool,
__dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
7017 ast_freefree(tmpxml);
7018
7019 tmpxml = ast_xmldoc_build_seealso("manager", action, NULL((void*)0));
7020 ast_string_field_set(cur, seealso, tmpxml)({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = 0; const char *__d__ = (tmpxml); size_t __dlen__
= (__d__) ? strlen(__d__) + 1 : 1; ast_string_field *__p__ =
(ast_string_field *) (&(cur)->seealso); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(cur)->__field_mgr, &
(cur)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(cur)->__field_mgr, &(cur)->__field_mgr_pool,
__dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
7021 ast_freefree(tmpxml);
7022
7023 tmpxml = ast_xmldoc_build_arguments("manager", action, NULL((void*)0));
7024 ast_string_field_set(cur, arguments, tmpxml)({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = 0; const char *__d__ = (tmpxml); size_t __dlen__
= (__d__) ? strlen(__d__) + 1 : 1; ast_string_field *__p__ =
(ast_string_field *) (&(cur)->arguments); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(cur)->__field_mgr, &
(cur)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(cur)->__field_mgr, &(cur)->__field_mgr_pool,
__dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
7025 ast_freefree(tmpxml);
7026
7027 cur->final_response = ast_xmldoc_build_final_response("manager", action, NULL((void*)0));
7028 cur->list_responses = ast_xmldoc_build_list_responses("manager", action, NULL((void*)0));
7029
7030 cur->docsrc = AST_XML_DOC;
7031 } else
7032#endif
7033 {
7034 ast_string_field_set(cur, synopsis, synopsis)({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = 0; const char *__d__ = (synopsis); size_t
__dlen__ = (__d__) ? strlen(__d__) + 1 : 1; ast_string_field
*__p__ = (ast_string_field *) (&(cur)->synopsis); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(cur)->__field_mgr, &
(cur)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(cur)->__field_mgr, &(cur)->__field_mgr_pool,
__dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
7035 ast_string_field_set(cur, description, description)({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = -1; if (((void *)(cur)) != ((void*)0)) { __res__
= ({ int __res__ = 0; const char *__d__ = (description); size_t
__dlen__ = (__d__) ? strlen(__d__) + 1 : 1; ast_string_field
*__p__ = (ast_string_field *) (&(cur)->description); ast_string_field
target = *__p__; if (__dlen__ == 1) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = __ast_string_field_empty
; } else if ((__dlen__ <= *((ast_string_field_allocation *
) (*__p__ - __alignof__(ast_string_field_allocation)))) || (!
__ast_string_field_ptr_grow(&(cur)->__field_mgr, &
(cur)->__field_mgr_pool, __dlen__, __p__)) || (target = __ast_string_field_alloc_space
(&(cur)->__field_mgr, &(cur)->__field_mgr_pool,
__dlen__))) { if (target != *__p__) { __ast_string_field_release_active
((cur)->__field_mgr_pool, *__p__); *__p__ = target; } memcpy
(* (void **) __p__, __d__, __dlen__); } else { __res__ = -1; }
__res__; }); } __res__; }); } __res__; })
;
7036#ifdef AST_XML_DOCS
7037 cur->docsrc = AST_STATIC_DOC;
7038#endif
7039 }
7040 if (ast_manager_register_struct(cur)) {
7041 ao2_t_ref(cur, -1, "action object registration failed")__ao2_ref((cur), (-1), ("action object registration failed"),
"manager.c", 7041, __PRETTY_FUNCTION__)
;
7042 return -1;
7043 }
7044
7045 ao2_t_ref(cur, -1, "action object registration successful")__ao2_ref((cur), (-1), ("action object registration successful"
), "manager.c", 7045, __PRETTY_FUNCTION__)
;
7046 return 0;
7047}
7048/*! @}
7049 END Doxygen group */
7050
7051/*
7052 * The following are support functions for AMI-over-http.
7053 * The common entry point is generic_http_callback(),
7054 * which extracts HTTP header and URI fields and reformats
7055 * them into AMI messages, locates a proper session
7056 * (using the mansession_id Cookie or GET variable),
7057 * and calls process_message() as for regular AMI clients.
7058 * When done, the output (which goes to a temporary file)
7059 * is read back into a buffer and reformatted as desired,
7060 * then fed back to the client over the original socket.
7061 */
7062
7063enum output_format {
7064 FORMAT_RAW,
7065 FORMAT_HTML,
7066 FORMAT_XML,
7067};
7068
7069static const char * const contenttype[] = {
7070 [FORMAT_RAW] = "plain",
7071 [FORMAT_HTML] = "html",
7072 [FORMAT_XML] = "xml",
7073};
7074
7075/*!
7076 * locate an http session in the list. The search key (ident) is
7077 * the value of the mansession_id cookie (0 is not valid and means
7078 * a session on the AMI socket).
7079 */
7080static struct mansession_session *find_session(uint32_t ident, int incinuse)
7081{
7082 struct ao2_container *sessions;
7083 struct mansession_session *session;
7084 struct ao2_iterator i;
7085
7086 if (ident == 0) {
7087 return NULL((void*)0);
7088 }
7089
7090 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 7090
, __PRETTY_FUNCTION__, "mgr_sessions")
;
7091 if (!sessions) {
7092 return NULL((void*)0);
7093 }
7094 i = ao2_iterator_init(sessions, 0);
7095 ao2_ref(sessions, -1)__ao2_ref((sessions), (-1), "", "manager.c", 7095, __PRETTY_FUNCTION__
)
;
7096 while ((session = ao2_iterator_next(&i)__ao2_iterator_next((&i), "", "manager.c", 7096, __PRETTY_FUNCTION__
)
)) {
7097 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 7097, "session")
;
7098 if (session->managerid == ident && !session->needdestroy) {
7099 ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
7100 break;
7101 }
7102 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7102,
"session")
;
7103 unref_mansession(session);
7104 }
7105 ao2_iterator_destroy(&i);
7106
7107 return session;
7108}
7109
7110/*!
7111 * locate an http session in the list.
7112 * The search keys (nonce) and (username) is value from received
7113 * "Authorization" http header.
7114 * As well as in find_session() function, the value of the nonce can't be zero.
7115 * (0 meansi, that the session used for AMI socket connection).
7116 * Flag (stale) is set, if client used valid, but old, nonce value.
7117 *
7118 */
7119static struct mansession_session *find_session_by_nonce(const char *username, unsigned long nonce, int *stale)
7120{
7121 struct mansession_session *session;
7122 struct ao2_container *sessions;
7123 struct ao2_iterator i;
7124
7125 if (nonce == 0 || username == NULL((void*)0) || stale == NULL((void*)0)) {
7126 return NULL((void*)0);
7127 }
7128
7129 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 7129
, __PRETTY_FUNCTION__, "mgr_sessions")
;
7130 if (!sessions) {
7131 return NULL((void*)0);
7132 }
7133 i = ao2_iterator_init(sessions, 0);
7134 ao2_ref(sessions, -1)__ao2_ref((sessions), (-1), "", "manager.c", 7134, __PRETTY_FUNCTION__
)
;
7135 while ((session = ao2_iterator_next(&i)__ao2_iterator_next((&i), "", "manager.c", 7135, __PRETTY_FUNCTION__
)
)) {
7136 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 7136, "session")
;
7137 if (!strcasecmp(session->username, username) && session->managerid == nonce) {
7138 *stale = 0;
7139 break;
7140 } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
7141 *stale = 1;
7142 break;
7143 }
7144 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7144,
"session")
;
7145 unref_mansession(session);
7146 }
7147 ao2_iterator_destroy(&i);
7148
7149 return session;
7150}
7151
7152int astman_is_authed(uint32_t ident)
7153{
7154 int authed;
7155 struct mansession_session *session;
7156
7157 if (!(session = find_session(ident, 0)))
7158 return 0;
7159
7160 authed = (session->authenticated != 0);
7161
7162 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7162,
"session")
;
7163 unref_mansession(session);
7164
7165 return authed;
7166}
7167
7168int astman_verify_session_readpermissions(uint32_t ident, int perm)
7169{
7170 int result = 0;
7171 struct mansession_session *session;
7172 struct ao2_container *sessions;
7173 struct ao2_iterator i;
7174
7175 if (ident == 0) {
7176 return 0;
7177 }
7178
7179 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 7179
, __PRETTY_FUNCTION__, "mgr_sessions")
;
7180 if (!sessions) {
7181 return 0;
7182 }
7183 i = ao2_iterator_init(sessions, 0);
7184 ao2_ref(sessions, -1)__ao2_ref((sessions), (-1), "", "manager.c", 7184, __PRETTY_FUNCTION__
)
;
7185 while ((session = ao2_iterator_next(&i)__ao2_iterator_next((&i), "", "manager.c", 7185, __PRETTY_FUNCTION__
)
)) {
7186 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 7186, "session")
;
7187 if ((session->managerid == ident) && (session->readperm & perm)) {
7188 result = 1;
7189 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7189,
"session")
;
7190 unref_mansession(session);
7191 break;
7192 }
7193 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7193,
"session")
;
7194 unref_mansession(session);
7195 }
7196 ao2_iterator_destroy(&i);
7197
7198 return result;
7199}
7200
7201int astman_verify_session_writepermissions(uint32_t ident, int perm)
7202{
7203 int result = 0;
7204 struct mansession_session *session;
7205 struct ao2_container *sessions;
7206 struct ao2_iterator i;
7207
7208 if (ident == 0) {
7209 return 0;
7210 }
7211
7212 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 7212
, __PRETTY_FUNCTION__, "mgr_sessions")
;
7213 if (!sessions) {
7214 return 0;
7215 }
7216 i = ao2_iterator_init(sessions, 0);
7217 ao2_ref(sessions, -1)__ao2_ref((sessions), (-1), "", "manager.c", 7217, __PRETTY_FUNCTION__
)
;
7218 while ((session = ao2_iterator_next(&i)__ao2_iterator_next((&i), "", "manager.c", 7218, __PRETTY_FUNCTION__
)
)) {
7219 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 7219, "session")
;
7220 if ((session->managerid == ident) && (session->writeperm & perm)) {
7221 result = 1;
7222 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7222,
"session")
;
7223 unref_mansession(session);
7224 break;
7225 }
7226 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7226,
"session")
;
7227 unref_mansession(session);
7228 }
7229 ao2_iterator_destroy(&i);
7230
7231 return result;
7232}
7233
7234/*
7235 * convert to xml with various conversion:
7236 * mode & 1 -> lowercase;
7237 * mode & 2 -> replace non-alphanumeric chars with underscore
7238 */
7239static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
7240{
7241 /* store in a local buffer to avoid calling ast_str_append too often */
7242 char buf[256];
7243 char *dst = buf;
7244 int space = sizeof(buf);
7245 /* repeat until done and nothing to flush */
7246 for ( ; *src || dst != buf ; src++) {
7247 if (*src == '\0' || space < 10) { /* flush */
7248 *dst++ = '\0';
7249 ast_str_append(out, 0, "%s", buf);
7250 dst = buf;
7251 space = sizeof(buf);
7252 if (*src == '\0') {
7253 break;
7254 }
7255 }
7256
7257 if ( (mode & 2) && !isalnum(*src)((*__ctype_b_loc ())[(int) ((*src))] & (unsigned short int
) _ISalnum)
) {
7258 *dst++ = '_';
7259 space--;
7260 continue;
7261 }
7262 switch (*src) {
7263 case '<':
7264 strcpy(dst, "&lt;");
7265 dst += 4;
7266 space -= 4;
7267 break;
7268 case '>':
7269 strcpy(dst, "&gt;");
7270 dst += 4;
7271 space -= 4;
7272 break;
7273 case '\"':
7274 strcpy(dst, "&quot;");
7275 dst += 6;
7276 space -= 6;
7277 break;
7278 case '\'':
7279 strcpy(dst, "&apos;");
7280 dst += 6;
7281 space -= 6;
7282 break;
7283 case '&':
7284 strcpy(dst, "&amp;");
7285 dst += 5;
7286 space -= 5;
7287 break;
7288
7289 default:
7290 *dst++ = mode ? tolower(*src)(__extension__ ({ int __res; if (sizeof (*src) > 1) { if (
__builtin_constant_p (*src)) { int __c = (*src); __res = __c <
-128 || __c > 255 ? __c : (*__ctype_tolower_loc ())[__c];
} else __res = tolower (*src); } else __res = (*__ctype_tolower_loc
())[(int) (*src)]; __res; }))
: *src;
7291 space--;
7292 }
7293 }
7294}
7295
7296struct variable_count {
7297 char *varname;
7298 int count;
7299};
7300
7301static int variable_count_hash_fn(const void *vvc, const int flags)
7302{
7303 const struct variable_count *vc = vvc;
7304
7305 return ast_str_hash(vc->varname);
7306}
7307
7308static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
7309{
7310 /* Due to the simplicity of struct variable_count, it makes no difference
7311 * if you pass in objects or strings, the same operation applies. This is
7312 * due to the fact that the hash occurs on the first element, which means
7313 * the address of both the struct and the string are exactly the same. */
7314 struct variable_count *vc = obj;
7315 char *str = vstr;
7316 return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
7317}
7318
7319/*! \brief Convert the input into XML or HTML.
7320 * The input is supposed to be a sequence of lines of the form
7321 * Name: value
7322 * optionally followed by a blob of unformatted text.
7323 * A blank line is a section separator. Basically, this is a
7324 * mixture of the format of Manager Interface and CLI commands.
7325 * The unformatted text is considered as a single value of a field
7326 * named 'Opaque-data'.
7327 *
7328 * At the moment the output format is the following (but it may
7329 * change depending on future requirements so don't count too
7330 * much on it when writing applications):
7331 *
7332 * General: the unformatted text is used as a value of
7333 * XML output: to be completed
7334 *
7335 * \verbatim
7336 * Each section is within <response type="object" id="xxx">
7337 * where xxx is taken from ajaxdest variable or defaults to unknown
7338 * Each row is reported as an attribute Name="value" of an XML
7339 * entity named from the variable ajaxobjtype, default to "generic"
7340 * \endverbatim
7341 *
7342 * HTML output:
7343 * each Name-value pair is output as a single row of a two-column table.
7344 * Sections (blank lines in the input) are separated by a <HR>
7345 *
7346 */
7347static void xml_translate(struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
7348{
7349 struct ast_variable *v;
7350 const char *dest = NULL((void*)0);
7351 char *var, *val;
7352 const char *objtype = NULL((void*)0);
7353 int in_data = 0; /* parsing data */
7354 int inobj = 0;
7355 int xml = (format == FORMAT_XML);
7356 struct variable_count *vc = NULL((void*)0);
7357 struct ao2_container *vco = NULL((void*)0);
7358
7359 if (xml) {
7360 /* dest and objtype need only for XML format */
7361 for (v = get_vars; v; v = v->next) {
7362 if (!strcasecmp(v->name, "ajaxdest")) {
7363 dest = v->value;
7364 } else if (!strcasecmp(v->name, "ajaxobjtype")) {
7365 objtype = v->value;
7366 }
7367 }
7368 if (ast_strlen_zero(dest)_ast_strlen_zero(dest, "manager.c", __PRETTY_FUNCTION__, 7368
)
) {
7369 dest = "unknown";
7370 }
7371 if (ast_strlen_zero(objtype)_ast_strlen_zero(objtype, "manager.c", __PRETTY_FUNCTION__, 7371
)
) {
7372 objtype = "generic";
7373 }
7374 }
7375
7376 /* we want to stop when we find an empty line */
7377 while (in && *in) {
7378 val = strsep(&in, "\r\n"); /* mark start and end of line */
7379 if (in && *in == '\n') { /* remove trailing \n if any */
7380 in++;
7381 }
7382 ast_trim_blanks(val);
7383 ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val)do { if ((option_debug >= (5) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (5)))) { ast_log(0,
"manager.c", 7383, __PRETTY_FUNCTION__, "inobj %d in_data %d line <%s>\n"
, inobj, in_data, val); } } while (0)
;
7384 if (ast_strlen_zero(val)_ast_strlen_zero(val, "manager.c", __PRETTY_FUNCTION__, 7384)) {
7385 /* empty line */
7386 if (in_data) {
7387 /* close data in Opaque mode */
7388 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
7389 in_data = 0;
7390 }
7391
7392 if (inobj) {
7393 /* close block */
7394 ast_str_append(out, 0, xml ? " /></response>\n" :
7395 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
7396 inobj = 0;
7397 ao2_ref(vco, -1)__ao2_ref((vco), (-1), "", "manager.c", 7397, __PRETTY_FUNCTION__
)
;
7398 vco = NULL((void*)0);
7399 }
7400 continue;
7401 }
7402
7403 if (!inobj) {
7404 /* start new block */
7405 if (xml) {
7406 ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
7407 }
7408 vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn)__ao2_container_alloc_hash(((AO2_ALLOC_OPT_LOCK_MUTEX)), (0),
(((37))), (((variable_count_hash_fn))), (((void*)0)), (((variable_count_cmp_fn
))), "", "manager.c", 7408, __PRETTY_FUNCTION__)
;
7409 inobj = 1;
7410 }
7411
7412 if (in_data) {
7413 /* Process data field in Opaque mode. This is a
7414 * followup, so we re-add line feeds. */
7415 ast_str_append(out, 0, xml ? "\n" : "<br>\n");
7416 xml_copy_escape(out, val, 0); /* data field */
7417 continue;
7418 }
7419
7420 /* We expect "Name: value" line here */
7421 var = strsep(&val, ":");
7422 if (val) {
7423 /* found the field name */
7424 val = ast_skip_blanks(val);
7425 ast_trim_blanks(var);
7426 } else {
7427 /* field name not found, switch to opaque mode */
7428 val = var;
7429 var = "Opaque-data";
7430 in_data = 1;
7431 }
7432
7433
7434 ast_str_append(out, 0, xml ? " " : "<tr><td>");
7435 if ((vc = ao2_find(vco, var, 0)__ao2_find((vco), (var), (0), "", "manager.c", 7435, __PRETTY_FUNCTION__
)
)) {
7436 vc->count++;
7437 } else {
7438 /* Create a new entry for this one */
7439 vc = ao2_alloc(sizeof(*vc), NULL)__ao2_alloc((sizeof(*vc)), (((void*)0)), AO2_ALLOC_OPT_LOCK_MUTEX
, "", "manager.c", 7439, __PRETTY_FUNCTION__)
;
7440 vc->varname = var;
7441 vc->count = 1;
7442 ao2_link(vco, vc)__ao2_link((vco), (vc), 0, "", "manager.c", 7442, __PRETTY_FUNCTION__
)
;
7443 }
7444
7445 xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
7446 if (vc->count > 1) {
7447 ast_str_append(out, 0, "-%d", vc->count);
7448 }
7449 ao2_ref(vc, -1)__ao2_ref((vc), (-1), "", "manager.c", 7449, __PRETTY_FUNCTION__
)
;
7450 ast_str_append(out, 0, xml ? "='" : "</td><td>");
7451 xml_copy_escape(out, val, 0); /* data field */
7452 if (!in_data || !*in) {
7453 ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
7454 }
7455 }
7456
7457 if (inobj) {
7458 ast_str_append(out, 0, xml ? " /></response>\n" :
7459 "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
7460 ao2_ref(vco, -1)__ao2_ref((vco), (-1), "", "manager.c", 7460, __PRETTY_FUNCTION__
)
;
7461 }
7462}
7463
7464static void close_mansession_file(struct mansession *s)
7465{
7466 if (s->f) {
7467 if (fclose(s->f)) {
7468 ast_log(LOG_ERROR4, "manager.c", 7468, __PRETTY_FUNCTION__, "fclose() failed: %s\n", strerror(errno(*__errno_location ())));
7469 }
7470 s->f = NULL((void*)0);
7471 s->fd = -1;
7472 } else if (s->fd != -1) {
7473 /*
7474 * Issuing shutdown() is necessary here to avoid a race
7475 * condition where the last data written may not appear
7476 * in the TCP stream. See ASTERISK-23548
7477 */
7478 shutdown(s->fd, SHUT_RDWRSHUT_RDWR);
7479 if (close(s->fd)) {
7480 ast_log(LOG_ERROR4, "manager.c", 7480, __PRETTY_FUNCTION__, "close() failed: %s\n", strerror(errno(*__errno_location ())));
7481 }
7482 s->fd = -1;
7483 } else {
7484 ast_log(LOG_ERROR4, "manager.c", 7484, __PRETTY_FUNCTION__, "Attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n");
7485 }
7486}
7487
7488static void process_output(struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
7489{
7490 char *buf;
7491 size_t l;
7492
7493 if (!s->f)
7494 return;
7495
7496 /* Ensure buffer is NULL-terminated */
7497 fprintf(s->f, "%c", 0);
7498 fflush(s->f);
7499
7500 if ((l = ftell(s->f)) > 0) {
7501 if (MAP_FAILED((void *) -1) == (buf = mmap(NULL((void*)0), l, PROT_READ0x1 | PROT_WRITE0x2, MAP_PRIVATE0x02, s->fd, 0))) {
7502 ast_log(LOG_WARNING3, "manager.c", 7502, __PRETTY_FUNCTION__, "mmap failed. Manager output was not processed\n");
7503 } else {
7504 if (format == FORMAT_XML || format == FORMAT_HTML) {
7505 xml_translate(out, buf, params, format);
7506 } else {
7507 ast_str_append(out, 0, "%s", buf);
7508 }
7509 munmap(buf, l);
7510 }
7511 } else if (format == FORMAT_XML || format == FORMAT_HTML) {
7512 xml_translate(out, "", params, format);
7513 }
7514
7515 close_mansession_file(s);
7516}
7517
7518static int generic_http_callback(struct ast_tcptls_session_instance *ser,
7519 enum ast_http_method method,
7520 enum output_format format,
7521 const struct ast_sockaddr *remote_address, const char *uri,
7522 struct ast_variable *get_params,
7523 struct ast_variable *headers)
7524{
7525 struct mansession s = { .session = NULL((void*)0), .tcptls_session = ser };
7526 struct mansession_session *session = NULL((void*)0);
7527 uint32_t ident;
7528 int blastaway = 0;
7529 struct ast_variable *v;
7530 struct ast_variable *params = get_params;
7531 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
7532 struct ast_str *http_header = NULL((void*)0), *out = NULL((void*)0);
7533 struct message m = { 0 };
7534 unsigned int idx;
7535 size_t hdrlen;
7536
7537 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
7538 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
7539 return 0;
7540 }
7541
7542 ident = ast_http_manid_from_vars(headers);
7543
7544 if (!(session = find_session(ident, 1))) {
7545
7546 /**/
7547 /* Create new session.
7548 * While it is not in the list we don't need any locking
7549 */
7550 if (!(session = build_mansession(remote_address))) {
7551 ast_http_request_close_on_completion(ser);
7552 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
7553 return 0;
7554 }
7555 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 7555, "session")
;
7556 session->send_events = 0;
7557 session->inuse = 1;
7558 /*!
7559 * \note There is approximately a 1 in 1.8E19 chance that the following
7560 * calculation will produce 0, which is an invalid ID, but due to the
7561 * properties of the rand() function (and the constantcy of s), that
7562 * won't happen twice in a row.
7563 */
7564 while ((session->managerid = ast_random() ^ (unsigned long) session) == 0) {
7565 }
7566 session->last_ev = grab_last();
7567 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores){ (&session->datastores)->first = ((void*)0); (&
session->datastores)->last = ((void*)0); }
;
7568 }
7569 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7569,
"session")
;
7570
7571 http_header = ast_str_create(128);
7572 out = ast_str_create(2048);
7573
7574 ast_mutex_init(&s.lock)__ast_pthread_mutex_init(1, "manager.c", 7574, __PRETTY_FUNCTION__
, "&s.lock", &s.lock)
;
7575
7576 if (http_header == NULL((void*)0) || out == NULL((void*)0)) {
7577 ast_http_request_close_on_completion(ser);
7578 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)");
7579 goto generic_callback_out;
7580 }
7581
7582 s.session = session;
7583 s.fd = mkstemp(template); /* create a temporary file for command output */
7584 unlink(template);
7585 if (s.fd <= -1) {
7586 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)");
7587 goto generic_callback_out;
7588 }
7589 s.f = fdopen(s.fd, "w+");
7590 if (!s.f) {
7591 ast_log(LOG_WARNING3, "manager.c", 7591, __PRETTY_FUNCTION__, "HTTP Manager, fdopen failed: %s!\n", strerror(errno(*__errno_location ())));
7592 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)");
7593 close(s.fd);
7594 goto generic_callback_out;
7595 }
7596
7597 if (method == AST_HTTP_POST) {
7598 params = ast_http_get_post_vars(ser, headers);
7599 if (!params) {
7600 switch (errno(*__errno_location ())) {
7601 case EFBIG27:
7602 ast_http_error(ser, 413, "Request Entity Too Large", "Body too large");
7603 close_mansession_file(&s);
7604 goto generic_callback_out;
7605 case ENOMEM12:
7606 ast_http_request_close_on_completion(ser);
7607 ast_http_error(ser, 500, "Server Error", "Out of memory");
7608 close_mansession_file(&s);
7609 goto generic_callback_out;
7610 case EIO5:
7611 ast_http_error(ser, 400, "Bad Request", "Error parsing request body");
7612 close_mansession_file(&s);
7613 goto generic_callback_out;
7614 }
7615 }
7616 }
7617
7618 for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers)(size_t) (sizeof(m.headers) / sizeof(0[m.headers])); v = v->next) {
7619 hdrlen = strlen(v->name) + strlen(v->value) + 3;
7620 m.headers[m.hdrcount] = ast_malloc(hdrlen)_ast_malloc((hdrlen), "manager.c", 7620, __PRETTY_FUNCTION__);
7621 if (!m.headers[m.hdrcount]) {
7622 /* Allocation failure */
7623 continue;
7624 }
7625 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
7626 ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount])do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 7626, __PRETTY_FUNCTION__, "HTTP Manager add header %s\n"
, m.headers[m.hdrcount]); } } while (0)
;
7627 ++m.hdrcount;
7628 }
7629
7630 if (process_message(&s, &m)) {
7631 if (session->authenticated) {
7632 if (manager_displayconnects(session)) {
7633 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr))do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 7633, __PRETTY_FUNCTION__, 2, "HTTP Manager '%s' logged off from %s\n"
, session->username, ast_sockaddr_stringify_addr(&session
->addr)); } } while (0)
;
7634 }
7635 } else {
7636 if (displayconnects) {
7637 ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_sockaddr_stringify_addr(&session->addr))do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 7637, __PRETTY_FUNCTION__, 2, "HTTP Connect attempt from '%s' unable to authenticate\n"
, ast_sockaddr_stringify_addr(&session->addr)); } } while
(0)
;
7638 }
7639 }
7640 session->needdestroy = 1;
7641 }
7642
7643 /* Free request headers. */
7644 for (idx = 0; idx < m.hdrcount; ++idx) {
7645 ast_freefree((void *) m.headers[idx]);
7646 m.headers[idx] = NULL((void*)0);
7647 }
7648
7649 ast_str_append(&http_header, 0,
7650 "Content-type: text/%s\r\n"
7651 "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
7652 "Pragma: SuppressEvents\r\n",
7653 contenttype[format],
7654 session->managerid, httptimeout);
7655
7656 if (format == FORMAT_XML) {
7657 ast_str_append(&out, 0, "<ajax-response>\n");
7658 } else if (format == FORMAT_HTML) {
7659 /*
7660 * When handling AMI-over-HTTP in HTML format, we provide a simple form for
7661 * debugging purposes. This HTML code should not be here, we
7662 * should read from some config file...
7663 */
7664
7665#define ROW_FMT"<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n" "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
7666#define TEST_STRING"<form action=\"manager\" method=\"post\">\n Action: <select name=\"action\">\n <option value=\"\">-----&gt;</option>\n <option value=\"login\">login</option>\n <option value=\"command\">Command</option>\n <option value=\"waitevent\">waitevent</option>\n <option value=\"listcommands\">listcommands</option>\n </select>\n or <input name=\"action\"><br/>\n CLI Command <input name=\"command\"><br>\n user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n <input type=\"submit\">\n</form>\n" \
7667 "<form action=\"manager\" method=\"post\">\n\
7668 Action: <select name=\"action\">\n\
7669 <option value=\"\">-----&gt;</option>\n\
7670 <option value=\"login\">login</option>\n\
7671 <option value=\"command\">Command</option>\n\
7672 <option value=\"waitevent\">waitevent</option>\n\
7673 <option value=\"listcommands\">listcommands</option>\n\
7674 </select>\n\
7675 or <input name=\"action\"><br/>\n\
7676 CLI Command <input name=\"command\"><br>\n\
7677 user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
7678 <input type=\"submit\">\n</form>\n"
7679
7680 ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
7681 ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
7682 ast_str_append(&out, 0, ROW_FMT"<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n", "<h1>Manager Tester</h1>");
7683 ast_str_append(&out, 0, ROW_FMT"<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n", TEST_STRING"<form action=\"manager\" method=\"post\">\n Action: <select name=\"action\">\n <option value=\"\">-----&gt;</option>\n <option value=\"login\">login</option>\n <option value=\"command\">Command</option>\n <option value=\"waitevent\">waitevent</option>\n <option value=\"listcommands\">listcommands</option>\n </select>\n or <input name=\"action\"><br/>\n CLI Command <input name=\"command\"><br>\n user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n <input type=\"submit\">\n</form>\n");
7684 }
7685
7686 process_output(&s, &out, params, format);
7687
7688 if (format == FORMAT_XML) {
7689 ast_str_append(&out, 0, "</ajax-response>\n");
7690 } else if (format == FORMAT_HTML) {
7691 ast_str_append(&out, 0, "</table></body>\r\n");
7692 }
7693
7694 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 7694, "session")
;
7695 /* Reset HTTP timeout. If we're not authenticated, keep it extremely short */
7696 session->sessiontimeout = time(NULL((void*)0)) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
7697
7698 if (session->needdestroy) {
7699 if (session->inuse == 1) {
7700 ast_debug(1, "Need destroy, doing it now!\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 7700, __PRETTY_FUNCTION__, "Need destroy, doing it now!\n"
); } } while (0)
;
7701 blastaway = 1;
7702 } else {
7703 ast_debug(1, "Need destroy, but can't do it yet!\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 7703, __PRETTY_FUNCTION__, "Need destroy, but can't do it yet!\n"
); } } while (0)
;
7704 if (session->waiting_thread != AST_PTHREADT_NULL(pthread_t) -1) {
7705 pthread_kill(session->waiting_thread, SIGURG23);
7706 }
7707 session->inuse--;
7708 }
7709 } else {
7710 session->inuse--;
7711 }
7712 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7712,
"session")
;
7713
7714 ast_http_send(ser, method, 200, NULL((void*)0), http_header, out, 0, 0);
7715 http_header = NULL((void*)0);
7716 out = NULL((void*)0);
7717
7718generic_callback_out:
7719 ast_mutex_destroy(&s.lock)__ast_pthread_mutex_destroy("manager.c", 7719, __PRETTY_FUNCTION__
, "&s.lock", &s.lock)
;
7720
7721 /* Clear resource */
7722
7723 if (method == AST_HTTP_POST && params) {
7724 ast_variables_destroy(params);
7725 }
7726 ast_freefree(http_header);
7727 ast_freefree(out);
7728
7729 if (session) {
7730 if (blastaway) {
7731 session_destroy(session);
7732 } else {
7733 if (session->f) {
7734 fclose(session->f);
7735 session->f = NULL((void*)0);
7736 }
7737 unref_mansession(session);
7738 }
7739 }
7740
7741 return 0;
7742}
7743
7744static int auth_http_callback(struct ast_tcptls_session_instance *ser,
7745 enum ast_http_method method,
7746 enum output_format format,
7747 const struct ast_sockaddr *remote_address, const char *uri,
7748 struct ast_variable *get_params,
7749 struct ast_variable *headers)
7750{
7751 struct mansession_session *session = NULL((void*)0);
7752 struct mansession s = { .session = NULL((void*)0), .tcptls_session = ser };
7753 struct ast_variable *v, *params = get_params;
7754 char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
7755 struct ast_str *http_header = NULL((void*)0), *out = NULL((void*)0);
7756 size_t result_size;
7757 struct message m = { 0 };
7758 unsigned int idx;
7759 size_t hdrlen;
7760
7761 time_t time_now = time(NULL((void*)0));
7762 unsigned long nonce = 0, nc;
7763 struct ast_http_digest d = { NULL((void*)0), };
7764 struct ast_manager_user *user = NULL((void*)0);
7765 int stale = 0;
7766 char resp_hash[256]="";
7767 /* Cache for user data */
7768 char u_username[80];
7769 int u_readperm;
7770 int u_writeperm;
7771 int u_writetimeout;
7772 int u_displayconnects;
7773
7774 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
7775 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
7776 return 0;
7777 }
7778
7779 /* Find "Authorization: " header */
7780 for (v = headers; v; v = v->next) {
7781 if (!strcasecmp(v->name, "Authorization")) {
7782 break;
7783 }
7784 }
7785
7786 if (!v || ast_strlen_zero(v->value)_ast_strlen_zero(v->value, "manager.c", __PRETTY_FUNCTION__
, 7786)
) {
7787 goto out_401; /* Authorization Header not present - send auth request */
7788 }
7789
7790 /* Digest found - parse */
7791 if (ast_string_field_init(&d, 128)({ int __res__ = -1; if (((void *)(&d)) != ((void*)0)) { __res__
= __ast_string_field_init(&(&d)->__field_mgr, &
(&d)->__field_mgr_pool, 128, "manager.c", 7791, __PRETTY_FUNCTION__
); } __res__ ; })
) {
7792 ast_http_request_close_on_completion(ser);
7793 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
7794 return 0;
7795 }
7796
7797 if (ast_parse_digest(v->value, &d, 0, 1)) {
7798 /* Error in Digest - send new one */
7799 nonce = 0;
7800 goto out_401;
7801 }
7802 if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
7803 ast_log(LOG_WARNING3, "manager.c", 7803, __PRETTY_FUNCTION__, "Received incorrect nonce in Digest <%s>\n", d.nonce);
7804 nonce = 0;
7805 goto out_401;
7806 }
7807
7808 AST_RWLIST_WRLOCK(&users)__ast_rwlock_wrlock("manager.c", 7808, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
7809 user = get_manager_by_name_locked(d.username);
7810 if(!user) {
7811 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 7811, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
7812 ast_log(LOG_NOTICE2, "manager.c", 7812, __PRETTY_FUNCTION__, "%s tried to authenticate with nonexistent user '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
7813 nonce = 0;
7814 goto out_401;
7815 }
7816
7817 /* --- We have User for this auth, now check ACL */
7818 if (user->acl && !ast_apply_acl(user->acl, remote_address, "Manager User ACL:")) {
7819 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 7819, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
7820 ast_log(LOG_NOTICE2, "manager.c", 7820, __PRETTY_FUNCTION__, "%s failed to pass IP ACL as '%s'\n", ast_sockaddr_stringify_addr(&session->addr), d.username);
7821 ast_http_request_close_on_completion(ser);
7822 ast_http_error(ser, 403, "Permission denied", "Permission denied");
7823 return 0;
7824 }
7825
7826 /* --- We have auth, so check it */
7827
7828 /* compute the expected response to compare with what we received */
7829 {
7830 char a2[256];
7831 char a2_hash[256];
7832 char resp[256];
7833
7834 /* XXX Now request method are hardcoded in A2 */
7835 snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
7836 ast_md5_hash(a2_hash, a2);
7837
7838 if (d.qop) {
7839 /* RFC 2617 */
7840 snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
7841 } else {
7842 /* RFC 2069 */
7843 snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
7844 }
7845 ast_md5_hash(resp_hash, resp);
7846 }
7847
7848 if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
7849 /* Something was wrong, so give the client to try with a new challenge */
7850 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 7850, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
7851 nonce = 0;
7852 goto out_401;
7853 }
7854
7855 /*
7856 * User are pass Digest authentication.
7857 * Now, cache the user data and unlock user list.
7858 */
7859 ast_copy_string(u_username, user->username, sizeof(u_username));
7860 u_readperm = user->readperm;
7861 u_writeperm = user->writeperm;
7862 u_displayconnects = user->displayconnects;
7863 u_writetimeout = user->writetimeout;
7864 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 7864, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
7865
7866 if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
7867 /*
7868 * Create new session.
7869 * While it is not in the list we don't need any locking
7870 */
7871 if (!(session = build_mansession(remote_address))) {
7872 ast_http_request_close_on_completion(ser);
7873 ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)");
7874 return 0;
7875 }
7876 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 7876, "session")
;
7877
7878 ast_copy_string(session->username, u_username, sizeof(session->username));
7879 session->managerid = nonce;
7880 session->last_ev = grab_last();
7881 AST_LIST_HEAD_INIT_NOLOCK(&session->datastores){ (&session->datastores)->first = ((void*)0); (&
session->datastores)->last = ((void*)0); }
;
7882
7883 session->readperm = u_readperm;
7884 session->writeperm = u_writeperm;
7885 session->writetimeout = u_writetimeout;
7886
7887 if (u_displayconnects) {
7888 ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr))do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 7888, __PRETTY_FUNCTION__, 2, "HTTP Manager '%s' logged in from %s\n"
, session->username, ast_sockaddr_stringify_addr(&session
->addr)); } } while (0)
;
7889 }
7890 session->noncetime = session->sessionstart = time_now;
7891 session->authenticated = 1;
7892 } else if (stale) {
7893 /*
7894 * Session found, but nonce is stale.
7895 *
7896 * This could be because an old request (w/old nonce) arrived.
7897 *
7898 * This may be as the result of http proxy usage (separate delay or
7899 * multipath) or in a situation where a page was refreshed too quickly
7900 * (seen in Firefox).
7901 *
7902 * In this situation, we repeat the 401 auth with the current nonce
7903 * value.
7904 */
7905 nonce = session->managerid;
7906 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7906,
"session")
;
7907 stale = 1;
7908 goto out_401;
7909 } else {
7910 sscanf(d.nc, "%30lx", &nc);
7911 if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
7912 /*
7913 * Nonce time expired (> 2 minutes) or something wrong with nonce
7914 * counter.
7915 *
7916 * Create new nonce key and resend Digest auth request. Old nonce
7917 * is saved for stale checking...
7918 */
7919 session->nc = 0; /* Reset nonce counter */
7920 session->oldnonce = session->managerid;
7921 nonce = session->managerid = ast_random();
7922 session->noncetime = time_now;
7923 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7923,
"session")
;
7924 stale = 1;
7925 goto out_401;
7926 } else {
7927 session->nc = nc; /* All OK, save nonce counter */
7928 }
7929 }
7930
7931
7932 /* Reset session timeout. */
7933 session->sessiontimeout = time(NULL((void*)0)) + (httptimeout > 5 ? httptimeout : 5);
7934 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 7934,
"session")
;
7935
7936 ast_mutex_init(&s.lock)__ast_pthread_mutex_init(1, "manager.c", 7936, __PRETTY_FUNCTION__
, "&s.lock", &s.lock)
;
7937 s.session = session;
7938 s.fd = mkstemp(template); /* create a temporary file for command output */
7939 unlink(template);
7940 if (s.fd <= -1) {
7941 ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)");
7942 goto auth_callback_out;
7943 }
7944 s.f = fdopen(s.fd, "w+");
7945 if (!s.f) {
7946 ast_log(LOG_WARNING3, "manager.c", 7946, __PRETTY_FUNCTION__, "HTTP Manager, fdopen failed: %s!\n", strerror(errno(*__errno_location ())));
7947 ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)");
7948 close(s.fd);
7949 goto auth_callback_out;
7950 }
7951
7952 if (method == AST_HTTP_POST) {
7953 params = ast_http_get_post_vars(ser, headers);
7954 if (!params) {
7955 switch (errno(*__errno_location ())) {
7956 case EFBIG27:
7957 ast_http_error(ser, 413, "Request Entity Too Large", "Body too large");
7958 close_mansession_file(&s);
7959 goto auth_callback_out;
7960 case ENOMEM12:
7961 ast_http_request_close_on_completion(ser);
7962 ast_http_error(ser, 500, "Server Error", "Out of memory");
7963 close_mansession_file(&s);
7964 goto auth_callback_out;
7965 case EIO5:
7966 ast_http_error(ser, 400, "Bad Request", "Error parsing request body");
7967 close_mansession_file(&s);
7968 goto auth_callback_out;
7969 }
7970 }
7971 }
7972
7973 for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers)(size_t) (sizeof(m.headers) / sizeof(0[m.headers])); v = v->next) {
7974 hdrlen = strlen(v->name) + strlen(v->value) + 3;
7975 m.headers[m.hdrcount] = ast_malloc(hdrlen)_ast_malloc((hdrlen), "manager.c", 7975, __PRETTY_FUNCTION__);
7976 if (!m.headers[m.hdrcount]) {
7977 /* Allocation failure */
7978 continue;
7979 }
7980 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
7981 ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount])do { if (((4) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 7981, __PRETTY_FUNCTION__, 4, "HTTP Manager add header %s\n"
, m.headers[m.hdrcount]); } } while (0)
;
7982 ++m.hdrcount;
7983 }
7984
7985 if (process_message(&s, &m)) {
7986 if (u_displayconnects) {
7987 ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr))do { if (((2) <= ast_verb_sys_level) ) { __ast_verbose("manager.c"
, 7987, __PRETTY_FUNCTION__, 2, "HTTP Manager '%s' logged off from %s\n"
, session->username, ast_sockaddr_stringify_addr(&session
->addr)); } } while (0)
;
7988 }
7989
7990 session->needdestroy = 1;
7991 }
7992
7993 /* Free request headers. */
7994 for (idx = 0; idx < m.hdrcount; ++idx) {
7995 ast_freefree((void *) m.headers[idx]);
7996 m.headers[idx] = NULL((void*)0);
7997 }
7998
7999 result_size = ftell(s.f); /* Calculate approx. size of result */
8000
8001 http_header = ast_str_create(80);
8002 out = ast_str_create(result_size * 2 + 512);
8003 if (http_header == NULL((void*)0) || out == NULL((void*)0)) {
8004 ast_http_request_close_on_completion(ser);
8005 ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)");
8006 close_mansession_file(&s);
8007 goto auth_callback_out;
8008 }
8009
8010 ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]);
8011
8012 if (format == FORMAT_XML) {
8013 ast_str_append(&out, 0, "<ajax-response>\n");
8014 } else if (format == FORMAT_HTML) {
8015 ast_str_append(&out, 0,
8016 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
8017 "<html><head>\r\n"
8018 "<title>Asterisk&trade; Manager Interface</title>\r\n"
8019 "</head><body style=\"background-color: #ffffff;\">\r\n"
8020 "<form method=\"POST\">\r\n"
8021 "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
8022 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
8023 "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
8024 "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
8025 }
8026
8027 process_output(&s, &out, params, format);
8028
8029 if (format == FORMAT_XML) {
8030 ast_str_append(&out, 0, "</ajax-response>\n");
8031 } else if (format == FORMAT_HTML) {
8032 ast_str_append(&out, 0, "</table></form></body></html>\r\n");
8033 }
8034
8035 ast_http_send(ser, method, 200, NULL((void*)0), http_header, out, 0, 0);
8036 http_header = NULL((void*)0);
8037 out = NULL((void*)0);
8038
8039auth_callback_out:
8040 ast_mutex_destroy(&s.lock)__ast_pthread_mutex_destroy("manager.c", 8040, __PRETTY_FUNCTION__
, "&s.lock", &s.lock)
;
8041
8042 /* Clear resources and unlock manager session */
8043 if (method == AST_HTTP_POST && params) {
8044 ast_variables_destroy(params);
8045 }
8046
8047 ast_freefree(http_header);
8048 ast_freefree(out);
8049
8050 ao2_lock(session)__ao2_lock(session, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 8050, "session")
;
8051 if (session->f) {
8052 fclose(session->f);
8053 }
8054 session->f = NULL((void*)0);
8055 session->fd = -1;
8056 ao2_unlock(session)__ao2_unlock(session, "manager.c", __PRETTY_FUNCTION__, 8056,
"session")
;
8057
8058 if (session->needdestroy) {
8059 ast_debug(1, "Need destroy, doing it now!\n")do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 8059, __PRETTY_FUNCTION__, "Need destroy, doing it now!\n"
); } } while (0)
;
8060 session_destroy(session);
8061 }
8062 ast_string_field_free_memory(&d)({ int __res__ = -1; if (((void *)(&d)) != ((void*)0)) { __res__
= __ast_string_field_free_memory(&(&d)->__field_mgr
, &(&d)->__field_mgr_pool, AST_STRINGFIELD_DESTROY
, "manager.c", 8062, __PRETTY_FUNCTION__); } __res__; })
;
8063 return 0;
8064
8065out_401:
8066 if (!nonce) {
8067 nonce = ast_random();
8068 }
8069
8070 ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL((void*)0));
8071 ast_string_field_free_memory(&d)({ int __res__ = -1; if (((void *)(&d)) != ((void*)0)) { __res__
= __ast_string_field_free_memory(&(&d)->__field_mgr
, &(&d)->__field_mgr_pool, AST_STRINGFIELD_DESTROY
, "manager.c", 8071, __PRETTY_FUNCTION__); } __res__; })
;
8072 return 0;
8073}
8074
8075static 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)
8076{
8077 int retval;
8078 struct ast_sockaddr ser_remote_address_tmp;
8079
8080 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8081 retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
8082 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8083 return retval;
8084}
8085
8086static 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)
8087{
8088 int retval;
8089 struct ast_sockaddr ser_remote_address_tmp;
8090
8091 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8092 retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
8093 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8094 return retval;
8095}
8096
8097static 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)
8098{
8099 int retval;
8100 struct ast_sockaddr ser_remote_address_tmp;
8101
8102 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8103 retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
8104 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8105 return retval;
8106}
8107
8108static struct ast_http_uri rawmanuri = {
8109 .description = "Raw HTTP Manager Event Interface",
8110 .uri = "rawman",
8111 .callback = rawman_http_callback,
8112 .data = NULL((void*)0),
8113 .key = __FILE__"manager.c",
8114};
8115
8116static struct ast_http_uri manageruri = {
8117 .description = "HTML Manager Event Interface",
8118 .uri = "manager",
8119 .callback = manager_http_callback,
8120 .data = NULL((void*)0),
8121 .key = __FILE__"manager.c",
8122};
8123
8124static struct ast_http_uri managerxmluri = {
8125 .description = "XML Manager Event Interface",
8126 .uri = "mxml",
8127 .callback = mxml_http_callback,
8128 .data = NULL((void*)0),
8129 .key = __FILE__"manager.c",
8130};
8131
8132
8133/* Callback with Digest authentication */
8134static 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)
8135{
8136 int retval;
8137 struct ast_sockaddr ser_remote_address_tmp;
8138
8139 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8140 retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
8141 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8142 return retval;
8143}
8144
8145static 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)
8146{
8147 int retval;
8148 struct ast_sockaddr ser_remote_address_tmp;
8149
8150 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8151 retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
8152 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8153 return retval;
8154}
8155
8156static 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)
8157{
8158 int retval;
8159 struct ast_sockaddr ser_remote_address_tmp;
8160
8161 ast_sockaddr_copy(&ser_remote_address_tmp, &ser->remote_address);
8162 retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
8163 ast_sockaddr_copy(&ser->remote_address, &ser_remote_address_tmp);
8164 return retval;
8165}
8166
8167static struct ast_http_uri arawmanuri = {
8168 .description = "Raw HTTP Manager Event Interface w/Digest authentication",
8169 .uri = "arawman",
8170 .has_subtree = 0,
8171 .callback = auth_rawman_http_callback,
8172 .data = NULL((void*)0),
8173 .key = __FILE__"manager.c",
8174};
8175
8176static struct ast_http_uri amanageruri = {
8177 .description = "HTML Manager Event Interface w/Digest authentication",
8178 .uri = "amanager",
8179 .has_subtree = 0,
8180 .callback = auth_manager_http_callback,
8181 .data = NULL((void*)0),
8182 .key = __FILE__"manager.c",
8183};
8184
8185static struct ast_http_uri amanagerxmluri = {
8186 .description = "XML Manager Event Interface w/Digest authentication",
8187 .uri = "amxml",
8188 .has_subtree = 0,
8189 .callback = auth_mxml_http_callback,
8190 .data = NULL((void*)0),
8191 .key = __FILE__"manager.c",
8192};
8193
8194/*! \brief Get number of logged in sessions for a login name */
8195static int get_manager_sessions_cb(void *obj, void *arg, void *data, int flags)
8196{
8197 struct mansession_session *session = obj;
8198 const char *login = (char *)arg;
8199 int *no_sessions = data;
8200
8201 if (strcasecmp(session->username, login) == 0) {
8202 (*no_sessions)++;
8203 }
8204
8205 return 0;
8206}
8207
8208
8209/*! \brief ${AMI_CLIENT()} Dialplan function - reads manager client data */
8210static int function_amiclient(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
8211{
8212 struct ast_manager_user *user = NULL((void*)0);
8213
8214 AST_DECLARE_APP_ARGS(args,struct { unsigned int argc; char *argv[0]; char *name; char *
param; } args = { 0, }
8215 AST_APP_ARG(name);struct { unsigned int argc; char *argv[0]; char *name; char *
param; } args = { 0, }
8216 AST_APP_ARG(param);struct { unsigned int argc; char *argv[0]; char *name; char *
param; } args = { 0, }
8217 )struct { unsigned int argc; char *argv[0]; char *name; char *
param; } args = { 0, }
;
8218
8219
8220 if (ast_strlen_zero(data)_ast_strlen_zero(data, "manager.c", __PRETTY_FUNCTION__, 8220
)
) {
8221 ast_log(LOG_WARNING3, "manager.c", 8221, __PRETTY_FUNCTION__, "AMI_CLIENT() requires two arguments: AMI_CLIENT(<name>[,<arg>])\n");
8222 return -1;
8223 }
8224 AST_STANDARD_APP_ARGS(args, data)args.argc = __ast_app_separate_args(data, ',', 1, args.argv, (
(sizeof(args) - __builtin_offsetof(typeof(args), argv)) / sizeof
(args.argv[0])))
;
8225 args.name = ast_strip(args.name);
8226 args.param = ast_strip(args.param);
8227
8228 AST_RWLIST_RDLOCK(&users)__ast_rwlock_rdlock("manager.c", 8228, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
8229 if (!(user = get_manager_by_name_locked(args.name))) {
8230 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 8230, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
8231 ast_log(LOG_ERROR4, "manager.c", 8231, __PRETTY_FUNCTION__, "There's no manager user called : \"%s\"\n", args.name);
8232 return -1;
8233 }
8234 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 8234, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
8235
8236 if (!strcasecmp(args.param, "sessions")) {
8237 int no_sessions = 0;
8238 struct ao2_container *sessions;
8239
8240 sessions = ao2_global_obj_ref(mgr_sessions)__ao2_global_obj_ref(&mgr_sessions, "", "manager.c", 8240
, __PRETTY_FUNCTION__, "mgr_sessions")
;
8241 if (sessions) {
8242 ao2_callback_data(sessions, 0, get_manager_sessions_cb, /*login name*/ data, &no_sessions)__ao2_callback_data((sessions), (0), (get_manager_sessions_cb
), (data), (&no_sessions), "", "manager.c", 8242, __PRETTY_FUNCTION__
)
;
8243 ao2_ref(sessions, -1)__ao2_ref((sessions), (-1), "", "manager.c", 8243, __PRETTY_FUNCTION__
)
;
8244 }
8245 snprintf(buf, len, "%d", no_sessions);
8246 } else {
8247 ast_log(LOG_ERROR4, "manager.c", 8247, __PRETTY_FUNCTION__, "Invalid arguments provided to function AMI_CLIENT: %s\n", args.param);
8248 return -1;
8249
8250 }
8251
8252 return 0;
8253}
8254
8255
8256/*! \brief description of AMI_CLIENT dialplan function */
8257static struct ast_custom_function managerclient_function = {
8258 .name = "AMI_CLIENT",
8259 .read = function_amiclient,
8260 .read_max = 12,
8261};
8262
8263static int webregged = 0;
8264
8265/*! \brief cleanup code called at each iteration of server_root,
8266 * guaranteed to happen every 5 seconds at most
8267 */
8268static void purge_old_stuff(void *data)
8269{
8270 purge_sessions(1);
8271 purge_events();
8272}
8273
8274static struct ast_tls_config ami_tls_cfg;
8275static struct ast_tcptls_session_args ami_desc = {
8276 .accept_fd = -1,
8277 .master = AST_PTHREADT_NULL(pthread_t) -1,
8278 .tls_cfg = NULL((void*)0),
8279 .poll_timeout = 5000, /* wake up every 5 seconds */
8280 .periodic_fn = purge_old_stuff,
8281 .name = "AMI server",
8282 .accept_fn = ast_tcptls_server_root, /* thread doing the accept() */
8283 .worker_fn = session_do, /* thread handling the session */
8284};
8285
8286static struct ast_tcptls_session_args amis_desc = {
8287 .accept_fd = -1,
8288 .master = AST_PTHREADT_NULL(pthread_t) -1,
8289 .tls_cfg = &ami_tls_cfg,
8290 .poll_timeout = -1, /* the other does the periodic cleanup */
8291 .name = "AMI TLS server",
8292 .accept_fn = ast_tcptls_server_root, /* thread doing the accept() */
8293 .worker_fn = session_do, /* thread handling the session */
8294};
8295
8296/*! \brief CLI command manager show settings */
8297static char *handle_manager_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8298{
8299 switch (cmd) {
8300 case CLI_INIT:
8301 e->command = "manager show settings";
8302 e->usage =
8303 "Usage: manager show settings\n"
8304 " Provides detailed list of the configuration of the Manager.\n";
8305 return NULL((void*)0);
8306 case CLI_GENERATE:
8307 return NULL((void*)0);
8308 }
8309#define FORMAT " %-25.25s %-15.55s\n"
8310#define FORMAT2 " %-25.25s %-15d\n"
8311 if (a->argc != 3) {
8312 return CLI_SHOWUSAGE(char *)1;
8313 }
8314 ast_cli(a->fd, "\nGlobal Settings:\n");
8315 ast_cli(a->fd, "----------------\n");
8316 ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled)((manager_enabled) ? "Yes" : "No"));
8317 ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled)((webmanager_enabled) ? "Yes" : "No"));
8318 ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
8319 ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
8320 ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled)((ami_tls_cfg.enabled) ? "Yes" : "No"));
8321 ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
8322 ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
8323 ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
8324 ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
8325 ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin)((allowmultiplelogin) ? "Yes" : "No"));
8326 ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects)((displayconnects) ? "Yes" : "No"));
8327 ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents)((timestampevents) ? "Yes" : "No"));
8328 ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, "")({typeof(&((manager_channelvars)[0])) __x = (manager_channelvars
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 8328
) ? ("") : __x;})
);
8329 ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug)((manager_debug) ? "Yes" : "No"));
8330#undef FORMAT
8331#undef FORMAT2
8332
8333 return CLI_SUCCESS(char *)0;
8334}
8335
8336#ifdef AST_XML_DOCS
8337
8338static int ast_xml_doc_item_cmp_fn(const void *a, const void *b)
8339{
8340 struct ast_xml_doc_item **item_a = (struct ast_xml_doc_item **)a;
8341 struct ast_xml_doc_item **item_b = (struct ast_xml_doc_item **)b;
8342 return strcmp((*item_a)->name, (*item_b)->name);
8343}
8344
8345static char *handle_manager_show_events(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8346{
8347 struct ao2_container *events;
8348 struct ao2_iterator *it_events;
8349 struct ast_xml_doc_item *item;
8350 struct ast_xml_doc_item **items;
8351 struct ast_str *buffer;
8352 int i = 0, totalitems = 0;
8353
8354 switch (cmd) {
8355 case CLI_INIT:
8356 e->command = "manager show events";
8357 e->usage =
8358 "Usage: manager show events\n"
8359 " Prints a listing of the available Asterisk manager interface events.\n";
8360 return NULL((void*)0);
8361 case CLI_GENERATE:
8362 return NULL((void*)0);
8363 }
8364 if (a->argc != 3) {
8365 return CLI_SHOWUSAGE(char *)1;
8366 }
8367
8368 buffer = ast_str_create(128);
8369 if (!buffer) {
8370 return CLI_SUCCESS(char *)0;
8371 }
8372
8373 events = ao2_global_obj_ref(event_docs)__ao2_global_obj_ref(&event_docs, "", "manager.c", 8373, __PRETTY_FUNCTION__
, "event_docs")
;
8374 if (!events) {
8375 ast_cli(a->fd, "No manager event documentation loaded\n");
8376 ast_freefree(buffer);
8377 return CLI_SUCCESS(char *)0;
8378 }
8379
8380 ao2_lock(events)__ao2_lock(events, AO2_LOCK_REQ_MUTEX, "manager.c", __PRETTY_FUNCTION__
, 8380, "events")
;
8381 if (!(it_events = ao2_callback(events, OBJ_MULTIPLE | OBJ_NOLOCK, NULL, NULL)__ao2_callback((events), (OBJ_MULTIPLE | OBJ_NOLOCK), (((void
*)0)), (((void*)0)), "", "manager.c", 8381, __PRETTY_FUNCTION__
)
)) {
8382 ao2_unlock(events)__ao2_unlock(events, "manager.c", __PRETTY_FUNCTION__, 8382, "events"
)
;
8383 ast_log(AST_LOG_ERROR4, "manager.c", 8383, __PRETTY_FUNCTION__, "Unable to create iterator for events container\n");
8384 ast_freefree(buffer);
8385 ao2_ref(events, -1)__ao2_ref((events), (-1), "", "manager.c", 8385, __PRETTY_FUNCTION__
)
;
8386 return CLI_SUCCESS(char *)0;
8387 }
8388 if (!(items = ast_calloc(sizeof(struct ast_xml_doc_item *), ao2_container_count(events))_ast_calloc((sizeof(struct ast_xml_doc_item *)), (ao2_container_count
(events)), "manager.c", 8388, __PRETTY_FUNCTION__)
)) {
8389 ao2_unlock(events)__ao2_unlock(events, "manager.c", __PRETTY_FUNCTION__, 8389, "events"
)
;
8390 ast_log(AST_LOG_ERROR4, "manager.c", 8390, __PRETTY_FUNCTION__, "Unable to create temporary sorting array for events\n");
8391 ao2_iterator_destroy(it_events);
8392 ast_freefree(buffer);
8393 ao2_ref(events, -1)__ao2_ref((events), (-1), "", "manager.c", 8393, __PRETTY_FUNCTION__
)
;
8394 return CLI_SUCCESS(char *)0;
8395 }
8396 ao2_unlock(events)__ao2_unlock(events, "manager.c", __PRETTY_FUNCTION__, 8396, "events"
)
;
8397
8398 while ((item = ao2_iterator_next(it_events)__ao2_iterator_next((it_events), "", "manager.c", 8398, __PRETTY_FUNCTION__
)
)) {
8399 items[totalitems++] = item;
8400 ao2_ref(item, -1)__ao2_ref((item), (-1), "", "manager.c", 8400, __PRETTY_FUNCTION__
)
;
8401 }
8402
8403 qsort(items, totalitems, sizeof(struct ast_xml_doc_item *), ast_xml_doc_item_cmp_fn);
8404
8405 ast_cli(a->fd, "Events:\n");
8406 ast_cli(a->fd, " -------------------- -------------------- -------------------- \n");
8407 for (i = 0; i < totalitems; i++) {
8408 ast_str_append(&buffer, 0, " %-20.20s", items[i]->name);
8409 if ((i + 1) % 3 == 0) {
8410 ast_cli(a->fd, "%s\n", ast_str_buffer(buffer));
8411 ast_str_set(&buffer, 0, "%s", "");
8412 }
8413 }
8414 if ((i + 1) % 3 != 0) {
8415 ast_cli(a->fd, "%s\n", ast_str_buffer(buffer));
8416 }
8417
8418 ao2_iterator_destroy(it_events);
8419 ast_freefree(items);
8420 ao2_ref(events, -1)__ao2_ref((events), (-1), "", "manager.c", 8420, __PRETTY_FUNCTION__
)
;
8421 ast_freefree(buffer);
8422
8423 return CLI_SUCCESS(char *)0;
8424}
8425
8426static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance)
8427{
8428 char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
8429
8430 term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA35, 0, 40);
8431 term_color(description_title, "[Description]\n", COLOR_MAGENTA35, 0, 40);
8432 term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA35, 0, 40);
8433 term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA35, 0, 40);
8434 term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA35, 0, 40);
8435
8436 if (!ast_strlen_zero(ast_str_buffer(instance->synopsis))_ast_strlen_zero(ast_str_buffer(instance->synopsis), "manager.c"
, __PRETTY_FUNCTION__, 8436)
) {
8437 char *synopsis = ast_xmldoc_printable(ast_str_buffer(instance->synopsis), 1);
8438 ast_cli(a->fd, "%s%s\n\n", synopsis_title, synopsis);
8439 ast_freefree(synopsis);
8440 }
8441 if (!ast_strlen_zero(ast_str_buffer(instance->syntax))_ast_strlen_zero(ast_str_buffer(instance->syntax), "manager.c"
, __PRETTY_FUNCTION__, 8441)
) {
8442 char *syntax = ast_xmldoc_printable(ast_str_buffer(instance->syntax), 1);
8443 ast_cli(a->fd, "%s%s\n\n", syntax_title, syntax);
8444 ast_freefree(syntax);
8445 }
8446 if (!ast_strlen_zero(ast_str_buffer(instance->description))_ast_strlen_zero(ast_str_buffer(instance->description), "manager.c"
, __PRETTY_FUNCTION__, 8446)
) {
8447 char *description = ast_xmldoc_printable(ast_str_buffer(instance->description), 1);
8448 ast_cli(a->fd, "%s%s\n\n", description_title, description);
8449 ast_freefree(description);
8450 }
8451 if (!ast_strlen_zero(ast_str_buffer(instance->arguments))_ast_strlen_zero(ast_str_buffer(instance->arguments), "manager.c"
, __PRETTY_FUNCTION__, 8451)
) {
8452 char *arguments = ast_xmldoc_printable(ast_str_buffer(instance->arguments), 1);
8453 ast_cli(a->fd, "%s%s\n\n", arguments_title, arguments);
8454 ast_freefree(arguments);
8455 }
8456 if (!ast_strlen_zero(ast_str_buffer(instance->seealso))_ast_strlen_zero(ast_str_buffer(instance->seealso), "manager.c"
, __PRETTY_FUNCTION__, 8456)
) {
8457 char *seealso = ast_xmldoc_printable(ast_str_buffer(instance->seealso), 1);
8458 ast_cli(a->fd, "%s%s\n\n", seealso_title, seealso);
8459 ast_freefree(seealso);
8460 }
8461}
8462
8463static char *handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8464{
8465 RAII_VAR(struct ao2_container *, events, NULL, ao2_cleanup)_raii_cleanup_block_t _raii_cleanup_events __attribute__((cleanup
(_raii_cleanup_block),unused)) = ((void*)0); __attribute__((__blocks__
(byref))) struct ao2_container * events = ((void*)0); _raii_cleanup_events
= ^{ {(void)__ao2_cleanup_debug((events), "", "manager.c", 8465
, __PRETTY_FUNCTION__);} }
;
8466 struct ao2_iterator it_events;
8467 struct ast_xml_doc_item *item, *temp;
8468 int length;
8469 int which;
8470 char *match = NULL((void*)0);
8471
8472 if (cmd == CLI_INIT) {
8473 e->command = "manager show event";
8474 e->usage =
8475 "Usage: manager show event <eventname>\n"
8476 " Provides a detailed description a Manager interface event.\n";
8477 return NULL((void*)0);
8478 }
8479
8480 events = ao2_global_obj_ref(event_docs)__ao2_global_obj_ref(&event_docs, "", "manager.c", 8480, __PRETTY_FUNCTION__
, "event_docs")
;
8481 if (!events) {
8482 ast_cli(a->fd, "No manager event documentation loaded\n");
8483 return CLI_SUCCESS(char *)0;
8484 }
8485
8486 if (cmd == CLI_GENERATE) {
8487 length = strlen(a->word);
8488 which = 0;
8489 it_events = ao2_iterator_init(events, 0);
8490 while ((item = ao2_iterator_next(&it_events)__ao2_iterator_next((&it_events), "", "manager.c", 8490, __PRETTY_FUNCTION__
)
)) {
8491 if (!strncasecmp(a->word, item->name, length) && ++which > a->n) {
8492 match = ast_strdup(item->name)_ast_strdup((item->name), "manager.c", 8492, __PRETTY_FUNCTION__
)
;
8493 ao2_ref(item, -1)__ao2_ref((item), (-1), "", "manager.c", 8493, __PRETTY_FUNCTION__
)
;
8494 break;
8495 }
8496 ao2_ref(item, -1)__ao2_ref((item), (-1), "", "manager.c", 8496, __PRETTY_FUNCTION__
)
;
8497 }
8498 ao2_iterator_destroy(&it_events);
8499 return match;
8500 }
8501
8502 if (a->argc != 4) {
8503 return CLI_SHOWUSAGE(char *)1;
8504 }
8505
8506 if (!(item = ao2_find(events, a->argv[3], OBJ_KEY)__ao2_find((events), (a->argv[3]), (OBJ_SEARCH_KEY), "", "manager.c"
, 8506, __PRETTY_FUNCTION__)
)) {
8507 ast_cli(a->fd, "Could not find event '%s'\n", a->argv[3]);
8508 return CLI_SUCCESS(char *)0;
8509 }
8510
8511 ast_cli(a->fd, "Event: %s\n", a->argv[3]);
8512 for (temp = item; temp; temp = AST_LIST_NEXT(temp, next)((temp)->next.next)) {
8513 print_event_instance(a, temp);
8514 }
8515
8516 ao2_ref(item, -1)__ao2_ref((item), (-1), "", "manager.c", 8516, __PRETTY_FUNCTION__
)
;
8517 return CLI_SUCCESS(char *)0;
8518}
8519
8520#endif
8521
8522static struct ast_cli_entry cli_manager[] = {
8523 AST_CLI_DEFINE(handle_showmancmd, "Show a manager interface command"){ .handler = handle_showmancmd, .summary = "Show a manager interface command"
}
,
8524 AST_CLI_DEFINE(handle_showmancmds, "List manager interface commands"){ .handler = handle_showmancmds, .summary = "List manager interface commands"
}
,
8525 AST_CLI_DEFINE(handle_showmanconn, "List connected manager interface users"){ .handler = handle_showmanconn, .summary = "List connected manager interface users"
}
,
8526 AST_CLI_DEFINE(handle_showmaneventq, "List manager interface queued events"){ .handler = handle_showmaneventq, .summary = "List manager interface queued events"
}
,
8527 AST_CLI_DEFINE(handle_showmanagers, "List configured manager users"){ .handler = handle_showmanagers, .summary = "List configured manager users"
}
,
8528 AST_CLI_DEFINE(handle_showmanager, "Display information on a specific manager user"){ .handler = handle_showmanager, .summary = "Display information on a specific manager user"
}
,
8529 AST_CLI_DEFINE(handle_mandebug, "Show, enable, disable debugging of the manager code"){ .handler = handle_mandebug, .summary = "Show, enable, disable debugging of the manager code"
}
,
8530 AST_CLI_DEFINE(handle_manager_reload, "Reload manager configurations"){ .handler = handle_manager_reload, .summary = "Reload manager configurations"
}
,
8531 AST_CLI_DEFINE(handle_manager_show_settings, "Show manager global settings"){ .handler = handle_manager_show_settings, .summary = "Show manager global settings"
}
,
8532#ifdef AST_XML_DOCS
8533 AST_CLI_DEFINE(handle_manager_show_events, "List manager interface events"){ .handler = handle_manager_show_events, .summary = "List manager interface events"
}
,
8534 AST_CLI_DEFINE(handle_manager_show_event, "Show a manager interface event"){ .handler = handle_manager_show_event, .summary = "Show a manager interface event"
}
,
8535#endif
8536};
8537
8538/*!
8539 * \internal
8540 * \brief Load the config channelvars variable.
8541 *
8542 * \param var Config variable to load.
8543 *
8544 * \return Nothing
8545 */
8546static void load_channelvars(struct ast_variable *var)
8547{
8548 char *parse = NULL((void*)0);
8549 AST_DECLARE_APP_ARGS(args,struct { unsigned int argc; char *argv[0]; char *vars[128]; }
args = { 0, }
8550 AST_APP_ARG(vars)[MAX_VARS];struct { unsigned int argc; char *argv[0]; char *vars[128]; }
args = { 0, }
8551 )struct { unsigned int argc; char *argv[0]; char *vars[128]; }
args = { 0, }
;
8552
8553 ast_freefree(manager_channelvars);
8554 manager_channelvars = ast_strdup(var->value)_ast_strdup((var->value), "manager.c", 8554, __PRETTY_FUNCTION__
)
;
8555
8556 /* parse the setting */
8557 parse = ast_strdupa(manager_channelvars)(__extension__ ({ const char *__old = (manager_channelvars); size_t
__len = strlen(__old) + 1; char *__new = __builtin_alloca(__len
); memcpy (__new, __old, __len); __new; }))
;
8558 AST_STANDARD_APP_ARGS(args, parse)args.argc = __ast_app_separate_args(parse, ',', 1, args.argv,
((sizeof(args) - __builtin_offsetof(typeof(args), argv)) / sizeof
(args.argv[0])))
;
8559
8560 ast_channel_set_manager_vars(args.argc, args.vars);
8561}
8562
8563/*!
8564 * \internal
8565 * \brief Free a user record. Should already be removed from the list
8566 */
8567static void manager_free_user(struct ast_manager_user *user)
8568{
8569 ast_freefree(user->a1_hash);
8570 ast_freefree(user->secret);
8571 if (user->whitefilters) {
8572 ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one")__ao2_ref((user->whitefilters), (-1), ("decrement ref for white container, should be last one"
), "manager.c", 8572, __PRETTY_FUNCTION__)
;
8573 }
8574 if (user->blackfilters) {
8575 ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one")__ao2_ref((user->blackfilters), (-1), ("decrement ref for black container, should be last one"
), "manager.c", 8575, __PRETTY_FUNCTION__)
;
8576 }
8577 user->acl = ast_free_acl_list(user->acl);
8578 ast_variables_destroy(user->chanvars);
8579 ast_freefree(user);
8580}
8581
8582/*!
8583 * \internal
8584 * \brief Clean up resources on Asterisk shutdown
8585 */
8586static void manager_shutdown(void)
8587{
8588 struct ast_manager_user *user;
8589
8590 /* This event is not actually transmitted, but causes all TCP sessions to be closed */
8591 manager_event(EVENT_FLAG_SHUTDOWN, "CloseSession", "CloseSession: true\r\n")__ast_manager_event_multichan(-1, "CloseSession", 0, ((void*)
0), "manager.c", 8591, __PRETTY_FUNCTION__, "CloseSession: true\r\n"
)
;
8592
8593 ast_manager_unregister("Ping");
8594 ast_manager_unregister("Events");
8595 ast_manager_unregister("Logoff");
8596 ast_manager_unregister("Login");
8597 ast_manager_unregister("Challenge");
8598 ast_manager_unregister("Hangup");
8599 ast_manager_unregister("Status");
8600 ast_manager_unregister("Setvar");
8601 ast_manager_unregister("Getvar");
8602 ast_manager_unregister("GetConfig");
8603 ast_manager_unregister("GetConfigJSON");
8604 ast_manager_unregister("UpdateConfig");
8605 ast_manager_unregister("CreateConfig");
8606 ast_manager_unregister("ListCategories");
8607 ast_manager_unregister("Redirect");
8608 ast_manager_unregister("Atxfer");
8609 ast_manager_unregister("Originate");
8610 ast_manager_unregister("Command");
8611 ast_manager_unregister("ExtensionState");
8612 ast_manager_unregister("PresenceState");
8613 ast_manager_unregister("AbsoluteTimeout");
8614 ast_manager_unregister("MailboxStatus");
8615 ast_manager_unregister("MailboxCount");
8616 ast_manager_unregister("ListCommands");
8617 ast_manager_unregister("SendText");
8618 ast_manager_unregister("UserEvent");
8619 ast_manager_unregister("WaitEvent");
8620 ast_manager_unregister("CoreSettings");
8621 ast_manager_unregister("CoreStatus");
8622 ast_manager_unregister("Reload");
8623 ast_manager_unregister("LoggerRotate");
8624 ast_manager_unregister("CoreShowChannels");
8625 ast_manager_unregister("ModuleLoad");
8626 ast_manager_unregister("ModuleCheck");
8627 ast_manager_unregister("AOCMessage");
8628 ast_manager_unregister("Filter");
8629 ast_manager_unregister("BlindTransfer");
8630 ast_custom_function_unregister(&managerclient_function);
8631 ast_cli_unregister_multiple(cli_manager, ARRAY_LEN(cli_manager)(size_t) (sizeof(cli_manager) / sizeof(0[cli_manager])));
8632
8633#ifdef AST_XML_DOCS
8634 ao2_t_global_obj_release(event_docs, "Dispose of event_docs")__ao2_global_obj_release(&event_docs, ("Dispose of event_docs"
), "manager.c", 8634, __PRETTY_FUNCTION__, "event_docs")
;
8635#endif
8636
8637#ifdef TEST_FRAMEWORK
8638 stasis_forward_cancel(test_suite_forwarder);
8639 test_suite_forwarder = NULL((void*)0);
8640#endif
8641
8642 if (stasis_router) {
8643 stasis_message_router_unsubscribe_and_join(stasis_router);
8644 stasis_router = NULL((void*)0);
8645 }
8646 stasis_forward_cancel(rtp_topic_forwarder);
8647 rtp_topic_forwarder = NULL((void*)0);
8648 stasis_forward_cancel(security_topic_forwarder);
8649 security_topic_forwarder = NULL((void*)0);
8650 ao2_cleanup(manager_topic)__ao2_cleanup_debug((manager_topic), "", "manager.c", 8650, __PRETTY_FUNCTION__
)
;
8651 manager_topic = NULL((void*)0);
8652 STASIS_MESSAGE_TYPE_CLEANUP(ast_manager_get_generic_type)({ __ao2_cleanup_debug((_priv_ast_manager_get_generic_type), ""
, "manager.c", 8652, __PRETTY_FUNCTION__); _priv_ast_manager_get_generic_type
= ((void*)0); })
;
8653
8654 ast_tcptls_server_stop(&ami_desc);
8655 ast_tcptls_server_stop(&amis_desc);
8656
8657 ast_freefree(ami_tls_cfg.certfile);
8658 ami_tls_cfg.certfile = NULL((void*)0);
8659 ast_freefree(ami_tls_cfg.pvtfile);
8660 ami_tls_cfg.pvtfile = NULL((void*)0);
8661 ast_freefree(ami_tls_cfg.cipher);
8662 ami_tls_cfg.cipher = NULL((void*)0);
8663
8664 ao2_global_obj_release(mgr_sessions)__ao2_global_obj_release(&mgr_sessions, "", "manager.c", 8664
, __PRETTY_FUNCTION__, "mgr_sessions")
;
8665
8666 while ((user = AST_LIST_REMOVE_HEAD(&users, list)({ typeof((&users)->first) __cur = (&users)->first
; if (__cur) { (&users)->first = __cur->list.next; __cur
->list.next = ((void*)0); if ((&users)->last == __cur
) (&users)->last = ((void*)0); } __cur; })
)) {
8667 manager_free_user(user);
8668 }
8669 acl_change_stasis_unsubscribe();
8670
8671 ast_freefree(manager_channelvars);
8672}
8673
8674
8675/*! \brief Initialize all \ref stasis topics and routers used by the various
8676 * sub-components of AMI
8677 */
8678static int manager_subscriptions_init(void)
8679{
8680 int res = 0;
8681
8682 rtp_topic_forwarder = stasis_forward_all(ast_rtp_topic(), manager_topic);
8683 if (!rtp_topic_forwarder) {
8684 return -1;
8685 }
8686
8687 security_topic_forwarder = stasis_forward_all(ast_security_topic(), manager_topic);
8688 if (!security_topic_forwarder) {
8689 return -1;
8690 }
8691
8692 stasis_router = stasis_message_router_create(manager_topic);
8693 if (!stasis_router) {
8694 return -1;
8695 }
8696 stasis_message_router_set_congestion_limits(stasis_router, -1,
8697 6 * AST_TASKPROCESSOR_HIGH_WATER_LEVEL500);
8698
8699 res |= stasis_message_router_set_default(stasis_router,
8700 manager_default_msg_cb, NULL((void*)0));
8701
8702 res |= stasis_message_router_add(stasis_router,
8703 ast_manager_get_generic_type(), manager_generic_msg_cb, NULL((void*)0));
8704
8705 if (res != 0) {
8706 return -1;
8707 }
8708 return 0;
8709}
8710
8711static int subscribe_all(void)
8712{
8713 if (manager_subscriptions_init()) {
8714 ast_log(AST_LOG_ERROR4, "manager.c", 8714, __PRETTY_FUNCTION__, "Failed to initialize manager subscriptions\n");
8715 return -1;
8716 }
8717 if (manager_system_init()) {
8718 ast_log(AST_LOG_ERROR4, "manager.c", 8718, __PRETTY_FUNCTION__, "Failed to initialize manager system handling\n");
8719 return -1;
8720 }
8721 if (manager_channels_init()) {
8722 ast_log(AST_LOG_ERROR4, "manager.c", 8722, __PRETTY_FUNCTION__, "Failed to initialize manager channel handling\n");
8723 return -1;
8724 }
8725 if (manager_mwi_init()) {
8726 ast_log(AST_LOG_ERROR4, "manager.c", 8726, __PRETTY_FUNCTION__, "Failed to initialize manager MWI handling\n");
8727 return -1;
8728 }
8729 if (manager_bridging_init()) {
8730 return -1;
8731 }
8732 if (manager_endpoints_init()) {
8733 ast_log(AST_LOG_ERROR4, "manager.c", 8733, __PRETTY_FUNCTION__, "Failed to initialize manager endpoints handling\n");
8734 return -1;
8735 }
8736
8737 subscribed = 1;
8738 return 0;
8739}
8740
8741static void manager_set_defaults(void)
8742{
8743 manager_enabled = 0;
8744 displayconnects = 1;
8745 broken_events_action = 0;
8746 authtimeout = 30;
8747 authlimit = 50;
8748 manager_debug = 0; /* Debug disabled by default */
8749
8750 /* default values */
8751 ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM)({typeof(&((ast_config_AST_SYSTEM_NAME)[0])) __x = (ast_config_AST_SYSTEM_NAME
); _ast_strlen_zero(__x, "manager.c", __PRETTY_FUNCTION__, 8751
) ? ("asterisk") : __x;})
,
8752 sizeof(global_realm));
8753 ast_sockaddr_setnull(&ami_desc.local_address);
8754 ast_sockaddr_setnull(&amis_desc.local_address);
8755
8756 ami_tls_cfg.enabled = 0;
8757 ast_freefree(ami_tls_cfg.certfile);
8758 ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE)_ast_strdup(("asterisk.pem"), "manager.c", 8758, __PRETTY_FUNCTION__
)
;
8759 ast_freefree(ami_tls_cfg.pvtfile);
8760 ami_tls_cfg.pvtfile = ast_strdup("")_ast_strdup((""), "manager.c", 8760, __PRETTY_FUNCTION__);
8761 ast_freefree(ami_tls_cfg.cipher);
8762 ami_tls_cfg.cipher = ast_strdup("")_ast_strdup((""), "manager.c", 8762, __PRETTY_FUNCTION__);
8763}
8764
8765static int __init_manager(int reload, int by_external_config)
8766{
8767 struct ast_config *ucfg = NULL((void*)0), *cfg = NULL((void*)0);
8768 const char *val;
8769 char *cat = NULL((void*)0);
8770 int newhttptimeout = 60;
8771 struct ast_manager_user *user = NULL((void*)0);
8772 struct ast_variable *var;
8773 struct ast_flags config_flags = { (reload && !by_external_config) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
8774 char a1[256];
8775 char a1_hash[256];
8776 struct ast_sockaddr ami_desc_local_address_tmp;
8777 struct ast_sockaddr amis_desc_local_address_tmp;
8778 int tls_was_enabled = 0;
8779 int acl_subscription_flag = 0;
8780
8781 if (!reload) {
1
Taking true branch
8782 struct ao2_container *sessions;
8783#ifdef AST_XML_DOCS
8784 struct ao2_container *temp_event_docs;
8785#endif
8786 int res;
8787
8788 ast_register_cleanup(manager_shutdown);
8789
8790 res = STASIS_MESSAGE_TYPE_INIT(ast_manager_get_generic_type)({ _ast_assert(_priv_ast_manager_get_generic_type == ((void*)
0), "_priv_ast_manager_get_generic_type == NULL", "manager.c"
, 8790, __PRETTY_FUNCTION__); stasis_message_type_create("ast_manager_get_generic_type"
, &_priv_ast_manager_get_generic_type_v, &_priv_ast_manager_get_generic_type
) == STASIS_MESSAGE_TYPE_ERROR ? 1 : 0; })
;
8791 if (res != 0) {
2
Taking false branch
8792 return -1;
8793 }
8794 manager_topic = stasis_topic_create("manager_topic");
8795 if (!manager_topic) {
3
Assuming 'manager_topic' is non-null
4
Taking false branch
8796 return -1;
8797 }
8798
8799 /* Register default actions */
8800 ast_manager_register_xml_core("Ping", 0, action_ping)ast_manager_register2("Ping", 0, action_ping, ((void*)0), ((void
*)0), ((void*)0))
;
8801 ast_manager_register_xml_core("Events", 0, action_events)ast_manager_register2("Events", 0, action_events, ((void*)0),
((void*)0), ((void*)0))
;
8802 ast_manager_register_xml_core("Logoff", 0, action_logoff)ast_manager_register2("Logoff", 0, action_logoff, ((void*)0),
((void*)0), ((void*)0))
;
8803 ast_manager_register_xml_core("Login", 0, action_login)ast_manager_register2("Login", 0, action_login, ((void*)0), (
(void*)0), ((void*)0))
;
8804 ast_manager_register_xml_core("Challenge", 0, action_challenge)ast_manager_register2("Challenge", 0, action_challenge, ((void
*)0), ((void*)0), ((void*)0))
;
8805 ast_manager_register_xml_core("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup)ast_manager_register2("Hangup", (1 << 0) | (1 << 1
), action_hangup, ((void*)0), ((void*)0), ((void*)0))
;
8806 ast_manager_register_xml_core("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status)ast_manager_register2("Status", (1 << 0) | (1 << 1
) | (1 << 9), action_status, ((void*)0), ((void*)0), ((
void*)0))
;
8807 ast_manager_register_xml_core("Setvar", EVENT_FLAG_CALL, action_setvar)ast_manager_register2("Setvar", (1 << 1), action_setvar
, ((void*)0), ((void*)0), ((void*)0))
;
8808 ast_manager_register_xml_core("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar)ast_manager_register2("Getvar", (1 << 1) | (1 << 9
), action_getvar, ((void*)0), ((void*)0), ((void*)0))
;
8809 ast_manager_register_xml_core("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig)ast_manager_register2("GetConfig", (1 << 0) | (1 <<
7), action_getconfig, ((void*)0), ((void*)0), ((void*)0))
;
8810 ast_manager_register_xml_core("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson)ast_manager_register2("GetConfigJSON", (1 << 0) | (1 <<
7), action_getconfigjson, ((void*)0), ((void*)0), ((void*)0)
)
;
8811 ast_manager_register_xml_core("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig)ast_manager_register2("UpdateConfig", (1 << 7), action_updateconfig
, ((void*)0), ((void*)0), ((void*)0))
;
8812 ast_manager_register_xml_core("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig)ast_manager_register2("CreateConfig", (1 << 7), action_createconfig
, ((void*)0), ((void*)0), ((void*)0))
;
8813 ast_manager_register_xml_core("ListCategories", EVENT_FLAG_CONFIG, action_listcategories)ast_manager_register2("ListCategories", (1 << 7), action_listcategories
, ((void*)0), ((void*)0), ((void*)0))
;
8814 ast_manager_register_xml_core("Redirect", EVENT_FLAG_CALL, action_redirect)ast_manager_register2("Redirect", (1 << 1), action_redirect
, ((void*)0), ((void*)0), ((void*)0))
;
8815 ast_manager_register_xml_core("Atxfer", EVENT_FLAG_CALL, action_atxfer)ast_manager_register2("Atxfer", (1 << 1), action_atxfer
, ((void*)0), ((void*)0), ((void*)0))
;
8816 ast_manager_register_xml_core("Originate", EVENT_FLAG_ORIGINATE, action_originate)ast_manager_register2("Originate", (1 << 12), action_originate
, ((void*)0), ((void*)0), ((void*)0))
;
8817 ast_manager_register_xml_core("Command", EVENT_FLAG_COMMAND, action_command)ast_manager_register2("Command", (1 << 4), action_command
, ((void*)0), ((void*)0), ((void*)0))
;
8818 ast_manager_register_xml_core("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate)ast_manager_register2("ExtensionState", (1 << 1) | (1 <<
9), action_extensionstate, ((void*)0), ((void*)0), ((void*)0
))
;
8819 ast_manager_register_xml_core("PresenceState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_presencestate)ast_manager_register2("PresenceState", (1 << 1) | (1 <<
9), action_presencestate, ((void*)0), ((void*)0), ((void*)0)
)
;
8820 ast_manager_register_xml_core("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout)ast_manager_register2("AbsoluteTimeout", (1 << 0) | (1 <<
1), action_timeout, ((void*)0), ((void*)0), ((void*)0))
;
8821 ast_manager_register_xml_core("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus)ast_manager_register2("MailboxStatus", (1 << 1) | (1 <<
9), action_mailboxstatus, ((void*)0), ((void*)0), ((void*)0)
)
;
8822 ast_manager_register_xml_core("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount)ast_manager_register2("MailboxCount", (1 << 1) | (1 <<
9), action_mailboxcount, ((void*)0), ((void*)0), ((void*)0))
;
8823 ast_manager_register_xml_core("ListCommands", 0, action_listcommands)ast_manager_register2("ListCommands", 0, action_listcommands,
((void*)0), ((void*)0), ((void*)0))
;
8824 ast_manager_register_xml_core("SendText", EVENT_FLAG_CALL, action_sendtext)ast_manager_register2("SendText", (1 << 1), action_sendtext
, ((void*)0), ((void*)0), ((void*)0))
;
8825 ast_manager_register_xml_core("UserEvent", EVENT_FLAG_USER, action_userevent)ast_manager_register2("UserEvent", (1 << 6), action_userevent
, ((void*)0), ((void*)0), ((void*)0))
;
8826 ast_manager_register_xml_core("WaitEvent", 0, action_waitevent)ast_manager_register2("WaitEvent", 0, action_waitevent, ((void
*)0), ((void*)0), ((void*)0))
;
8827 ast_manager_register_xml_core("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings)ast_manager_register2("CoreSettings", (1 << 0) | (1 <<
9), action_coresettings, ((void*)0), ((void*)0), ((void*)0))
;
8828 ast_manager_register_xml_core("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus)ast_manager_register2("CoreStatus", (1 << 0) | (1 <<
9), action_corestatus, ((void*)0), ((void*)0), ((void*)0))
;
8829 ast_manager_register_xml_core("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload)ast_manager_register2("Reload", (1 << 7) | (1 << 0
), action_reload, ((void*)0), ((void*)0), ((void*)0))
;
8830 ast_manager_register_xml_core("LoggerRotate", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_loggerrotate)ast_manager_register2("LoggerRotate", (1 << 0) | (1 <<
9), action_loggerrotate, ((void*)0), ((void*)0), ((void*)0))
;
8831 ast_manager_register_xml_core("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels)ast_manager_register2("CoreShowChannels", (1 << 0) | (1
<< 9), action_coreshowchannels, ((void*)0), ((void*)0)
, ((void*)0))
;
8832 ast_manager_register_xml_core("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload)ast_manager_register2("ModuleLoad", (1 << 0), manager_moduleload
, ((void*)0), ((void*)0), ((void*)0))
;
8833 ast_manager_register_xml_core("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck)ast_manager_register2("ModuleCheck", (1 << 0), manager_modulecheck
, ((void*)0), ((void*)0), ((void*)0))
;
8834 ast_manager_register_xml_core("AOCMessage", EVENT_FLAG_AOC, action_aocmessage)ast_manager_register2("AOCMessage", (1 << 16), action_aocmessage
, ((void*)0), ((void*)0), ((void*)0))
;
8835 ast_manager_register_xml_core("Filter", EVENT_FLAG_SYSTEM, action_filter)ast_manager_register2("Filter", (1 << 0), action_filter
, ((void*)0), ((void*)0), ((void*)0))
;
8836 ast_manager_register_xml_core("BlindTransfer", EVENT_FLAG_CALL, action_blind_transfer)ast_manager_register2("BlindTransfer", (1 << 1), action_blind_transfer
, ((void*)0), ((void*)0), ((void*)0))
;
8837
8838#ifdef TEST_FRAMEWORK
8839 test_suite_forwarder = stasis_forward_all(ast_test_suite_topic(), manager_topic);
8840#endif
8841
8842 ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager))__ast_cli_register_multiple(cli_manager, (size_t) (sizeof(cli_manager
) / sizeof(0[cli_manager])), ((void*)0))
;
8843 __ast_custom_function_register(&managerclient_function, NULL((void*)0));
8844 ast_extension_state_add(NULL((void*)0), NULL((void*)0), manager_state_cb, NULL((void*)0));
8845
8846 /* Append placeholder event so master_eventq never runs dry */
8847 if (append_event("Event: Placeholder\r\n\r\n", 0)) {
5
Calling 'append_event'
8848 return -1;
8849 }
8850
8851#ifdef AST_XML_DOCS
8852 temp_event_docs = ast_xmldoc_build_documentation("managerEvent");
8853 if (temp_event_docs) {
8854 ao2_t_global_obj_replace_unref(event_docs, temp_event_docs, "Toss old event docs")__ao2_global_obj_replace_unref(&event_docs, (temp_event_docs
), ("Toss old event docs"), "manager.c", 8854, __PRETTY_FUNCTION__
, "event_docs")
;
8855 ao2_t_ref(temp_event_docs, -1, "Remove creation ref - container holds only ref now")__ao2_ref((temp_event_docs), (-1), ("Remove creation ref - container holds only ref now"
), "manager.c", 8855, __PRETTY_FUNCTION__)
;
8856 }
8857#endif
8858
8859 /* If you have a NULL hash fn, you only need a single bucket */
8860 sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn)__ao2_container_alloc_hash(((AO2_ALLOC_OPT_LOCK_MUTEX)), (0),
(((1))), (((((void*)0)))), (((void*)0)), (((mansession_cmp_fn
))), "", "manager.c", 8860, __PRETTY_FUNCTION__)
;
8861 if (!sessions) {
8862 return -1;
8863 }
8864 ao2_global_obj_replace_unref(mgr_sessions, sessions)__ao2_global_obj_replace_unref(&mgr_sessions, (sessions),
"", "manager.c", 8864, __PRETTY_FUNCTION__, "mgr_sessions")
;
8865 ao2_ref(sessions, -1)__ao2_ref((sessions), (-1), "", "manager.c", 8865, __PRETTY_FUNCTION__
)
;
8866
8867 /* Initialize all settings before first configuration load. */
8868 manager_set_defaults();
8869 }
8870
8871 cfg = ast_config_load2("manager.conf", "manager", config_flags);
8872 if (cfg == CONFIG_STATUS_FILEUNCHANGED(void *)-1) {
8873 return 0;
8874 } else if (!cfg || cfg == CONFIG_STATUS_FILEINVALID(void *)-2) {
8875 ast_log(LOG_NOTICE2, "manager.c", 8875, __PRETTY_FUNCTION__, "Unable to open AMI configuration manager.conf, or configuration is invalid.\n");
8876 return 0;
8877 }
8878
8879 /* 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. */
8880 if (!by_external_config) {
8881 acl_change_stasis_unsubscribe();
8882 }
8883
8884 if (reload) {
8885 /* Reset all settings before reloading configuration */
8886 tls_was_enabled = ami_tls_cfg.enabled;
8887 manager_set_defaults();
8888 }
8889
8890 ast_sockaddr_parse(&ami_desc_local_address_tmp, "[::]", 0);
8891 ast_sockaddr_set_port(&ami_desc_local_address_tmp, DEFAULT_MANAGER_PORT)_ast_sockaddr_set_port(&ami_desc_local_address_tmp,5038,"manager.c"
,8891,__PRETTY_FUNCTION__)
;
8892
8893 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
8894 val = var->value;
8895
8896 /* read tls config options while preventing unsupported options from being set */
8897 if (strcasecmp(var->name, "tlscafile")
8898 && strcasecmp(var->name, "tlscapath")
8899 && strcasecmp(var->name, "tlscadir")
8900 && strcasecmp(var->name, "tlsverifyclient")
8901 && strcasecmp(var->name, "tlsdontverifyserver")
8902 && strcasecmp(var->name, "tlsclientmethod")
8903 && strcasecmp(var->name, "sslclientmethod")
8904 && !ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
8905 continue;
8906 }
8907
8908 if (!strcasecmp(var->name, "enabled")) {
8909 manager_enabled = ast_true(val);
8910 } else if (!strcasecmp(var->name, "webenabled")) {
8911 webmanager_enabled = ast_true(val);
8912 } else if (!strcasecmp(var->name, "port")) {
8913 int bindport;
8914 if (ast_parse_arg(val, PARSE_UINT32|PARSE_IN_RANGE, &bindport, 1024, 65535)) {
8915 ast_log(LOG_WARNING3, "manager.c", 8915, __PRETTY_FUNCTION__, "Invalid port number '%s'\n", val);
8916 }
8917 ast_sockaddr_set_port(&ami_desc_local_address_tmp, bindport)_ast_sockaddr_set_port(&ami_desc_local_address_tmp,bindport
,"manager.c",8917,__PRETTY_FUNCTION__)
;
8918 } else if (!strcasecmp(var->name, "bindaddr")) {
8919 /* remember port if it has already been set */
8920 int setport = ast_sockaddr_port(&ami_desc_local_address_tmp)_ast_sockaddr_port(&ami_desc_local_address_tmp, "manager.c"
, 8920, __PRETTY_FUNCTION__)
;
8921
8922 if (ast_parse_arg(val, PARSE_ADDR|PARSE_PORT_IGNORE, NULL((void*)0))) {
8923 ast_log(LOG_WARNING3, "manager.c", 8923, __PRETTY_FUNCTION__, "Invalid address '%s' specified, default '%s' will be used\n", val,
8924 ast_sockaddr_stringify_addr(&ami_desc_local_address_tmp));
8925 } else {
8926 ast_sockaddr_parse(&ami_desc_local_address_tmp, val, PARSE_PORT_IGNORE);
8927 }
8928
8929 if (setport) {
8930 ast_sockaddr_set_port(&ami_desc_local_address_tmp, setport)_ast_sockaddr_set_port(&ami_desc_local_address_tmp,setport
,"manager.c",8930,__PRETTY_FUNCTION__)
;
8931 }
8932
8933 } else if (!strcasecmp(var->name, "brokeneventsaction")) {
8934 broken_events_action = ast_true(val);
8935 } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
8936 allowmultiplelogin = ast_true(val);
8937 } else if (!strcasecmp(var->name, "displayconnects")) {
8938 displayconnects = ast_true(val);
8939 } else if (!strcasecmp(var->name, "timestampevents")) {
8940 timestampevents = ast_true(val);
8941 } else if (!strcasecmp(var->name, "debug")) {
8942 manager_debug = ast_true(val);
8943 } else if (!strcasecmp(var->name, "httptimeout")) {
8944 newhttptimeout = atoi(val);
8945 } else if (!strcasecmp(var->name, "authtimeout")) {
8946 int timeout = atoi(var->value);
8947
8948 if (timeout < 1) {
8949 ast_log(LOG_WARNING3, "manager.c", 8949, __PRETTY_FUNCTION__, "Invalid authtimeout value '%s', using default value\n", var->value);
8950 } else {
8951 authtimeout = timeout;
8952 }
8953 } else if (!strcasecmp(var->name, "authlimit")) {
8954 int limit = atoi(var->value);
8955
8956 if (limit < 1) {
8957 ast_log(LOG_WARNING3, "manager.c", 8957, __PRETTY_FUNCTION__, "Invalid authlimit value '%s', using default value\n", var->value);
8958 } else {
8959 authlimit = limit;
8960 }
8961 } else if (!strcasecmp(var->name, "channelvars")) {
8962 load_channelvars(var);
8963 } else {
8964 ast_log(LOG_NOTICE2, "manager.c", 8964, __PRETTY_FUNCTION__, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
8965 var->name, val);
8966 }
8967 }
8968
8969 if (manager_enabled && !subscribed) {
8970 if (subscribe_all() != 0) {
8971 ast_log(LOG_ERROR4, "manager.c", 8971, __PRETTY_FUNCTION__, "Manager subscription error\n");
8972 return -1;
8973 }
8974 }
8975
8976 ast_sockaddr_copy(&amis_desc_local_address_tmp, &amis_desc.local_address);
8977
8978 /* if the amis address has not been set, default is the same as non secure ami */
8979 if (ast_sockaddr_isnull(&amis_desc_local_address_tmp)) {
8980 ast_sockaddr_copy(&amis_desc_local_address_tmp, &ami_desc_local_address_tmp);
8981 }
8982
8983 /* if the amis address was not set, it will have non-secure ami port set; if
8984 amis address was set, we need to check that a port was set or not, if not
8985 use the default tls port */
8986 if (ast_sockaddr_port(&amis_desc_local_address_tmp)_ast_sockaddr_port(&amis_desc_local_address_tmp, "manager.c"
, 8986, __PRETTY_FUNCTION__)
== 0 ||
8987 (ast_sockaddr_port(&ami_desc_local_address_tmp)_ast_sockaddr_port(&ami_desc_local_address_tmp, "manager.c"
, 8987, __PRETTY_FUNCTION__)
== ast_sockaddr_port(&amis_desc_local_address_tmp)_ast_sockaddr_port(&amis_desc_local_address_tmp, "manager.c"
, 8987, __PRETTY_FUNCTION__)
)) {
8988
8989 ast_sockaddr_set_port(&amis_desc_local_address_tmp, DEFAULT_MANAGER_TLS_PORT)_ast_sockaddr_set_port(&amis_desc_local_address_tmp,5039,
"manager.c",8989,__PRETTY_FUNCTION__)
;
8990 }
8991
8992 if (manager_enabled) {
8993 ast_sockaddr_copy(&ami_desc.local_address, &ami_desc_local_address_tmp);
8994 ast_sockaddr_copy(&amis_desc.local_address, &amis_desc_local_address_tmp);
8995 }
8996
8997 AST_RWLIST_WRLOCK(&users)__ast_rwlock_wrlock("manager.c", 8997, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
8998
8999 /* First, get users from users.conf */
9000 ucfg = ast_config_load2("users.conf", "manager", config_flags);
9001 if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED(void *)-1) && ucfg != CONFIG_STATUS_FILEINVALID(void *)-2) {
9002 const char *hasmanager;
9003 int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
9004
9005 while ((cat = ast_category_browse(ucfg, cat))) {
9006 if (!strcasecmp(cat, "general")) {
9007 continue;
9008 }
9009
9010 hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
9011 if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
9012 const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
9013 const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
9014 const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
9015 const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
9016 const char *user_allowmultiplelogin = ast_variable_retrieve(ucfg, cat, "allowmultiplelogin");
9017 const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
9018
9019 /* Look for an existing entry,
9020 * if none found - create one and add it to the list
9021 */
9022 if (!(user = get_manager_by_name_locked(cat))) {
9023 if (!(user = ast_calloc(1, sizeof(*user))_ast_calloc((1), (sizeof(*user)), "manager.c", 9023, __PRETTY_FUNCTION__
)
)) {
9024 break;
9025 }
9026
9027 /* Copy name over */
9028 ast_copy_string(user->username, cat, sizeof(user->username));
9029 /* Insert into list */
9030 AST_LIST_INSERT_TAIL(&users, user, list)do { if (!(&users)->first) { (&users)->first = (
user); (&users)->last = (user); } else { (&users)->
last->list.next = (user); (&users)->last = (user); }
} while (0)
;
9031 user->acl = NULL((void*)0);
9032 user->keep = 1;
9033 user->readperm = -1;
9034 user->writeperm = -1;
9035 /* Default displayconnect from [general] */
9036 user->displayconnects = displayconnects;
9037 /* Default allowmultiplelogin from [general] */
9038 user->allowmultiplelogin = allowmultiplelogin;
9039 user->writetimeout = 100;
9040 }
9041
9042 if (!user_secret) {
9043 user_secret = ast_variable_retrieve(ucfg, "general", "secret");
9044 }
9045 if (!user_read) {
9046 user_read = ast_variable_retrieve(ucfg, "general", "read");
9047 }
9048 if (!user_write) {
9049 user_write = ast_variable_retrieve(ucfg, "general", "write");
9050 }
9051 if (!user_displayconnects) {
9052 user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
9053 }
9054 if (!user_allowmultiplelogin) {
9055 user_allowmultiplelogin = ast_variable_retrieve(ucfg, "general", "allowmultiplelogin");
9056 }
9057 if (!user_writetimeout) {
9058 user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
9059 }
9060
9061 if (!ast_strlen_zero(user_secret)_ast_strlen_zero(user_secret, "manager.c", __PRETTY_FUNCTION__
, 9061)
) {
9062 ast_freefree(user->secret);
9063 user->secret = ast_strdup(user_secret)_ast_strdup((user_secret), "manager.c", 9063, __PRETTY_FUNCTION__
)
;
9064 }
9065
9066 if (user_read) {
9067 user->readperm = get_perm(user_read);
9068 }
9069 if (user_write) {
9070 user->writeperm = get_perm(user_write);
9071 }
9072 if (user_displayconnects) {
9073 user->displayconnects = ast_true(user_displayconnects);
9074 }
9075 if (user_allowmultiplelogin) {
9076 user->allowmultiplelogin = ast_true(user_allowmultiplelogin);
9077 }
9078 if (user_writetimeout) {
9079 int value = atoi(user_writetimeout);
9080 if (value < 100) {
9081 ast_log(LOG_WARNING3, "manager.c", 9081, __PRETTY_FUNCTION__, "Invalid writetimeout value '%d' in users.conf\n", value);
9082 } else {
9083 user->writetimeout = value;
9084 }
9085 }
9086 }
9087 }
9088 ast_config_destroy(ucfg);
9089 }
9090
9091 /* cat is NULL here in any case */
9092
9093 while ((cat = ast_category_browse(cfg, cat))) {
9094 struct ast_acl_list *oldacl;
9095
9096 if (!strcasecmp(cat, "general")) {
9097 continue;
9098 }
9099
9100 /* Look for an existing entry, if none found - create one and add it to the list */
9101 if (!(user = get_manager_by_name_locked(cat))) {
9102 if (!(user = ast_calloc(1, sizeof(*user))_ast_calloc((1), (sizeof(*user)), "manager.c", 9102, __PRETTY_FUNCTION__
)
)) {
9103 break;
9104 }
9105 /* Copy name over */
9106 ast_copy_string(user->username, cat, sizeof(user->username));
9107
9108 user->acl = NULL((void*)0);
9109 user->readperm = 0;
9110 user->writeperm = 0;
9111 /* Default displayconnect from [general] */
9112 user->displayconnects = displayconnects;
9113 /* Default allowmultiplelogin from [general] */
9114 user->allowmultiplelogin = allowmultiplelogin;
9115 user->writetimeout = 100;
9116 user->whitefilters = ao2_container_alloc(1, NULL, NULL)__ao2_container_alloc_hash(((AO2_ALLOC_OPT_LOCK_MUTEX)), (0),
(((1))), (((((void*)0)))), (((void*)0)), (((((void*)0)))), ""
, "manager.c", 9116, __PRETTY_FUNCTION__)
;
9117 user->blackfilters = ao2_container_alloc(1, NULL, NULL)__ao2_container_alloc_hash(((AO2_ALLOC_OPT_LOCK_MUTEX)), (0),
(((1))), (((((void*)0)))), (((void*)0)), (((((void*)0)))), ""
, "manager.c", 9117, __PRETTY_FUNCTION__)
;
9118 if (!user->whitefilters || !user->blackfilters) {
9119 manager_free_user(user);
9120 break;
9121 }
9122
9123 /* Insert into list */
9124 AST_RWLIST_INSERT_TAIL(&users, user, list)do { if (!(&users)->first) { (&users)->first = (
user); (&users)->last = (user); } else { (&users)->
last->list.next = (user); (&users)->last = (user); }
} while (0)
;
9125 } else {
9126 ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters")__ao2_callback((user->whitefilters), (OBJ_UNLINK | OBJ_NODATA
| OBJ_MULTIPLE), (((void*)0)), (((void*)0)), ("unlink all white filters"
), "manager.c", 9126, __PRETTY_FUNCTION__)
;
9127 ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters")__ao2_callback((user->blackfilters), (OBJ_UNLINK | OBJ_NODATA
| OBJ_MULTIPLE), (((void*)0)), (((void*)0)), ("unlink all black filters"
), "manager.c", 9127, __PRETTY_FUNCTION__)
;
9128 }
9129
9130 /* Make sure we keep this user and don't destroy it during cleanup */
9131 user->keep = 1;
9132 oldacl = user->acl;
9133 user->acl = NULL((void*)0);
9134 ast_variables_destroy(user->chanvars);
9135
9136 var = ast_variable_browse(cfg, cat);
9137 for (; var; var = var->next) {
9138 if (!strcasecmp(var->name, "secret")) {
9139 ast_freefree(user->secret);
9140 user->secret = ast_strdup(var->value)_ast_strdup((var->value), "manager.c", 9140, __PRETTY_FUNCTION__
)
;
9141 } else if (!strcasecmp(var->name, "deny") ||
9142 !strcasecmp(var->name, "permit") ||
9143 !strcasecmp(var->name, "acl")) {
9144 int acl_error = 0;
9145
9146 ast_append_acl(var->name, var->value, &user->acl, &acl_error, &acl_subscription_flag);
9147 if (acl_error) {
9148 ast_log(LOG_ERROR4, "manager.c", 9148, __PRETTY_FUNCTION__, "Invalid ACL '%s' for manager user '%s' on line %d. Deleting user\n",
9149 var->value, user->username, var->lineno);
9150 user->keep = 0;
9151 }
9152 } else if (!strcasecmp(var->name, "read") ) {
9153 user->readperm = get_perm(var->value);
9154 } else if (!strcasecmp(var->name, "write") ) {
9155 user->writeperm = get_perm(var->value);
9156 } else if (!strcasecmp(var->name, "displayconnects") ) {
9157 user->displayconnects = ast_true(var->value);
9158 } else if (!strcasecmp(var->name, "allowmultiplelogin") ) {
9159 user->allowmultiplelogin = ast_true(var->value);
9160 } else if (!strcasecmp(var->name, "writetimeout")) {
9161 int value = atoi(var->value);
9162 if (value < 100) {
9163 ast_log(LOG_WARNING3, "manager.c", 9163, __PRETTY_FUNCTION__, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
9164 } else {
9165 user->writetimeout = value;
9166 }
9167 } else if (!strcasecmp(var->name, "setvar")) {
9168 struct ast_variable *tmpvar;
9169 char varbuf[256];
9170 char *varval;
9171 char *varname;
9172
9173 ast_copy_string(varbuf, var->value, sizeof(varbuf));
9174 varname = varbuf;
9175
9176 if ((varval = strchr(varname,'=')(__extension__ (__builtin_constant_p ('=') && !__builtin_constant_p
(varname) && ('=') == '\0' ? (char *) __rawmemchr (varname
, '=') : __builtin_strchr (varname, '=')))
)) {
9177 *varval++ = '\0';
9178 if ((tmpvar = ast_variable_new(varname, varval, ""))) {
9179 tmpvar->next = user->chanvars;
9180 user->chanvars = tmpvar;
9181 }
9182 }
9183 } else if (!strcasecmp(var->name, "eventfilter")) {
9184 const char *value = var->value;
9185 manager_add_filter(value, user->whitefilters, user->blackfilters);
9186 } else {
9187 ast_debug(1, "%s is an unknown option.\n", var->name)do { if ((option_debug >= (1) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (1)))) { ast_log(0,
"manager.c", 9187, __PRETTY_FUNCTION__, "%s is an unknown option.\n"
, var->name); } } while (0)
;
9188 }
9189 }
9190
9191 oldacl = ast_free_acl_list(oldacl);
9192 }
9193 ast_config_destroy(cfg);
9194
9195 /* Check the flag for named ACL event subscription and if we need to, register a subscription. */
9196 if (acl_subscription_flag && !by_external_config) {
9197 acl_change_stasis_subscribe();
9198 }
9199
9200 /* Perform cleanup - essentially prune out old users that no longer exist */
9201 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list){ typeof((&users)) __list_head = &users; typeof(__list_head
->first) __list_next; typeof(__list_head->first) __list_prev
= ((void*)0); typeof(__list_head->first) __list_current; for
((user) = __list_head->first, __list_current = (user), __list_next
= (user) ? (user)->list.next : ((void*)0); (user); __list_prev
= __list_current, (user) = __list_next, __list_current = (user
), __list_next = (user) ? (user)->list.next : ((void*)0), (
void) __list_prev )
{
9202 if (user->keep) { /* valid record. clear flag for the next round */
9203 user->keep = 0;
9204
9205 /* Calculate A1 for Digest auth */
9206 snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
9207 ast_md5_hash(a1_hash,a1);
9208 ast_freefree(user->a1_hash);
9209 user->a1_hash = ast_strdup(a1_hash)_ast_strdup((a1_hash), "manager.c", 9209, __PRETTY_FUNCTION__
)
;
9210 continue;
9211 }
9212 /* We do not need to keep this user so take them out of the list */
9213 AST_RWLIST_REMOVE_CURRENT(list)do { __list_current->list.next = ((void*)0); __list_current
= __list_prev; if (__list_prev) { __list_prev->list.next =
__list_next; } else { __list_head->first = __list_next; }
if (!__list_next) { __list_head->last = __list_prev; } } while
(0)
;
9214 ast_debug(4, "Pruning user '%s'\n", user->username)do { if ((option_debug >= (4) || (({ typeof ((&ast_options
)->flags) __p = (&ast_options)->flags; typeof (__unsigned_int_flags_dummy
) __x = 0; (void) (&__p == &__x); ((&ast_options)
->flags & (AST_OPT_FLAG_DEBUG_MODULE)); }) && (
int)ast_debug_get_by_module("core") >= (4)))) { ast_log(0,
"manager.c", 9214, __PRETTY_FUNCTION__, "Pruning user '%s'\n"
, user->username); } } while (0)
;
9215 manager_free_user(user);
9216 }
9217 AST_RWLIST_TRAVERSE_SAFE_END};
9218
9219 AST_RWLIST_UNLOCK(&users)__ast_rwlock_unlock("manager.c", 9219, __PRETTY_FUNCTION__, &
(&users)->lock, "&(&users)->lock")
;
9220
9221 if (webmanager_enabled && manager_enabled) {
9222 if (!webregged) {
9223 ast_http_uri_link(&rawmanuri);
9224 ast_http_uri_link(&manageruri);
9225 ast_http_uri_link(&managerxmluri);
9226
9227 ast_http_uri_link(&arawmanuri);
9228 ast_http_uri_link(&amanageruri);
9229 ast_http_uri_link(&amanagerxmluri);
9230 webregged = 1;
9231 }
9232 } else {
9233 if (webregged) {
9234 ast_http_uri_unlink(&rawmanuri);
9235 ast_http_uri_unlink(&manageruri);
9236 ast_http_uri_unlink(&managerxmluri);
9237
9238 ast_http_uri_unlink(&arawmanuri);
9239 ast_http_uri_unlink(&amanageruri);
9240 ast_http_uri_unlink(&amanagerxmluri);
9241 webregged = 0;
9242 }
9243 }
9244
9245 if (newhttptimeout > 0) {
9246 httptimeout = newhttptimeout;
9247 }
9248
9249 ast_tcptls_server_start(&ami_desc);
9250 if (tls_was_enabled && !ami_tls_cfg.enabled) {
9251 ast_tcptls_server_stop(&amis_desc);
9252 } else if (ast_ssl_setup(amis_desc.tls_cfg)) {
9253 ast_tcptls_server_start(&amis_desc);
9254 }
9255
9256 return 0;
9257}
9258
9259static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
9260 struct stasis_message *message)
9261{
9262 if (stasis_message_type(message) != ast_named_acl_change_type()) {
9263 return;
9264 }
9265
9266 /* For now, this is going to be performed simply and just execute a forced reload. */
9267 ast_log(LOG_NOTICE2, "manager.c", 9267, __PRETTY_FUNCTION__, "Reloading manager in response to ACL change event.\n");
9268 __init_manager(1, 1);
9269}
9270
9271int init_manager(void)
9272{
9273 return __init_manager(0, 0);
9274}
9275
9276int reload_manager(void)
9277{
9278 return __init_manager(1, 0);
9279}
9280
9281int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
9282{
9283 AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry)do { (datastore)->entry.next = (&s->session->datastores
)->first; (&s->session->datastores)->first = (
datastore); if (!(&s->session->datastores)->last
) (&s->session->datastores)->last = (datastore);
} while (0)
;
9284
9285 return 0;
9286}
9287
9288int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
9289{
9290 return AST_LIST_REMOVE(&s->session->datastores, datastore, entry)({ __typeof(datastore) __elm = (datastore); if (__elm) { if (
(&s->session->datastores)->first == __elm) { (&
s->session->datastores)->first = __elm->entry.next
; __elm->entry.next = ((void*)0); if ((&s->session->
datastores)->last == __elm) { (&s->session->datastores
)->last = ((void*)0); } } else { typeof(datastore) __prev =
(&s->session->datastores)->first; while (__prev
&& __prev->entry.next != __elm) { __prev = __prev
->entry.next; } if (__prev) { __prev->entry.next = __elm
->entry.next; __elm->entry.next = ((void*)0); if ((&
s->session->datastores)->last == __elm) { (&s->
session->datastores)->last = __prev; } } else { __elm =
((void*)0); } } } __elm; })
? 0 : -1;
9291}
9292
9293struct ast_datastore *astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
9294{
9295 struct ast_datastore *datastore = NULL((void*)0);
9296
9297 if (info == NULL((void*)0))
9298 return NULL((void*)0);
9299
9300 AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry){ typeof((&s->session->datastores)) __list_head = &
s->session->datastores; typeof(__list_head->first) __list_next
; typeof(__list_head->first) __list_prev = ((void*)0); typeof
(__list_head->first) __list_current; for ((datastore) = __list_head
->first, __list_current = (datastore), __list_next = (datastore
) ? (datastore)->entry.next : ((void*)0); (datastore); __list_prev
= __list_current, (datastore) = __list_next, __list_current =
(datastore), __list_next = (datastore) ? (datastore)->entry
.next : ((void*)0), (void) __list_prev )
{
9301 if (datastore->info != info) {
9302 continue;
9303 }
9304
9305 if (uid == NULL((void*)0)) {
9306 /* matched by type only */
9307 break;
9308 }
9309
9310 if ((datastore->uid != NULL((void*)0)) && !strcasecmp(uid, datastore->uid)) {
9311 /* Matched by type AND uid */
9312 break;
9313 }
9314 }
9315 AST_LIST_TRAVERSE_SAFE_END};
9316
9317 return datastore;
9318}
9319
9320int ast_str_append_event_header(struct ast_str **fields_string,
9321 const char *header, const char *value)
9322{
9323 struct ast_str *working_str = *fields_string;
9324
9325 if (!working_str) {
9326 working_str = ast_str_create(128);
9327 if (!working_str) {
9328 return -1;
9329 }
9330 *fields_string = working_str;
9331 }
9332
9333 ast_str_append(&working_str, 0,
9334 "%s: %s\r\n",
9335 header, value);
9336
9337 return 0;
9338}
9339
9340static void manager_event_blob_dtor(void *obj)
9341{
9342 struct ast_manager_event_blob *ev = obj;
9343
9344 ast_string_field_free_memory(ev)({ int __res__ = -1; if (((void *)(ev)) != ((void*)0)) { __res__
= __ast_string_field_free_memory(&(ev)->__field_mgr, &
(ev)->__field_mgr_pool, AST_STRINGFIELD_DESTROY, "manager.c"
, 9344, __PRETTY_FUNCTION__); } __res__; })
;
9345}
9346
9347struct ast_manager_event_blob *
9348__attribute__((format(printf, 3, 4)))
9349ast_manager_event_blob_create(
9350 int event_flags,
9351 const char *manager_event,
9352 const char *extra_fields_fmt,
9353 ...)
9354{
9355 struct ast_manager_event_blob *ev;
9356 va_list argp;
9357
9358 ast_assert(extra_fields_fmt != NULL)_ast_assert(extra_fields_fmt != ((void*)0), "extra_fields_fmt != NULL"
, "manager.c", 9358, __PRETTY_FUNCTION__)
;
9359 ast_assert(manager_event != NULL)_ast_assert(manager_event != ((void*)0), "manager_event != NULL"
, "manager.c", 9359, __PRETTY_FUNCTION__)
;
9360
9361 ev = ao2_alloc_options(sizeof(*ev), manager_event_blob_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK)__ao2_alloc((sizeof(*ev)), (manager_event_blob_dtor), (AO2_ALLOC_OPT_LOCK_NOLOCK
), "", "manager.c", 9361, __PRETTY_FUNCTION__)
;
9362 if (!ev) {
9363 return NULL((void*)0);
9364 }
9365
9366 if (ast_string_field_init(ev, 20)({ int __res__ = -1; if (((void *)(ev)) != ((void*)0)) { __res__
= __ast_string_field_init(&(ev)->__field_mgr, &(ev
)->__field_mgr_pool, 20, "manager.c", 9366, __PRETTY_FUNCTION__
); } __res__ ; })
) {
9367 ao2_ref(ev, -1)__ao2_ref((ev), (-1), "", "manager.c", 9367, __PRETTY_FUNCTION__
)
;
9368 return NULL((void*)0);
9369 }
9370
9371 ev->manager_event = manager_event;
9372 ev->event_flags = event_flags;
9373
9374 va_start(argp, extra_fields_fmt)__builtin_va_start(argp, extra_fields_fmt);
9375 ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt, argp)({ int __res__ = -1; if (((void *)(ev)) != ((void*)0)) { __ast_string_field_ptr_build_va
(&(ev)->__field_mgr, &(ev)->__field_mgr_pool, (
ast_string_field *) &ev->extra_fields, extra_fields_fmt
, argp); __res__ = 0; } __res__; })
;
9376 va_end(argp)__builtin_va_end(argp);
9377
9378 return ev;
9379}