Wed Jan 8 2020 09:49:48

Asterisk developer's documentation


manager.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief The Asterisk Management Interface - AMI
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \extref 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 /*! \addtogroup Group_AMI AMI functions
40 */
41 /*! @{
42  Doxygen group */
43 
44 /*** MODULEINFO
45  <support_level>core</support_level>
46  ***/
47 
48 #include "asterisk.h"
49 
50 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 423276 $")
51 
52 #include "asterisk/_private.h"
53 #include "asterisk/paths.h" /* use various ast_config_AST_* */
54 #include <ctype.h>
55 #include <sys/time.h>
56 #include <signal.h>
57 #include <sys/mman.h>
58 #include <sys/types.h>
59 #include <regex.h>
60 
61 #include "asterisk/channel.h"
62 #include "asterisk/file.h"
63 #include "asterisk/manager.h"
64 #include "asterisk/module.h"
65 #include "asterisk/config.h"
66 #include "asterisk/callerid.h"
67 #include "asterisk/lock.h"
68 #include "asterisk/cli.h"
69 #include "asterisk/app.h"
70 #include "asterisk/pbx.h"
71 #include "asterisk/md5.h"
72 #include "asterisk/acl.h"
73 #include "asterisk/utils.h"
74 #include "asterisk/tcptls.h"
75 #include "asterisk/http.h"
76 #include "asterisk/ast_version.h"
77 #include "asterisk/threadstorage.h"
78 #include "asterisk/linkedlists.h"
79 #include "asterisk/term.h"
80 #include "asterisk/astobj2.h"
81 #include "asterisk/features.h"
83 #include "asterisk/aoc.h"
84 #include "asterisk/stringfields.h"
85 
86 /*** DOCUMENTATION
87  <manager name="Ping" language="en_US">
88  <synopsis>
89  Keepalive command.
90  </synopsis>
91  <syntax>
92  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
93  </syntax>
94  <description>
95  <para>A 'Ping' action will ellicit a 'Pong' response. Used to keep the
96  manager connection open.</para>
97  </description>
98  </manager>
99  <manager name="Events" language="en_US">
100  <synopsis>
101  Control Event Flow.
102  </synopsis>
103  <syntax>
104  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
105  <parameter name="EventMask" required="true">
106  <enumlist>
107  <enum name="on">
108  <para>If all events should be sent.</para>
109  </enum>
110  <enum name="off">
111  <para>If no events should be sent.</para>
112  </enum>
113  <enum name="system,call,log,...">
114  <para>To select which flags events should have to be sent.</para>
115  </enum>
116  </enumlist>
117  </parameter>
118  </syntax>
119  <description>
120  <para>Enable/Disable sending of events to this manager client.</para>
121  </description>
122  </manager>
123  <manager name="Logoff" language="en_US">
124  <synopsis>
125  Logoff Manager.
126  </synopsis>
127  <syntax>
128  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
129  </syntax>
130  <description>
131  <para>Logoff the current manager session.</para>
132  </description>
133  </manager>
134  <manager name="Login" language="en_US">
135  <synopsis>
136  Login Manager.
137  </synopsis>
138  <syntax>
139  <parameter name="ActionID">
140  <para>ActionID for this transaction. Will be returned.</para>
141  </parameter>
142  <parameter name="Username" required="true">
143  <para>Username to login with as specified in manager.conf.</para>
144  </parameter>
145  <parameter name="Secret">
146  <para>Secret to login with as specified in manager.conf.</para>
147  </parameter>
148  </syntax>
149  <description>
150  <para>Login Manager.</para>
151  </description>
152  </manager>
153  <manager name="Challenge" language="en_US">
154  <synopsis>
155  Generate Challenge for MD5 Auth.
156  </synopsis>
157  <syntax>
158  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
159  <parameter name="AuthType" required="true">
160  <para>Digest algorithm to use in the challenge. Valid values are:</para>
161  <enumlist>
162  <enum name="MD5" />
163  </enumlist>
164  </parameter>
165  </syntax>
166  <description>
167  <para>Generate a challenge for MD5 authentication.</para>
168  </description>
169  </manager>
170  <manager name="Hangup" language="en_US">
171  <synopsis>
172  Hangup channel.
173  </synopsis>
174  <syntax>
175  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
176  <parameter name="Channel" required="true">
177  <para>The channel name to be hangup.</para>
178  </parameter>
179  <parameter name="Cause">
180  <para>Numeric hangup cause.</para>
181  </parameter>
182  </syntax>
183  <description>
184  <para>Hangup a channel.</para>
185  </description>
186  </manager>
187  <manager name="Status" language="en_US">
188  <synopsis>
189  List channel status.
190  </synopsis>
191  <syntax>
192  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
193  <parameter name="Channel" required="false">
194  <para>The name of the channel to query for status.</para>
195  </parameter>
196  <parameter name="Variables">
197  <para>Comma <literal>,</literal> separated list of variable to include.</para>
198  </parameter>
199  </syntax>
200  <description>
201  <para>Will return the status information of each channel along with the
202  value for the specified channel variables.</para>
203  </description>
204  </manager>
205  <manager name="Setvar" language="en_US">
206  <synopsis>
207  Sets a channel variable or function value.
208  </synopsis>
209  <syntax>
210  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
211  <parameter name="Channel">
212  <para>Channel to set variable for.</para>
213  </parameter>
214  <parameter name="Variable" required="true">
215  <para>Variable name, function or expression.</para>
216  </parameter>
217  <parameter name="Value" required="true">
218  <para>Variable or function value.</para>
219  </parameter>
220  </syntax>
221  <description>
222  <para>This command can be used to set the value of channel variables or dialplan
223  functions.</para>
224  <note>
225  <para>If a channel name is not provided then the variable is considered global.</para>
226  </note>
227  </description>
228  </manager>
229  <manager name="Getvar" language="en_US">
230  <synopsis>
231  Gets a channel variable or function value.
232  </synopsis>
233  <syntax>
234  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
235  <parameter name="Channel">
236  <para>Channel to read variable from.</para>
237  </parameter>
238  <parameter name="Variable" required="true">
239  <para>Variable name, function or expression.</para>
240  </parameter>
241  </syntax>
242  <description>
243  <para>Get the value of a channel variable or function return.</para>
244  <note>
245  <para>If a channel name is not provided then the variable is considered global.</para>
246  </note>
247  </description>
248  </manager>
249  <manager name="GetConfig" language="en_US">
250  <synopsis>
251  Retrieve configuration.
252  </synopsis>
253  <syntax>
254  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
255  <parameter name="Filename" required="true">
256  <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
257  </parameter>
258  <parameter name="Category">
259  <para>Category in configuration file.</para>
260  </parameter>
261  </syntax>
262  <description>
263  <para>This action will dump the contents of a configuration
264  file by category and contents or optionally by specified category only.</para>
265  </description>
266  </manager>
267  <manager name="GetConfigJSON" language="en_US">
268  <synopsis>
269  Retrieve configuration (JSON format).
270  </synopsis>
271  <syntax>
272  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
273  <parameter name="Filename" required="true">
274  <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
275  </parameter>
276  </syntax>
277  <description>
278  <para>This action will dump the contents of a configuration file by category
279  and contents in JSON format. This only makes sense to be used using rawman over
280  the HTTP interface.</para>
281  </description>
282  </manager>
283  <manager name="UpdateConfig" language="en_US">
284  <synopsis>
285  Update basic configuration.
286  </synopsis>
287  <syntax>
288  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
289  <parameter name="SrcFilename" required="true">
290  <para>Configuration filename to read (e.g. <filename>foo.conf</filename>).</para>
291  </parameter>
292  <parameter name="DstFilename" required="true">
293  <para>Configuration filename to write (e.g. <filename>foo.conf</filename>)</para>
294  </parameter>
295  <parameter name="Reload">
296  <para>Whether or not a reload should take place (or name of specific module).</para>
297  </parameter>
298  <parameter name="Action-XXXXXX">
299  <para>Action to take.</para>
300  <para>X's represent 6 digit number beginning with 000000.</para>
301  <enumlist>
302  <enum name="NewCat" />
303  <enum name="RenameCat" />
304  <enum name="DelCat" />
305  <enum name="EmptyCat" />
306  <enum name="Update" />
307  <enum name="Delete" />
308  <enum name="Append" />
309  <enum name="Insert" />
310  </enumlist>
311  </parameter>
312  <parameter name="Cat-XXXXXX">
313  <para>Category to operate on.</para>
314  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
315  </parameter>
316  <parameter name="Var-XXXXXX">
317  <para>Variable to work on.</para>
318  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
319  </parameter>
320  <parameter name="Value-XXXXXX">
321  <para>Value to work on.</para>
322  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
323  </parameter>
324  <parameter name="Match-XXXXXX">
325  <para>Extra match required to match line.</para>
326  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
327  </parameter>
328  <parameter name="Line-XXXXXX">
329  <para>Line in category to operate on (used with delete and insert actions).</para>
330  <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
331  </parameter>
332  </syntax>
333  <description>
334  <para>This action will modify, create, or delete configuration elements
335  in Asterisk configuration files.</para>
336  </description>
337  </manager>
338  <manager name="CreateConfig" language="en_US">
339  <synopsis>
340  Creates an empty file in the configuration directory.
341  </synopsis>
342  <syntax>
343  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
344  <parameter name="Filename" required="true">
345  <para>The configuration filename to create (e.g. <filename>foo.conf</filename>).</para>
346  </parameter>
347  </syntax>
348  <description>
349  <para>This action will create an empty file in the configuration
350  directory. This action is intended to be used before an UpdateConfig
351  action.</para>
352  </description>
353  </manager>
354  <manager name="ListCategories" language="en_US">
355  <synopsis>
356  List categories in configuration file.
357  </synopsis>
358  <syntax>
359  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
360  <parameter name="Filename" required="true">
361  <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
362  </parameter>
363  </syntax>
364  <description>
365  <para>This action will dump the categories in a given file.</para>
366  </description>
367  </manager>
368  <manager name="Redirect" language="en_US">
369  <synopsis>
370  Redirect (transfer) a call.
371  </synopsis>
372  <syntax>
373  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
374  <parameter name="Channel" required="true">
375  <para>Channel to redirect.</para>
376  </parameter>
377  <parameter name="ExtraChannel">
378  <para>Second call leg to transfer (optional).</para>
379  </parameter>
380  <parameter name="Exten" required="true">
381  <para>Extension to transfer to.</para>
382  </parameter>
383  <parameter name="ExtraExten">
384  <para>Extension to transfer extrachannel to (optional).</para>
385  </parameter>
386  <parameter name="Context" required="true">
387  <para>Context to transfer to.</para>
388  </parameter>
389  <parameter name="ExtraContext">
390  <para>Context to transfer extrachannel to (optional).</para>
391  </parameter>
392  <parameter name="Priority" required="true">
393  <para>Priority to transfer to.</para>
394  </parameter>
395  <parameter name="ExtraPriority">
396  <para>Priority to transfer extrachannel to (optional).</para>
397  </parameter>
398  </syntax>
399  <description>
400  <para>Redirect (transfer) a call.</para>
401  </description>
402  </manager>
403  <manager name="Atxfer" language="en_US">
404  <synopsis>
405  Attended transfer.
406  </synopsis>
407  <syntax>
408  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
409  <parameter name="Channel" required="true">
410  <para>Transferer's channel.</para>
411  </parameter>
412  <parameter name="Exten" required="true">
413  <para>Extension to transfer to.</para>
414  </parameter>
415  <parameter name="Context" required="true">
416  <para>Context to transfer to.</para>
417  </parameter>
418  <parameter name="Priority" required="true">
419  <para>Priority to transfer to.</para>
420  </parameter>
421  </syntax>
422  <description>
423  <para>Attended transfer.</para>
424  </description>
425  </manager>
426  <manager name="Originate" language="en_US">
427  <synopsis>
428  Originate a call.
429  </synopsis>
430  <syntax>
431  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
432  <parameter name="Channel" required="true">
433  <para>Channel name to call.</para>
434  </parameter>
435  <parameter name="Exten">
436  <para>Extension to use (requires <literal>Context</literal> and
437  <literal>Priority</literal>)</para>
438  </parameter>
439  <parameter name="Context">
440  <para>Context to use (requires <literal>Exten</literal> and
441  <literal>Priority</literal>)</para>
442  </parameter>
443  <parameter name="Priority">
444  <para>Priority to use (requires <literal>Exten</literal> and
445  <literal>Context</literal>)</para>
446  </parameter>
447  <parameter name="Application">
448  <para>Application to execute.</para>
449  </parameter>
450  <parameter name="Data">
451  <para>Data to use (requires <literal>Application</literal>).</para>
452  </parameter>
453  <parameter name="Timeout" default="30000">
454  <para>How long to wait for call to be answered (in ms.).</para>
455  </parameter>
456  <parameter name="CallerID">
457  <para>Caller ID to be set on the outgoing channel.</para>
458  </parameter>
459  <parameter name="Variable">
460  <para>Channel variable to set, multiple Variable: headers are allowed.</para>
461  </parameter>
462  <parameter name="Account">
463  <para>Account code.</para>
464  </parameter>
465  <parameter name="Async">
466  <para>Set to <literal>true</literal> for fast origination.</para>
467  </parameter>
468  <parameter name="Codecs">
469  <para>Comma-separated list of codecs to use for this call.</para>
470  </parameter>
471  </syntax>
472  <description>
473  <para>Generates an outgoing call to a
474  <replaceable>Extension</replaceable>/<replaceable>Context</replaceable>/<replaceable>Priority</replaceable>
475  or <replaceable>Application</replaceable>/<replaceable>Data</replaceable></para>
476  </description>
477  </manager>
478  <manager name="Command" language="en_US">
479  <synopsis>
480  Execute Asterisk CLI Command.
481  </synopsis>
482  <syntax>
483  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
484  <parameter name="Command" required="true">
485  <para>Asterisk CLI command to run.</para>
486  </parameter>
487  </syntax>
488  <description>
489  <para>Run a CLI command.</para>
490  </description>
491  </manager>
492  <manager name="ExtensionState" language="en_US">
493  <synopsis>
494  Check Extension Status.
495  </synopsis>
496  <syntax>
497  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
498  <parameter name="Exten" required="true">
499  <para>Extension to check state on.</para>
500  </parameter>
501  <parameter name="Context" required="true">
502  <para>Context for extension.</para>
503  </parameter>
504  </syntax>
505  <description>
506  <para>Report the extension state for given extension. If the extension has a hint,
507  will use devicestate to check the status of the device connected to the extension.</para>
508  <para>Will return an <literal>Extension Status</literal> message. The response will include
509  the hint for the extension and the status.</para>
510  </description>
511  </manager>
512  <manager name="AbsoluteTimeout" language="en_US">
513  <synopsis>
514  Set absolute timeout.
515  </synopsis>
516  <syntax>
517  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
518  <parameter name="Channel" required="true">
519  <para>Channel name to hangup.</para>
520  </parameter>
521  <parameter name="Timeout" required="true">
522  <para>Maximum duration of the call (sec).</para>
523  </parameter>
524  </syntax>
525  <description>
526  <para>Hangup a channel after a certain time. Acknowledges set time with
527  <literal>Timeout Set</literal> message.</para>
528  </description>
529  </manager>
530  <manager name="MailboxStatus" language="en_US">
531  <synopsis>
532  Check mailbox.
533  </synopsis>
534  <syntax>
535  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
536  <parameter name="Mailbox" required="true">
537  <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
538  </parameter>
539  </syntax>
540  <description>
541  <para>Checks a voicemail account for status.</para>
542  <para>Returns whether there are messages waiting.</para>
543  <para>Message: Mailbox Status.</para>
544  <para>Mailbox: <replaceable>mailboxid</replaceable>.</para>
545  <para>Waiting: <literal>0</literal> if messages waiting, <literal>1</literal>
546  if no messages waiting.</para>
547  </description>
548  </manager>
549  <manager name="MailboxCount" language="en_US">
550  <synopsis>
551  Check Mailbox Message Count.
552  </synopsis>
553  <syntax>
554  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
555  <parameter name="Mailbox" required="true">
556  <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
557  </parameter>
558  </syntax>
559  <description>
560  <para>Checks a voicemail account for new messages.</para>
561  <para>Returns number of urgent, new and old messages.</para>
562  <para>Message: Mailbox Message Count</para>
563  <para>Mailbox: <replaceable>mailboxid</replaceable></para>
564  <para>UrgentMessages: <replaceable>count</replaceable></para>
565  <para>NewMessages: <replaceable>count</replaceable></para>
566  <para>OldMessages: <replaceable>count</replaceable></para>
567  </description>
568  </manager>
569  <manager name="ListCommands" language="en_US">
570  <synopsis>
571  List available manager commands.
572  </synopsis>
573  <syntax>
574  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
575  </syntax>
576  <description>
577  <para>Returns the action name and synopsis for every action that
578  is available to the user.</para>
579  </description>
580  </manager>
581  <manager name="SendText" language="en_US">
582  <synopsis>
583  Send text message to channel.
584  </synopsis>
585  <syntax>
586  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
587  <parameter name="Channel" required="true">
588  <para>Channel to send message to.</para>
589  </parameter>
590  <parameter name="Message" required="true">
591  <para>Message to send.</para>
592  </parameter>
593  </syntax>
594  <description>
595  <para>Sends A Text Message to a channel while in a call.</para>
596  </description>
597  </manager>
598  <manager name="UserEvent" language="en_US">
599  <synopsis>
600  Send an arbitrary event.
601  </synopsis>
602  <syntax>
603  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
604  <parameter name="UserEvent" required="true">
605  <para>Event string to send.</para>
606  </parameter>
607  <parameter name="Header1">
608  <para>Content1.</para>
609  </parameter>
610  <parameter name="HeaderN">
611  <para>ContentN.</para>
612  </parameter>
613  </syntax>
614  <description>
615  <para>Send an event to manager sessions.</para>
616  </description>
617  </manager>
618  <manager name="WaitEvent" language="en_US">
619  <synopsis>
620  Wait for an event to occur.
621  </synopsis>
622  <syntax>
623  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
624  <parameter name="Timeout" required="true">
625  <para>Maximum time (in seconds) to wait for events, <literal>-1</literal> means forever.</para>
626  </parameter>
627  </syntax>
628  <description>
629  <para>This action will ellicit a <literal>Success</literal> response. Whenever
630  a manager event is queued. Once WaitEvent has been called on an HTTP manager
631  session, events will be generated and queued.</para>
632  </description>
633  </manager>
634  <manager name="CoreSettings" language="en_US">
635  <synopsis>
636  Show PBX core settings (version etc).
637  </synopsis>
638  <syntax>
639  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
640  </syntax>
641  <description>
642  <para>Query for Core PBX settings.</para>
643  </description>
644  </manager>
645  <manager name="CoreStatus" language="en_US">
646  <synopsis>
647  Show PBX core status variables.
648  </synopsis>
649  <syntax>
650  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
651  </syntax>
652  <description>
653  <para>Query for Core PBX status.</para>
654  </description>
655  </manager>
656  <manager name="Reload" language="en_US">
657  <synopsis>
658  Send a reload event.
659  </synopsis>
660  <syntax>
661  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
662  <parameter name="Module">
663  <para>Name of the module to reload.</para>
664  </parameter>
665  </syntax>
666  <description>
667  <para>Send a reload event.</para>
668  </description>
669  </manager>
670  <manager name="CoreShowChannels" language="en_US">
671  <synopsis>
672  List currently active channels.
673  </synopsis>
674  <syntax>
675  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
676  </syntax>
677  <description>
678  <para>List currently defined channels and some information about them.</para>
679  </description>
680  </manager>
681  <manager name="ModuleLoad" language="en_US">
682  <synopsis>
683  Module management.
684  </synopsis>
685  <syntax>
686  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
687  <parameter name="Module">
688  <para>Asterisk module name (including .so extension) or subsystem identifier:</para>
689  <enumlist>
690  <enum name="cdr" />
691  <enum name="dnsmgr" />
692  <enum name="extconfig" />
693  <enum name="enum" />
694  <enum name="manager" />
695  <enum name="http" />
696  <enum name="logger" />
697  <enum name="features" />
698  <enum name="dsp" />
699  <enum name="udptl" />
700  <enum name="indications" />
701  <enum name="cel" />
702  <enum name="plc" />
703  </enumlist>
704  </parameter>
705  <parameter name="LoadType" required="true">
706  <para>The operation to be done on module. Subsystem identifiers may only
707  be reloaded.</para>
708  <enumlist>
709  <enum name="load" />
710  <enum name="unload" />
711  <enum name="reload" />
712  </enumlist>
713  <para>If no module is specified for a <literal>reload</literal> loadtype,
714  all modules are reloaded.</para>
715  </parameter>
716  </syntax>
717  <description>
718  <para>Loads, unloads or reloads an Asterisk module in a running system.</para>
719  </description>
720  </manager>
721  <manager name="ModuleCheck" language="en_US">
722  <synopsis>
723  Check if module is loaded.
724  </synopsis>
725  <syntax>
726  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
727  <parameter name="Module" required="true">
728  <para>Asterisk module name (not including extension).</para>
729  </parameter>
730  </syntax>
731  <description>
732  <para>Checks if Asterisk module is loaded. Will return Success/Failure.
733  For success returns, the module revision number is included.</para>
734  </description>
735  </manager>
736  <manager name="AOCMessage" language="en_US">
737  <synopsis>
738  Generate an Advice of Charge message on a channel.
739  </synopsis>
740  <syntax>
741  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
742  <parameter name="Channel" required="true">
743  <para>Channel name to generate the AOC message on.</para>
744  </parameter>
745  <parameter name="ChannelPrefix">
746  <para>Partial channel prefix. By using this option one can match the beginning part
747  of a channel name without having to put the entire name in. For example
748  if a channel name is SIP/snom-00000001 and this value is set to SIP/snom, then
749  that channel matches and the message will be sent. Note however that only
750  the first matched channel has the message sent on it. </para>
751  </parameter>
752  <parameter name="MsgType" required="true">
753  <para>Defines what type of AOC message to create, AOC-D or AOC-E</para>
754  <enumlist>
755  <enum name="D" />
756  <enum name="E" />
757  </enumlist>
758  </parameter>
759  <parameter name="ChargeType" required="true">
760  <para>Defines what kind of charge this message represents.</para>
761  <enumlist>
762  <enum name="NA" />
763  <enum name="FREE" />
764  <enum name="Currency" />
765  <enum name="Unit" />
766  </enumlist>
767  </parameter>
768  <parameter name="UnitAmount(0)">
769  <para>This represents the amount of units charged. The ETSI AOC standard specifies that
770  this value along with the optional UnitType value are entries in a list. To accommodate this
771  these values take an index value starting at 0 which can be used to generate this list of
772  unit entries. For Example, If two unit entires were required this could be achieved by setting the
773  paramter UnitAmount(0)=1234 and UnitAmount(1)=5678. Note that UnitAmount at index 0 is
774  required when ChargeType=Unit, all other entries in the list are optional.
775  </para>
776  </parameter>
777  <parameter name="UnitType(0)">
778  <para>Defines the type of unit. ETSI AOC standard specifies this as an integer
779  value between 1 and 16, but this value is left open to accept any positive
780  integer. Like the UnitAmount parameter, this value represents a list entry
781  and has an index parameter that starts at 0.
782  </para>
783  </parameter>
784  <parameter name="CurrencyName">
785  <para>Specifies the currency's name. Note that this value is truncated after 10 characters.</para>
786  </parameter>
787  <parameter name="CurrencyAmount">
788  <para>Specifies the charge unit amount as a positive integer. This value is required
789  when ChargeType==Currency.</para>
790  </parameter>
791  <parameter name="CurrencyMultiplier">
792  <para>Specifies the currency multiplier. This value is required when ChargeType==Currency.</para>
793  <enumlist>
794  <enum name="OneThousandth" />
795  <enum name="OneHundredth" />
796  <enum name="OneTenth" />
797  <enum name="One" />
798  <enum name="Ten" />
799  <enum name="Hundred" />
800  <enum name="Thousand" />
801  </enumlist>
802  </parameter>
803  <parameter name="TotalType" default="Total">
804  <para>Defines what kind of AOC-D total is represented.</para>
805  <enumlist>
806  <enum name="Total" />
807  <enum name="SubTotal" />
808  </enumlist>
809  </parameter>
810  <parameter name="AOCBillingId">
811  <para>Represents a billing ID associated with an AOC-D or AOC-E message. Note
812  that only the first 3 items of the enum are valid AOC-D billing IDs</para>
813  <enumlist>
814  <enum name="Normal" />
815  <enum name="ReverseCharge" />
816  <enum name="CreditCard" />
817  <enum name="CallFwdUnconditional" />
818  <enum name="CallFwdBusy" />
819  <enum name="CallFwdNoReply" />
820  <enum name="CallDeflection" />
821  <enum name="CallTransfer" />
822  </enumlist>
823  </parameter>
824  <parameter name="ChargingAssociationId">
825  <para>Charging association identifier. This is optional for AOC-E and can be
826  set to any value between -32768 and 32767</para>
827  </parameter>
828  <parameter name="ChargingAssociationNumber">
829  <para>Represents the charging association party number. This value is optional
830  for AOC-E.</para>
831  </parameter>
832  <parameter name="ChargingAssociationPlan">
833  <para>Integer representing the charging plan associated with the ChargingAssociationNumber.
834  The value is bits 7 through 1 of the Q.931 octet containing the type-of-number and
835  numbering-plan-identification fields.</para>
836  </parameter>
837  </syntax>
838  <description>
839  <para>Generates an AOC-D or AOC-E message on a channel.</para>
840  </description>
841  </manager>
842  ***/
843 
856 };
857 
858 
859 /*!
860  * Linked list of events.
861  * Global events are appended to the list by append_event().
862  * The usecount is the number of stored pointers to the element,
863  * excluding the list pointers. So an element that is only in
864  * the list has a usecount of 0, not 1.
865  *
866  * Clients have a pointer to the last event processed, and for each
867  * of these clients we track the usecount of the elements.
868  * If we have a pointer to an entry in the list, it is safe to navigate
869  * it forward because elements will not be deleted, but only appended.
870  * The worst that can happen is seeing the pointer still NULL.
871  *
872  * When the usecount of an element drops to 0, and the element is the
873  * first in the list, we can remove it. Removal is done within the
874  * main thread, which is woken up for the purpose.
875  *
876  * For simplicity of implementation, we make sure the list is never empty.
877  */
878 struct eventqent {
879  int usecount; /*!< # of clients who still need the event */
880  int category;
881  unsigned int seq; /*!< sequence number */
882  struct timeval tv; /*!< When event was allocated */
883  AST_RWLIST_ENTRY(eventqent) eq_next;
884  char eventdata[1]; /*!< really variable size, allocated by append_event() */
885 };
886 
888 
889 static const int DEFAULT_ENABLED = 0; /*!< Default setting for manager to be enabled */
890 static const int DEFAULT_WEBENABLED = 0; /*!< Default setting for the web interface to be enabled */
891 static const int DEFAULT_DISPLAYCONNECTS = 1; /*!< Default setting for displaying manager connections */
892 static const int DEFAULT_TIMESTAMPEVENTS = 0; /*!< Default setting for timestampevents */
893 static const int DEFAULT_HTTPTIMEOUT = 60; /*!< Default manager http timeout */
894 static const int DEFAULT_BROKENEVENTSACTION = 0; /*!< Default setting for brokeneventsaction */
895 static const int DEFAULT_AUTHTIMEOUT = 30; /*!< Default setting for authtimeout */
896 static const int DEFAULT_AUTHLIMIT = 50; /*!< Default setting for authlimit */
897 static const int DEFAULT_MANAGERDEBUG = 0; /*!< Default setting for manager debug */
898 
899 static int displayconnects;
900 static int allowmultiplelogin = 1;
901 static int timestampevents;
902 static int httptimeout;
904 static int manager_enabled = 0;
905 static int webmanager_enabled = 0;
906 static int manager_debug = 0; /*!< enable some debugging code in the manager */
907 static int authtimeout;
908 static int authlimit;
909 static char *manager_channelvars;
910 
911 #define DEFAULT_REALM "asterisk"
912 static char global_realm[MAXHOSTNAMELEN]; /*!< Default realm */
913 
914 static int unauth_sessions = 0;
915 
916 
917 /*! \brief
918  * Descriptor for a manager session, either on the AMI socket or over HTTP.
919  *
920  * \note
921  * AMI session have managerid == 0; the entry is created upon a connect,
922  * and destroyed with the socket.
923  * HTTP sessions have managerid != 0, the value is used as a search key
924  * to lookup sessions (using the mansession_id cookie, or nonce key from
925  * Digest Authentication http header).
926  */
927 #define MAX_BLACKLIST_CMD_LEN 2
928 static const struct {
929  const char *words[AST_MAX_CMD_LEN];
930 } command_blacklist[] = {
931  {{ "module", "load", NULL }},
932  {{ "module", "unload", NULL }},
933  {{ "restart", "gracefully", NULL }},
934 };
935 
936 /* In order to understand what the heck is going on with the
937  * mansession_session and mansession structs, we need to have a bit of a history
938  * lesson.
939  *
940  * In the beginning, there was the mansession. The mansession contained data that was
941  * intrinsic to a manager session, such as the time that it started, the name of the logged-in
942  * user, etc. In addition to these parameters were the f and fd parameters. For typical manager
943  * sessions, these were used to represent the TCP socket over which the AMI session was taking
944  * place. It makes perfect sense for these fields to be a part of the session-specific data since
945  * the session actually defines this information.
946  *
947  * Then came the HTTP AMI sessions. With these, the f and fd fields need to be opened and closed
948  * for every single action that occurs. Thus the f and fd fields aren't really specific to the session
949  * but rather to the action that is being executed. Because a single session may execute many commands
950  * at once, some sort of safety needed to be added in order to be sure that we did not end up with fd
951  * leaks from one action overwriting the f and fd fields used by a previous action before the previous action
952  * has had a chance to properly close its handles.
953  *
954  * The initial idea to solve this was to use thread synchronization, but this prevented multiple actions
955  * from being run at the same time in a single session. Some manager actions may block for a long time, thus
956  * creating a large queue of actions to execute. In addition, this fix did not address the basic architectural
957  * issue that for HTTP manager sessions, the f and fd variables are not really a part of the session, but are
958  * part of the action instead.
959  *
960  * The new idea was to create a structure on the stack for each HTTP Manager action. This structure would
961  * contain the action-specific information, such as which file to write to. In order to maintain expectations
962  * of action handlers and not have to change the public API of the manager code, we would need to name this
963  * new stacked structure 'mansession' and contain within it the old mansession struct that we used to use.
964  * We renamed the old mansession struct 'mansession_session' to hopefully convey that what is in this structure
965  * is session-specific data. The structure that it is wrapped in, called a 'mansession' really contains action-specific
966  * data.
967  */
969  /* XXX need to document which fields it is protecting */
970  struct sockaddr_in sin; /*!< address we are connecting from */
971  FILE *f; /*!< fdopen() on the underlying fd */
972  int fd; /*!< descriptor used for output. Either the socket (AMI) or a temporary file (HTTP) */
973  int inuse; /*!< number of HTTP sessions using this entry */
974  int needdestroy; /*!< Whether an HTTP session should be destroyed */
975  pthread_t waiting_thread; /*!< Sleeping thread using this descriptor */
976  uint32_t managerid; /*!< Unique manager identifier, 0 for AMI sessions */
977  time_t sessionstart; /*!< Session start time */
978  struct timeval sessionstart_tv; /*!< Session start time */
979  time_t sessiontimeout; /*!< Session timeout if HTTP */
980  char username[80]; /*!< Logged in username */
981  char challenge[10]; /*!< Authentication challenge */
982  int authenticated; /*!< Authentication status */
983  int readperm; /*!< Authorization for reading */
984  int writeperm; /*!< Authorization for writing */
985  char inbuf[1025]; /*!< Buffer */
986  /* we use the extra byte to add a '\0' and simplify parsing */
987  int inlen; /*!< number of buffered bytes */
988  int send_events; /*!< XXX what ? */
989  struct eventqent *last_ev; /*!< last event processed. */
990  int writetimeout; /*!< Timeout for ast_carefulwrite() */
991  time_t authstart;
992  int pending_event; /*!< Pending events indicator in case when waiting_thread is NULL */
993  time_t noncetime; /*!< Timer for nonce value expiration */
996  unsigned long oldnonce; /*!< Stale nonce value */
997  unsigned long nc; /*!< incremental nonce counter */
998  AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore) datastores; /*!< Data stores on the session */
1000 };
1001 
1005 };
1006 
1007 /* In case you didn't read that giant block of text above the mansession_session struct, the
1008  * 'mansession' struct is named this solely to keep the API the same in Asterisk. This structure really
1009  * represents data that is different from Manager action to Manager action. The mansession_session pointer
1010  * contained within points to session-specific data.
1011  */
1012 struct mansession {
1015  FILE *f;
1016  int fd;
1018  int write_error:1;
1021 };
1022 
1023 static struct ao2_container *sessions = NULL;
1024 
1027  unsigned int isfunc:1;
1028  char name[0]; /* allocate off the end the real size. */
1029 };
1030 
1032 
1033 /*! \brief user descriptor, as read from the config file.
1034  *
1035  * \note It is still missing some fields -- e.g. we can have multiple permit and deny
1036  * lines which are not supported here, and readperm/writeperm/writetimeout
1037  * are not stored.
1038  */
1040  char username[80];
1041  char *secret;
1042  struct ast_ha *ha; /*!< ACL setting */
1043  int readperm; /*! Authorization for reading */
1044  int writeperm; /*! Authorization for writing */
1045  int writetimeout; /*! Per user Timeout for ast_carefulwrite() */
1046  int displayconnects; /*!< XXX unused */
1047  int keep; /*!< mark entries created on a reload */
1050  char *a1_hash; /*!< precalculated A1 for Digest auth */
1051  AST_RWLIST_ENTRY(ast_manager_user) list;
1052 };
1053 
1054 /*! \brief list of users found in the config file */
1055 static AST_RWLIST_HEAD_STATIC(users, ast_manager_user);
1056 
1057 /*! \brief list of actions registered */
1059 
1060 /*! \brief list of hooks registered */
1062 
1063 static void free_channelvars(void);
1064 
1065 static int match_filter(struct mansession *s, char *eventdata);
1066 
1067 /*!
1068  * \internal
1069  * \brief Find a registered action object.
1070  *
1071  * \param name Name of AMI action to find.
1072  *
1073  * \return Reffed action found or NULL
1074  */
1075 static struct manager_action *action_find(const char *name)
1076 {
1077  struct manager_action *act;
1078 
1079  AST_RWLIST_RDLOCK(&actions);
1080  AST_RWLIST_TRAVERSE(&actions, act, list) {
1081  if (!strcasecmp(name, act->action)) {
1082  ao2_t_ref(act, +1, "found action object");
1083  break;
1084  }
1085  }
1086  AST_RWLIST_UNLOCK(&actions);
1087 
1088  return act;
1089 }
1090 
1091 /*! \brief Add a custom hook to be called when an event is fired */
1093 {
1095  AST_RWLIST_INSERT_TAIL(&manager_hooks, hook, list);
1097 }
1098 
1099 /*! \brief Delete a custom hook to be called when an event is fired */
1101 {
1103  AST_RWLIST_REMOVE(&manager_hooks, hook, list);
1105 }
1106 
1108 {
1109  return manager_enabled;
1110 }
1111 
1113 {
1114  return (webmanager_enabled && manager_enabled);
1115 }
1116 
1117 /*!
1118  * Grab a reference to the last event, update usecount as needed.
1119  * Can handle a NULL pointer.
1120  */
1121 static struct eventqent *grab_last(void)
1122 {
1123  struct eventqent *ret;
1124 
1125  AST_RWLIST_WRLOCK(&all_events);
1126  ret = AST_RWLIST_LAST(&all_events);
1127  /* the list is never empty now, but may become so when
1128  * we optimize it in the future, so be prepared.
1129  */
1130  if (ret) {
1132  }
1133  AST_RWLIST_UNLOCK(&all_events);
1134  return ret;
1135 }
1136 
1137 /*!
1138  * Purge unused events. Remove elements from the head
1139  * as long as their usecount is 0 and there is a next element.
1140  */
1141 static void purge_events(void)
1142 {
1143  struct eventqent *ev;
1144  struct timeval now = ast_tvnow();
1145 
1146  AST_RWLIST_WRLOCK(&all_events);
1147  while ( (ev = AST_RWLIST_FIRST(&all_events)) &&
1148  ev->usecount == 0 && AST_RWLIST_NEXT(ev, eq_next)) {
1149  AST_RWLIST_REMOVE_HEAD(&all_events, eq_next);
1150  ast_free(ev);
1151  }
1152 
1153  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&all_events, ev, eq_next) {
1154  /* Never release the last event */
1155  if (!AST_RWLIST_NEXT(ev, eq_next)) {
1156  break;
1157  }
1158 
1159  /* 2.5 times whatever the HTTP timeout is (maximum 2.5 hours) is the maximum time that we will definitely cache an event */
1160  if (ev->usecount == 0 && ast_tvdiff_sec(now, ev->tv) > (httptimeout > 3600 ? 3600 : httptimeout) * 2.5) {
1161  AST_RWLIST_REMOVE_CURRENT(eq_next);
1162  ast_free(ev);
1163  }
1164  }
1166  AST_RWLIST_UNLOCK(&all_events);
1167 }
1168 
1169 /*!
1170  * helper functions to convert back and forth between
1171  * string and numeric representation of set of flags
1172  */
1173 static const struct permalias {
1174  int num;
1175  const char *label;
1176 } perms[] = {
1177  { EVENT_FLAG_SYSTEM, "system" },
1178  { EVENT_FLAG_CALL, "call" },
1179  { EVENT_FLAG_LOG, "log" },
1180  { EVENT_FLAG_VERBOSE, "verbose" },
1181  { EVENT_FLAG_COMMAND, "command" },
1182  { EVENT_FLAG_AGENT, "agent" },
1183  { EVENT_FLAG_USER, "user" },
1184  { EVENT_FLAG_CONFIG, "config" },
1185  { EVENT_FLAG_DTMF, "dtmf" },
1186  { EVENT_FLAG_REPORTING, "reporting" },
1187  { EVENT_FLAG_CDR, "cdr" },
1188  { EVENT_FLAG_DIALPLAN, "dialplan" },
1189  { EVENT_FLAG_ORIGINATE, "originate" },
1190  { EVENT_FLAG_AGI, "agi" },
1191  { EVENT_FLAG_CC, "cc" },
1192  { EVENT_FLAG_AOC, "aoc" },
1193  { EVENT_FLAG_TEST, "test" },
1194  { INT_MAX, "all" },
1195  { 0, "none" },
1196 };
1197 
1198 /*! \brief Checks to see if a string which can be used to evaluate functions should be rejected */
1199 static int function_capable_string_allowed_with_auths(const char *evaluating, int writepermlist)
1200 {
1201  if (!(writepermlist & EVENT_FLAG_SYSTEM)
1202  && (
1203  strstr(evaluating, "SHELL") || /* NoOp(${SHELL(rm -rf /)}) */
1204  strstr(evaluating, "EVAL") /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
1205  )) {
1206  return 0;
1207  }
1208  return 1;
1209 }
1210 
1211 /*! \brief Convert authority code to a list of options for a user. This will only
1212  * display those authority codes that have an explicit match on authority */
1213 static const char *user_authority_to_str(int authority, struct ast_str **res)
1214 {
1215  int i;
1216  char *sep = "";
1217 
1218  ast_str_reset(*res);
1219  for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
1220  if ((authority & perms[i].num) == perms[i].num) {
1221  ast_str_append(res, 0, "%s%s", sep, perms[i].label);
1222  sep = ",";
1223  }
1224  }
1225 
1226  if (ast_str_strlen(*res) == 0) /* replace empty string with something sensible */
1227  ast_str_append(res, 0, "<none>");
1228 
1229  return ast_str_buffer(*res);
1230 }
1231 
1232 
1233 /*! \brief Convert authority code to a list of options. Note that the EVENT_FLAG_ALL
1234  * authority will always be returned. */
1235 static const char *authority_to_str(int authority, struct ast_str **res)
1236 {
1237  int i;
1238  char *sep = "";
1239 
1240  ast_str_reset(*res);
1241  for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
1242  if (authority & perms[i].num) {
1243  ast_str_append(res, 0, "%s%s", sep, perms[i].label);
1244  sep = ",";
1245  }
1246  }
1247 
1248  if (ast_str_strlen(*res) == 0) /* replace empty string with something sensible */
1249  ast_str_append(res, 0, "<none>");
1250 
1251  return ast_str_buffer(*res);
1252 }
1253 
1254 /*! Tells you if smallstr exists inside bigstr
1255  which is delim by delim and uses no buf or stringsep
1256  ast_instring("this|that|more","this",'|') == 1;
1257 
1258  feel free to move this to app.c -anthm */
1259 static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
1260 {
1261  const char *val = bigstr, *next;
1262 
1263  do {
1264  if ((next = strchr(val, delim))) {
1265  if (!strncmp(val, smallstr, (next - val))) {
1266  return 1;
1267  } else {
1268  continue;
1269  }
1270  } else {
1271  return !strcmp(smallstr, val);
1272  }
1273  } while (*(val = (next + 1)));
1274 
1275  return 0;
1276 }
1277 
1278 static int get_perm(const char *instr)
1279 {
1280  int x = 0, ret = 0;
1281 
1282  if (!instr) {
1283  return 0;
1284  }
1285 
1286  for (x = 0; x < ARRAY_LEN(perms); x++) {
1287  if (ast_instring(instr, perms[x].label, ',')) {
1288  ret |= perms[x].num;
1289  }
1290  }
1291 
1292  return ret;
1293 }
1294 
1295 /*!
1296  * A number returns itself, false returns 0, true returns all flags,
1297  * other strings return the flags that are set.
1298  */
1299 static int strings_to_mask(const char *string)
1300 {
1301  const char *p;
1302 
1303  if (ast_strlen_zero(string)) {
1304  return -1;
1305  }
1306 
1307  for (p = string; *p; p++) {
1308  if (*p < '0' || *p > '9') {
1309  break;
1310  }
1311  }
1312  if (!*p) { /* all digits */
1313  return atoi(string);
1314  }
1315  if (ast_false(string)) {
1316  return 0;
1317  }
1318  if (ast_true(string)) { /* all permissions */
1319  int x, ret = 0;
1320  for (x = 0; x < ARRAY_LEN(perms); x++) {
1321  ret |= perms[x].num;
1322  }
1323  return ret;
1324  }
1325  return get_perm(string);
1326 }
1327 
1328 /*! \brief Unreference manager session object.
1329  If no more references, then go ahead and delete it */
1331 {
1332  int refcount = ao2_ref(s, -1);
1333  if (manager_debug) {
1334  ast_log(LOG_DEBUG, "Mansession: %p refcount now %d\n", s, refcount - 1);
1335  }
1336  return s;
1337 }
1338 
1339 static void event_filter_destructor(void *obj)
1340 {
1341  regex_t *regex_filter = obj;
1342  regfree(regex_filter);
1343 }
1344 
1345 static void session_destructor(void *obj)
1346 {
1347  struct mansession_session *session = obj;
1348  struct eventqent *eqe = session->last_ev;
1349  struct ast_datastore *datastore;
1350 
1351  /* Get rid of each of the data stores on the session */
1352  while ((datastore = AST_LIST_REMOVE_HEAD(&session->datastores, entry))) {
1353  /* Free the data store */
1354  ast_datastore_free(datastore);
1355  }
1356 
1357  if (session->f != NULL) {
1358  fflush(session->f);
1359  fclose(session->f);
1360  }
1361  if (eqe) {
1362  ast_atomic_fetchadd_int(&eqe->usecount, -1);
1363  }
1364 
1365  if (session->whitefilters) {
1366  ao2_t_ref(session->whitefilters, -1, "decrement ref for white container, should be last one");
1367  }
1368 
1369  if (session->blackfilters) {
1370  ao2_t_ref(session->blackfilters, -1, "decrement ref for black container, should be last one");
1371  }
1372 }
1373 
1374 /*! \brief Allocate manager session structure and add it to the list of sessions */
1375 static struct mansession_session *build_mansession(struct sockaddr_in sin)
1376 {
1377  struct mansession_session *newsession;
1378 
1379  if (!(newsession = ao2_alloc(sizeof(*newsession), session_destructor))) {
1380  return NULL;
1381  }
1382 
1383  if (!(newsession->whitefilters = ao2_container_alloc(1, NULL, NULL))) {
1384  ao2_ref(newsession, -1);
1385  return NULL;
1386  }
1387 
1388  if (!(newsession->blackfilters = ao2_container_alloc(1, NULL, NULL))) {
1389  ao2_ref(newsession, -1); /* session_destructor will cleanup the other filter */
1390  return NULL;
1391  }
1392 
1393  newsession->fd = -1;
1394  newsession->waiting_thread = AST_PTHREADT_NULL;
1395  newsession->writetimeout = 100;
1396  newsession->send_events = -1;
1397  newsession->sin = sin;
1398 
1399  ao2_link(sessions, newsession);
1400 
1401  return newsession;
1402 }
1403 
1404 static int mansession_cmp_fn(void *obj, void *arg, int flags)
1405 {
1406  struct mansession_session *s = obj;
1407  char *str = arg;
1408  return !strcasecmp(s->username, str) ? CMP_MATCH : 0;
1409 }
1410 
1411 static void session_destroy(struct mansession_session *s)
1412 {
1413  ao2_unlink(sessions, s);
1414  unref_mansession(s);
1415 }
1416 
1417 
1418 static int check_manager_session_inuse(const char *name)
1419 {
1420  struct mansession_session *session = ao2_find(sessions, (char *) name, 0);
1421  int inuse = 0;
1422 
1423  if (session) {
1424  inuse = 1;
1425  unref_mansession(session);
1426  }
1427  return inuse;
1428 }
1429 
1430 
1431 /*!
1432  * lookup an entry in the list of registered users.
1433  * must be called with the list lock held.
1434  */
1435 static struct ast_manager_user *get_manager_by_name_locked(const char *name)
1436 {
1437  struct ast_manager_user *user = NULL;
1438 
1439  AST_RWLIST_TRAVERSE(&users, user, list) {
1440  if (!strcasecmp(user->username, name)) {
1441  break;
1442  }
1443  }
1444 
1445  return user;
1446 }
1447 
1448 /*! \brief Get displayconnects config option.
1449  * \param session manager session to get parameter from.
1450  * \return displayconnects config option value.
1451  */
1452 static int manager_displayconnects (struct mansession_session *session)
1453 {
1454  struct ast_manager_user *user = NULL;
1455  int ret = 0;
1456 
1458  if ((user = get_manager_by_name_locked (session->username))) {
1459  ret = user->displayconnects;
1460  }
1462 
1463  return ret;
1464 }
1465 
1466 static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1467 {
1468  struct manager_action *cur;
1469  struct ast_str *authority;
1470  int num, l, which;
1471  char *ret = NULL;
1472 #ifdef AST_XML_DOCS
1473  char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
1474 #endif
1475 
1476  switch (cmd) {
1477  case CLI_INIT:
1478  e->command = "manager show command";
1479  e->usage =
1480  "Usage: manager show command <actionname> [<actionname> [<actionname> [...]]]\n"
1481  " Shows the detailed description for a specific Asterisk manager interface command.\n";
1482  return NULL;
1483  case CLI_GENERATE:
1484  l = strlen(a->word);
1485  which = 0;
1487  AST_RWLIST_TRAVERSE(&actions, cur, list) {
1488  if (!strncasecmp(a->word, cur->action, l) && ++which > a->n) {
1489  ret = ast_strdup(cur->action);
1490  break; /* make sure we exit even if ast_strdup() returns NULL */
1491  }
1492  }
1494  return ret;
1495  }
1496  authority = ast_str_alloca(80);
1497  if (a->argc < 4) {
1498  return CLI_SHOWUSAGE;
1499  }
1500 
1501 #ifdef AST_XML_DOCS
1502  /* setup the titles */
1503  term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1504  term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
1505  term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1506  term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
1507  term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
1508 #endif
1509 
1511  AST_RWLIST_TRAVERSE(&actions, cur, list) {
1512  for (num = 3; num < a->argc; num++) {
1513  if (!strcasecmp(cur->action, a->argv[num])) {
1514 #ifdef AST_XML_DOCS
1515  if (cur->docsrc == AST_XML_DOC) {
1516  char *syntax = ast_xmldoc_printable(S_OR(cur->syntax, "Not available"), 1);
1517  char *synopsis = ast_xmldoc_printable(S_OR(cur->synopsis, "Not available"), 1);
1518  char *description = ast_xmldoc_printable(S_OR(cur->description, "Not available"), 1);
1519  char *arguments = ast_xmldoc_printable(S_OR(cur->arguments, "Not available"), 1);
1520  char *seealso = ast_xmldoc_printable(S_OR(cur->seealso, "Not available"), 1);
1521  ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n",
1522  syntax_title, syntax,
1523  synopsis_title, synopsis,
1524  description_title, description,
1525  arguments_title, arguments,
1526  seealso_title, seealso);
1527  ast_free(syntax);
1528  ast_free(synopsis);
1529  ast_free(description);
1530  ast_free(arguments);
1531  ast_free(seealso);
1532  } else
1533 #endif
1534  {
1535  ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
1536  cur->action, cur->synopsis,
1537  authority_to_str(cur->authority, &authority),
1538  S_OR(cur->description, ""));
1539  }
1540  }
1541  }
1542  }
1544 
1545  return CLI_SUCCESS;
1546 }
1547 
1548 static char *handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1549 {
1550  switch (cmd) {
1551  case CLI_INIT:
1552  e->command = "manager set debug [on|off]";
1553  e->usage = "Usage: manager set debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
1554  return NULL;
1555  case CLI_GENERATE:
1556  return NULL;
1557  }
1558 
1559  if (a->argc == 3) {
1560  ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
1561  } else if (a->argc == 4) {
1562  if (!strcasecmp(a->argv[3], "on")) {
1563  manager_debug = 1;
1564  } else if (!strcasecmp(a->argv[3], "off")) {
1565  manager_debug = 0;
1566  } else {
1567  return CLI_SHOWUSAGE;
1568  }
1569  }
1570  return CLI_SUCCESS;
1571 }
1572 
1573 static char *handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1574 {
1575  struct ast_manager_user *user = NULL;
1576  int l, which;
1577  char *ret = NULL;
1578  struct ast_str *rauthority = ast_str_alloca(128);
1579  struct ast_str *wauthority = ast_str_alloca(128);
1580 
1581  switch (cmd) {
1582  case CLI_INIT:
1583  e->command = "manager show user";
1584  e->usage =
1585  " Usage: manager show user <user>\n"
1586  " Display all information related to the manager user specified.\n";
1587  return NULL;
1588  case CLI_GENERATE:
1589  l = strlen(a->word);
1590  which = 0;
1591  if (a->pos != 3) {
1592  return NULL;
1593  }
1595  AST_RWLIST_TRAVERSE(&users, user, list) {
1596  if ( !strncasecmp(a->word, user->username, l) && ++which > a->n ) {
1597  ret = ast_strdup(user->username);
1598  break;
1599  }
1600  }
1602  return ret;
1603  }
1604 
1605  if (a->argc != 4) {
1606  return CLI_SHOWUSAGE;
1607  }
1608 
1610 
1611  if (!(user = get_manager_by_name_locked(a->argv[3]))) {
1612  ast_cli(a->fd, "There is no manager called %s\n", a->argv[3]);
1614  return CLI_SUCCESS;
1615  }
1616 
1617  ast_cli(a->fd, "\n");
1618  ast_cli(a->fd,
1619  " username: %s\n"
1620  " secret: %s\n"
1621  " acl: %s\n"
1622  " read perm: %s\n"
1623  " write perm: %s\n"
1624  "displayconnects: %s\n",
1625  (user->username ? user->username : "(N/A)"),
1626  (user->secret ? "<Set>" : "(N/A)"),
1627  (user->ha ? "yes" : "no"),
1628  user_authority_to_str(user->readperm, &rauthority),
1629  user_authority_to_str(user->writeperm, &wauthority),
1630  (user->displayconnects ? "yes" : "no"));
1631 
1633 
1634  return CLI_SUCCESS;
1635 }
1636 
1637 static char *handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1638 {
1639  struct ast_manager_user *user = NULL;
1640  int count_amu = 0;
1641  switch (cmd) {
1642  case CLI_INIT:
1643  e->command = "manager show users";
1644  e->usage =
1645  "Usage: manager show users\n"
1646  " Prints a listing of all managers that are currently configured on that\n"
1647  " system.\n";
1648  return NULL;
1649  case CLI_GENERATE:
1650  return NULL;
1651  }
1652  if (a->argc != 3) {
1653  return CLI_SHOWUSAGE;
1654  }
1655 
1657 
1658  /* If there are no users, print out something along those lines */
1659  if (AST_RWLIST_EMPTY(&users)) {
1660  ast_cli(a->fd, "There are no manager users.\n");
1662  return CLI_SUCCESS;
1663  }
1664 
1665  ast_cli(a->fd, "\nusername\n--------\n");
1666 
1667  AST_RWLIST_TRAVERSE(&users, user, list) {
1668  ast_cli(a->fd, "%s\n", user->username);
1669  count_amu++;
1670  }
1671 
1673 
1674  ast_cli(a->fd,"-------------------\n"
1675  "%d manager users configured.\n", count_amu);
1676  return CLI_SUCCESS;
1677 }
1678 
1679 /*! \brief CLI command manager list commands */
1680 static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1681 {
1682  struct manager_action *cur;
1683  struct ast_str *authority;
1684 #define HSMC_FORMAT " %-15.15s %-15.15s %-55.55s\n"
1685  switch (cmd) {
1686  case CLI_INIT:
1687  e->command = "manager show commands";
1688  e->usage =
1689  "Usage: manager show commands\n"
1690  " Prints a listing of all the available Asterisk manager interface commands.\n";
1691  return NULL;
1692  case CLI_GENERATE:
1693  return NULL;
1694  }
1695  authority = ast_str_alloca(80);
1696  ast_cli(a->fd, HSMC_FORMAT, "Action", "Privilege", "Synopsis");
1697  ast_cli(a->fd, HSMC_FORMAT, "------", "---------", "--------");
1698 
1700  AST_RWLIST_TRAVERSE(&actions, cur, list) {
1701  ast_cli(a->fd, HSMC_FORMAT, cur->action, authority_to_str(cur->authority, &authority), cur->synopsis);
1702  }
1704 
1705  return CLI_SUCCESS;
1706 }
1707 
1708 /*! \brief CLI command manager list connected */
1709 static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1710 {
1711  struct mansession_session *session;
1712  time_t now = time(NULL);
1713 #define HSMCONN_FORMAT1 " %-15.15s %-15.15s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
1714 #define HSMCONN_FORMAT2 " %-15.15s %-15.15s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
1715  int count = 0;
1716  struct ao2_iterator i;
1717 
1718  switch (cmd) {
1719  case CLI_INIT:
1720  e->command = "manager show connected";
1721  e->usage =
1722  "Usage: manager show connected\n"
1723  " Prints a listing of the users that are currently connected to the\n"
1724  "Asterisk manager interface.\n";
1725  return NULL;
1726  case CLI_GENERATE:
1727  return NULL;
1728  }
1729 
1730  ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
1731 
1732  i = ao2_iterator_init(sessions, 0);
1733  while ((session = ao2_iterator_next(&i))) {
1734  ao2_lock(session);
1735  ast_cli(a->fd, HSMCONN_FORMAT2, session->username, ast_inet_ntoa(session->sin.sin_addr), (int)(session->sessionstart), (int)(now - session->sessionstart), session->fd, session->inuse, session->readperm, session->writeperm);
1736  count++;
1737  ao2_unlock(session);
1738  unref_mansession(session);
1739  }
1741  ast_cli(a->fd, "%d users connected.\n", count);
1742 
1743  return CLI_SUCCESS;
1744 }
1745 
1746 /*! \brief CLI command manager list eventq */
1747 /* Should change to "manager show connected" */
1748 static char *handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1749 {
1750  struct eventqent *s;
1751  switch (cmd) {
1752  case CLI_INIT:
1753  e->command = "manager show eventq";
1754  e->usage =
1755  "Usage: manager show eventq\n"
1756  " Prints a listing of all events pending in the Asterisk manger\n"
1757  "event queue.\n";
1758  return NULL;
1759  case CLI_GENERATE:
1760  return NULL;
1761  }
1762  AST_RWLIST_RDLOCK(&all_events);
1763  AST_RWLIST_TRAVERSE(&all_events, s, eq_next) {
1764  ast_cli(a->fd, "Usecount: %d\n", s->usecount);
1765  ast_cli(a->fd, "Category: %d\n", s->category);
1766  ast_cli(a->fd, "Event:\n%s", s->eventdata);
1767  }
1768  AST_RWLIST_UNLOCK(&all_events);
1769 
1770  return CLI_SUCCESS;
1771 }
1772 
1773 /*! \brief CLI command manager reload */
1774 static char *handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1775 {
1776  switch (cmd) {
1777  case CLI_INIT:
1778  e->command = "manager reload";
1779  e->usage =
1780  "Usage: manager reload\n"
1781  " Reloads the manager configuration.\n";
1782  return NULL;
1783  case CLI_GENERATE:
1784  return NULL;
1785  }
1786  if (a->argc > 2) {
1787  return CLI_SHOWUSAGE;
1788  }
1789  reload_manager();
1790  return CLI_SUCCESS;
1791 }
1792 
1793 static struct eventqent *advance_event(struct eventqent *e)
1794 {
1795  struct eventqent *next;
1796 
1797  AST_RWLIST_RDLOCK(&all_events);
1798  if ((next = AST_RWLIST_NEXT(e, eq_next))) {
1799  ast_atomic_fetchadd_int(&next->usecount, 1);
1801  }
1802  AST_RWLIST_UNLOCK(&all_events);
1803  return next;
1804 }
1805 
1806 #define GET_HEADER_FIRST_MATCH 0
1807 #define GET_HEADER_LAST_MATCH 1
1808 #define GET_HEADER_SKIP_EMPTY 2
1809 
1810 /*!
1811  * \brief Return a matching header value.
1812  *
1813  * \details
1814  * Generic function to return either the first or the last
1815  * matching header from a list of variables, possibly skipping
1816  * empty strings.
1817  *
1818  * \note At the moment there is only one use of this function in
1819  * this file, so we make it static.
1820  *
1821  * \note Never returns NULL.
1822  */
1823 static const char *__astman_get_header(const struct message *m, char *var, int mode)
1824 {
1825  int x, l = strlen(var);
1826  const char *result = "";
1827 
1828  if (!m) {
1829  return result;
1830  }
1831 
1832  for (x = 0; x < m->hdrcount; x++) {
1833  const char *h = m->headers[x];
1834  if (!strncasecmp(var, h, l) && h[l] == ':') {
1835  const char *value = h + l + 1;
1836  value = ast_skip_blanks(value); /* ignore leading spaces in the value */
1837  /* found a potential candidate */
1838  if ((mode & GET_HEADER_SKIP_EMPTY) && ast_strlen_zero(value)) {
1839  continue; /* not interesting */
1840  }
1841  if (mode & GET_HEADER_LAST_MATCH) {
1842  result = value; /* record the last match so far */
1843  } else {
1844  return value;
1845  }
1846  }
1847  }
1848 
1849  return result;
1850 }
1851 
1852 /*!
1853  * \brief Return the first matching variable from an array.
1854  *
1855  * \note This is the legacy function and is implemented in
1856  * therms of __astman_get_header().
1857  *
1858  * \note Never returns NULL.
1859  */
1860 const char *astman_get_header(const struct message *m, char *var)
1861 {
1863 }
1864 
1865 /*!
1866  * \internal
1867  * \brief Process one "Variable:" header value string.
1868  *
1869  * \param head Current list of AMI variables to get new values added.
1870  * \param hdr_val Header value string to process.
1871  *
1872  * \return New variable list head.
1873  */
1874 static struct ast_variable *man_do_variable_value(struct ast_variable *head, const char *hdr_val)
1875 {
1876  char *parse;
1878  AST_APP_ARG(vars)[64];
1879  );
1880 
1881  hdr_val = ast_skip_blanks(hdr_val); /* ignore leading spaces in the value */
1882  parse = ast_strdupa(hdr_val);
1883 
1884  /* Break the header value string into name=val pair items. */
1885  AST_STANDARD_APP_ARGS(args, parse);
1886  if (args.argc) {
1887  int y;
1888 
1889  /* Process each name=val pair item. */
1890  for (y = 0; y < args.argc; y++) {
1891  struct ast_variable *cur;
1892  char *var;
1893  char *val;
1894 
1895  if (!args.vars[y]) {
1896  continue;
1897  }
1898  var = val = args.vars[y];
1899  strsep(&val, "=");
1900 
1901  /* XXX We may wish to trim whitespace from the strings. */
1902  if (!val || ast_strlen_zero(var)) {
1903  continue;
1904  }
1905 
1906  /* Create new variable list node and prepend it to the list. */
1907  cur = ast_variable_new(var, val, "");
1908  if (cur) {
1909  cur->next = head;
1910  head = cur;
1911  }
1912  }
1913  }
1914 
1915  return head;
1916 }
1917 
1919 {
1921 }
1922 
1924  enum variable_orders order)
1925 {
1926  int varlen;
1927  int x;
1928  struct ast_variable *head = NULL;
1929 
1930  static const char var_hdr[] = "Variable:";
1931 
1932  /* Process all "Variable:" headers. */
1933  varlen = strlen(var_hdr);
1934  for (x = 0; x < m->hdrcount; x++) {
1935  if (strncasecmp(var_hdr, m->headers[x], varlen)) {
1936  continue;
1937  }
1938  head = man_do_variable_value(head, m->headers[x] + varlen);
1939  }
1940 
1941  if (order == ORDER_NATURAL) {
1942  head = ast_variables_reverse(head);
1943  }
1944 
1945  return head;
1946 }
1947 
1948 /* access for hooks to send action messages to ami */
1949 
1950 int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
1951 {
1952  const char *action;
1953  int ret = 0;
1954  struct manager_action *act_found;
1955  struct mansession s = {.session = NULL, };
1956  struct message m = { 0 };
1957  char *dup_str;
1958  char *src;
1959  int x = 0;
1960  int curlen;
1961 
1962  if (hook == NULL) {
1963  return -1;
1964  }
1965 
1966  /* Create our own copy of the AMI action msg string. */
1967  src = dup_str = ast_strdup(msg);
1968  if (!dup_str) {
1969  return -1;
1970  }
1971 
1972  /* convert msg string to message struct */
1973  curlen = strlen(src);
1974  for (x = 0; x < curlen; x++) {
1975  int cr; /* set if we have \r */
1976  if (src[x] == '\r' && x+1 < curlen && src[x+1] == '\n')
1977  cr = 2; /* Found. Update length to include \r\n */
1978  else if (src[x] == '\n')
1979  cr = 1; /* also accept \n only */
1980  else
1981  continue;
1982  /* don't keep empty lines */
1983  if (x && m.hdrcount < ARRAY_LEN(m.headers)) {
1984  /* ... but trim \r\n and terminate the header string */
1985  src[x] = '\0';
1986  m.headers[m.hdrcount++] = src;
1987  }
1988  x += cr;
1989  curlen -= x; /* remaining size */
1990  src += x; /* update pointer */
1991  x = -1; /* reset loop */
1992  }
1993 
1994  action = astman_get_header(&m, "Action");
1995  if (strcasecmp(action, "login")) {
1996  act_found = action_find(action);
1997  if (act_found) {
1998  /*
1999  * we have to simulate a session for this action request
2000  * to be able to pass it down for processing
2001  * This is necessary to meet the previous design of manager.c
2002  */
2003  s.hook = hook;
2004  s.f = (void*)1; /* set this to something so our request will make it through all functions that test it*/
2005 
2006  ao2_lock(act_found);
2007  if (act_found->registered && act_found->func) {
2008  ++act_found->active_count;
2009  ao2_unlock(act_found);
2010  ret = act_found->func(&s, &m);
2011  ao2_lock(act_found);
2012  --act_found->active_count;
2013  } else {
2014  ret = -1;
2015  }
2016  ao2_unlock(act_found);
2017  ao2_t_ref(act_found, -1, "done with found action object");
2018  }
2019  }
2020  ast_free(dup_str);
2021  return ret;
2022 }
2023 
2024 
2025 /*!
2026  * helper function to send a string to the socket.
2027  * Return -1 on error (e.g. buffer full).
2028  */
2029 static int send_string(struct mansession *s, char *string)
2030 {
2031  int res;
2032  FILE *f = s->f ? s->f : s->session->f;
2033  int fd = s->f ? s->fd : s->session->fd;
2034 
2035  /* It's a result from one of the hook's action invocation */
2036  if (s->hook) {
2037  /*
2038  * to send responses, we're using the same function
2039  * as for receiving events. We call the event "HookResponse"
2040  */
2041  s->hook->helper(EVENT_FLAG_HOOKRESPONSE, "HookResponse", string);
2042  return 0;
2043  }
2044 
2045  if ((res = ast_careful_fwrite(f, fd, string, strlen(string), s->session->writetimeout))) {
2046  s->write_error = 1;
2047  }
2048 
2049  return res;
2050 }
2051 
2052 /*!
2053  * \brief thread local buffer for astman_append
2054  *
2055  * \note This can not be defined within the astman_append() function
2056  * because it declares a couple of functions that get used to
2057  * initialize the thread local storage key.
2058  */
2061 
2062 /*! \brief initial allocated size for the astman_append_buf */
2063 #define ASTMAN_APPEND_BUF_INITSIZE 256
2064 
2065 /*!
2066  * utility functions for creating AMI replies
2067  */
2068 void astman_append(struct mansession *s, const char *fmt, ...)
2069 {
2070  va_list ap;
2071  struct ast_str *buf;
2072 
2074  return;
2075  }
2076 
2077  va_start(ap, fmt);
2078  ast_str_set_va(&buf, 0, fmt, ap);
2079  va_end(ap);
2080 
2081  if (s->f != NULL || s->session->f != NULL) {
2082  send_string(s, ast_str_buffer(buf));
2083  } else {
2084  ast_verbose("fd == -1 in astman_append, should not happen\n");
2085  }
2086 }
2087 
2088 /*! \note NOTE: XXX this comment is unclear and possibly wrong.
2089  Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
2090  hold the session lock _or_ be running in an action callback (in which case s->session->busy will
2091  be non-zero). In either of these cases, there is no need to lock-protect the session's
2092  fd, since no other output will be sent (events will be queued), and no input will
2093  be read until either the current action finishes or get_input() obtains the session
2094  lock.
2095  */
2096 
2097 /*! \brief send a response with an optional message,
2098  * and terminate it with an empty line.
2099  * m is used only to grab the 'ActionID' field.
2100  *
2101  * Use the explicit constant MSG_MOREDATA to remove the empty line.
2102  * XXX MSG_MOREDATA should go to a header file.
2103  */
2104 #define MSG_MOREDATA ((char *)astman_send_response)
2105 static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
2106 {
2107  const char *id = astman_get_header(m, "ActionID");
2108 
2109  astman_append(s, "Response: %s\r\n", resp);
2110  if (!ast_strlen_zero(id)) {
2111  astman_append(s, "ActionID: %s\r\n", id);
2112  }
2113  if (listflag) {
2114  astman_append(s, "EventList: %s\r\n", listflag); /* Start, complete, cancelled */
2115  }
2116  if (msg == MSG_MOREDATA) {
2117  return;
2118  } else if (msg) {
2119  astman_append(s, "Message: %s\r\n\r\n", msg);
2120  } else {
2121  astman_append(s, "\r\n");
2122  }
2123 }
2124 
2125 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
2126 {
2127  astman_send_response_full(s, m, resp, msg, NULL);
2128 }
2129 
2130 void astman_send_error(struct mansession *s, const struct message *m, char *error)
2131 {
2132  astman_send_response_full(s, m, "Error", error, NULL);
2133 }
2134 
2135 void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
2136 {
2137  astman_send_response_full(s, m, "Success", msg, NULL);
2138 }
2139 
2140 static void astman_start_ack(struct mansession *s, const struct message *m)
2141 {
2142  astman_send_response_full(s, m, "Success", MSG_MOREDATA, NULL);
2143 }
2144 
2145 void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
2146 {
2147  astman_send_response_full(s, m, "Success", msg, listflag);
2148 }
2149 
2150 /*! \brief Lock the 'mansession' structure. */
2151 static void mansession_lock(struct mansession *s)
2152 {
2153  ast_mutex_lock(&s->lock);
2154 }
2155 
2156 /*! \brief Unlock the 'mansession' structure. */
2157 static void mansession_unlock(struct mansession *s)
2158 {
2159  ast_mutex_unlock(&s->lock);
2160 }
2161 
2162 /*! \brief
2163  Rather than braindead on,off this now can also accept a specific int mask value
2164  or a ',' delim list of mask strings (the same as manager.conf) -anthm
2165 */
2166 static int set_eventmask(struct mansession *s, const char *eventmask)
2167 {
2168  int maskint = strings_to_mask(eventmask);
2169 
2170  ao2_lock(s->session);
2171  if (maskint >= 0) {
2172  s->session->send_events = maskint;
2173  }
2174  ao2_unlock(s->session);
2175 
2176  return maskint;
2177 }
2178 
2180 {
2183 }
2184 
2185 static struct sockaddr_in *mansession_encode_sin_local(const struct mansession *s,
2186  struct sockaddr_in *sin_local)
2187 {
2189  sin_local);
2190 
2191  return sin_local;
2192 }
2193 
2194 static void report_invalid_user(const struct mansession *s, const char *username)
2195 {
2196  struct sockaddr_in sin_local;
2197  char session_id[32];
2198  struct ast_security_event_inval_acct_id inval_acct_id = {
2200  .common.version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
2201  .common.service = "AMI",
2202  .common.account_id = username,
2203  .common.session_tv = &s->session->sessionstart_tv,
2204  .common.local_addr = {
2205  .sin = mansession_encode_sin_local(s, &sin_local),
2206  .transport = mansession_get_transport(s),
2207  },
2208  .common.remote_addr = {
2209  .sin = &s->session->sin,
2210  .transport = mansession_get_transport(s),
2211  },
2212  .common.session_id = session_id,
2213  };
2214 
2215  snprintf(session_id, sizeof(session_id), "%p", s);
2216 
2217  ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
2218 }
2219 
2220 static void report_failed_acl(const struct mansession *s, const char *username)
2221 {
2222  struct sockaddr_in sin_local;
2223  char session_id[32];
2224  struct ast_security_event_failed_acl failed_acl_event = {
2226  .common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
2227  .common.service = "AMI",
2228  .common.account_id = username,
2229  .common.session_tv = &s->session->sessionstart_tv,
2230  .common.local_addr = {
2231  .sin = mansession_encode_sin_local(s, &sin_local),
2232  .transport = mansession_get_transport(s),
2233  },
2234  .common.remote_addr = {
2235  .sin = &s->session->sin,
2236  .transport = mansession_get_transport(s),
2237  },
2238  .common.session_id = session_id,
2239  };
2240 
2241  snprintf(session_id, sizeof(session_id), "%p", s->session);
2242 
2243  ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
2244 }
2245 
2246 static void report_inval_password(const struct mansession *s, const char *username)
2247 {
2248  struct sockaddr_in sin_local;
2249  char session_id[32];
2250  struct ast_security_event_inval_password inval_password = {
2253  .common.service = "AMI",
2254  .common.account_id = username,
2255  .common.session_tv = &s->session->sessionstart_tv,
2256  .common.local_addr = {
2257  .sin = mansession_encode_sin_local(s, &sin_local),
2258  .transport = mansession_get_transport(s),
2259  },
2260  .common.remote_addr = {
2261  .sin = &s->session->sin,
2262  .transport = mansession_get_transport(s),
2263  },
2264  .common.session_id = session_id,
2265  };
2266 
2267  snprintf(session_id, sizeof(session_id), "%p", s->session);
2268 
2269  ast_security_event_report(AST_SEC_EVT(&inval_password));
2270 }
2271 
2272 static void report_auth_success(const struct mansession *s)
2273 {
2274  struct sockaddr_in sin_local;
2275  char session_id[32];
2276  struct ast_security_event_successful_auth successful_auth = {
2279  .common.service = "AMI",
2280  .common.account_id = s->session->username,
2281  .common.session_tv = &s->session->sessionstart_tv,
2282  .common.local_addr = {
2283  .sin = mansession_encode_sin_local(s, &sin_local),
2284  .transport = mansession_get_transport(s),
2285  },
2286  .common.remote_addr = {
2287  .sin = &s->session->sin,
2288  .transport = mansession_get_transport(s),
2289  },
2290  .common.session_id = session_id,
2291  };
2292 
2293  snprintf(session_id, sizeof(session_id), "%p", s->session);
2294 
2295  ast_security_event_report(AST_SEC_EVT(&successful_auth));
2296 }
2297 
2298 static void report_req_not_allowed(const struct mansession *s, const char *action)
2299 {
2300  struct sockaddr_in sin_local;
2301  char session_id[32];
2302  char request_type[64];
2303  struct ast_security_event_req_not_allowed req_not_allowed = {
2306  .common.service = "AMI",
2307  .common.account_id = s->session->username,
2308  .common.session_tv = &s->session->sessionstart_tv,
2309  .common.local_addr = {
2310  .sin = mansession_encode_sin_local(s, &sin_local),
2311  .transport = mansession_get_transport(s),
2312  },
2313  .common.remote_addr = {
2314  .sin = &s->session->sin,
2315  .transport = mansession_get_transport(s),
2316  },
2317  .common.session_id = session_id,
2318 
2319  .request_type = request_type,
2320  };
2321 
2322  snprintf(session_id, sizeof(session_id), "%p", s->session);
2323  snprintf(request_type, sizeof(request_type), "Action: %s", action);
2324 
2325  ast_security_event_report(AST_SEC_EVT(&req_not_allowed));
2326 }
2327 
2328 static void report_req_bad_format(const struct mansession *s, const char *action)
2329 {
2330  struct sockaddr_in sin_local;
2331  char session_id[32];
2332  char request_type[64];
2333  struct ast_security_event_req_bad_format req_bad_format = {
2336  .common.service = "AMI",
2337  .common.account_id = s->session->username,
2338  .common.session_tv = &s->session->sessionstart_tv,
2339  .common.local_addr = {
2340  .sin = mansession_encode_sin_local(s, &sin_local),
2341  .transport = mansession_get_transport(s),
2342  },
2343  .common.remote_addr = {
2344  .sin = &s->session->sin,
2345  .transport = mansession_get_transport(s),
2346  },
2347  .common.session_id = session_id,
2348 
2349  .request_type = request_type,
2350  };
2351 
2352  snprintf(session_id, sizeof(session_id), "%p", s->session);
2353  snprintf(request_type, sizeof(request_type), "Action: %s", action);
2354 
2355  ast_security_event_report(AST_SEC_EVT(&req_bad_format));
2356 }
2357 
2358 static void report_failed_challenge_response(const struct mansession *s,
2359  const char *response, const char *expected_response)
2360 {
2361  struct sockaddr_in sin_local;
2362  char session_id[32];
2363  struct ast_security_event_chal_resp_failed chal_resp_failed = {
2366  .common.service = "AMI",
2367  .common.account_id = s->session->username,
2368  .common.session_tv = &s->session->sessionstart_tv,
2369  .common.local_addr = {
2370  .sin = mansession_encode_sin_local(s, &sin_local),
2371  .transport = mansession_get_transport(s),
2372  },
2373  .common.remote_addr = {
2374  .sin = &s->session->sin,
2375  .transport = mansession_get_transport(s),
2376  },
2377  .common.session_id = session_id,
2378 
2379  .challenge = s->session->challenge,
2380  .response = response,
2381  .expected_response = expected_response,
2382  };
2383 
2384  snprintf(session_id, sizeof(session_id), "%p", s->session);
2385 
2386  ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
2387 }
2388 
2389 static void report_session_limit(const struct mansession *s)
2390 {
2391  struct sockaddr_in sin_local;
2392  char session_id[32];
2393  struct ast_security_event_session_limit session_limit = {
2395  .common.version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
2396  .common.service = "AMI",
2397  .common.account_id = s->session->username,
2398  .common.session_tv = &s->session->sessionstart_tv,
2399  .common.local_addr = {
2400  .sin = mansession_encode_sin_local(s, &sin_local),
2401  .transport = mansession_get_transport(s),
2402  },
2403  .common.remote_addr = {
2404  .sin = &s->session->sin,
2405  .transport = mansession_get_transport(s),
2406  },
2407  .common.session_id = session_id,
2408  };
2409 
2410  snprintf(session_id, sizeof(session_id), "%p", s->session);
2411 
2412  ast_security_event_report(AST_SEC_EVT(&session_limit));
2413 }
2414 
2415 /*
2416  * Here we start with action_ handlers for AMI actions,
2417  * and the internal functions used by them.
2418  * Generally, the handlers are called action_foo()
2419  */
2420 
2421 /* helper function for action_login() */
2422 static int authenticate(struct mansession *s, const struct message *m)
2423 {
2424  const char *username = astman_get_header(m, "Username");
2425  const char *password = astman_get_header(m, "Secret");
2426  int error = -1;
2427  struct ast_manager_user *user = NULL;
2428  regex_t *regex_filter;
2429  struct ao2_iterator filter_iter;
2430  struct ast_sockaddr addr;
2431 
2432  if (ast_strlen_zero(username)) { /* missing username */
2433  return -1;
2434  }
2435 
2436  /* locate user in locked state */
2438 
2439  ast_sockaddr_from_sin(&addr, &s->session->sin);
2440 
2441  if (!(user = get_manager_by_name_locked(username))) {
2442  report_invalid_user(s, username);
2443  ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
2444  } else if (user->ha && !ast_apply_ha(user->ha, &addr)) {
2445  report_failed_acl(s, username);
2446  ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
2447  } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
2448  const char *key = astman_get_header(m, "Key");
2449  if (!ast_strlen_zero(key) && !ast_strlen_zero(s->session->challenge) && user->secret) {
2450  int x;
2451  int len = 0;
2452  char md5key[256] = "";
2453  struct MD5Context md5;
2454  unsigned char digest[16];
2455 
2456  MD5Init(&md5);
2457  MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
2458  MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
2459  MD5Final(digest, &md5);
2460  for (x = 0; x < 16; x++)
2461  len += sprintf(md5key + len, "%2.2x", (unsigned)digest[x]);
2462  if (!strcmp(md5key, key)) {
2463  error = 0;
2464  } else {
2465  report_failed_challenge_response(s, key, md5key);
2466  }
2467  } else {
2468  ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
2469  S_OR(s->session->challenge, ""));
2470  }
2471  } else if (user->secret) {
2472  if (!strcmp(password, user->secret)) {
2473  error = 0;
2474  } else {
2475  report_inval_password(s, username);
2476  }
2477  }
2478 
2479  if (error) {
2480  ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
2482  return -1;
2483  }
2484 
2485  /* auth complete */
2486 
2487  /* All of the user parameters are copied to the session so that in the event
2488  * of a reload and a configuration change, the session parameters are not
2489  * changed. */
2490  ast_copy_string(s->session->username, username, sizeof(s->session->username));
2491  s->session->readperm = user->readperm;
2492  s->session->writeperm = user->writeperm;
2493  s->session->writetimeout = user->writetimeout;
2494 
2495  filter_iter = ao2_iterator_init(user->whitefilters, 0);
2496  while ((regex_filter = ao2_iterator_next(&filter_iter))) {
2497  ao2_t_link(s->session->whitefilters, regex_filter, "add white user filter to session");
2498  ao2_t_ref(regex_filter, -1, "remove iterator ref");
2499  }
2500  ao2_iterator_destroy(&filter_iter);
2501 
2502  filter_iter = ao2_iterator_init(user->blackfilters, 0);
2503  while ((regex_filter = ao2_iterator_next(&filter_iter))) {
2504  ao2_t_link(s->session->blackfilters, regex_filter, "add black user filter to session");
2505  ao2_t_ref(regex_filter, -1, "remove iterator ref");
2506  }
2507  ao2_iterator_destroy(&filter_iter);
2508 
2509  s->session->sessionstart = time(NULL);
2511  set_eventmask(s, astman_get_header(m, "Events"));
2512 
2514 
2516  return 0;
2517 }
2518 
2519 static int action_ping(struct mansession *s, const struct message *m)
2520 {
2521  const char *actionid = astman_get_header(m, "ActionID");
2522  struct timeval now = ast_tvnow();
2523 
2524  astman_append(s, "Response: Success\r\n");
2525  if (!ast_strlen_zero(actionid)){
2526  astman_append(s, "ActionID: %s\r\n", actionid);
2527  }
2528  astman_append(
2529  s,
2530  "Ping: Pong\r\n"
2531  "Timestamp: %ld.%06lu\r\n"
2532  "\r\n",
2533  (long) now.tv_sec, (unsigned long) now.tv_usec);
2534  return 0;
2535 }
2536 
2537 static int action_getconfig(struct mansession *s, const struct message *m)
2538 {
2539  struct ast_config *cfg;
2540  const char *fn = astman_get_header(m, "Filename");
2541  const char *category = astman_get_header(m, "Category");
2542  int catcount = 0;
2543  int lineno = 0;
2544  char *cur_category = NULL;
2545  struct ast_variable *v;
2546  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
2547 
2548  if (ast_strlen_zero(fn)) {
2549  astman_send_error(s, m, "Filename not specified");
2550  return 0;
2551  }
2552  cfg = ast_config_load2(fn, "manager", config_flags);
2553  if (cfg == CONFIG_STATUS_FILEMISSING) {
2554  astman_send_error(s, m, "Config file not found");
2555  return 0;
2556  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
2557  astman_send_error(s, m, "Config file has invalid format");
2558  return 0;
2559  }
2560 
2561  astman_start_ack(s, m);
2562  while ((cur_category = ast_category_browse(cfg, cur_category))) {
2563  if (ast_strlen_zero(category) || (!ast_strlen_zero(category) && !strcmp(category, cur_category))) {
2564  lineno = 0;
2565  astman_append(s, "Category-%06d: %s\r\n", catcount, cur_category);
2566  for (v = ast_variable_browse(cfg, cur_category); v; v = v->next) {
2567  astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
2568  }
2569  catcount++;
2570  }
2571  }
2572  if (!ast_strlen_zero(category) && catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
2573  astman_append(s, "No categories found\r\n");
2574  }
2575  ast_config_destroy(cfg);
2576  astman_append(s, "\r\n");
2577 
2578  return 0;
2579 }
2580 
2581 static int action_listcategories(struct mansession *s, const struct message *m)
2582 {
2583  struct ast_config *cfg;
2584  const char *fn = astman_get_header(m, "Filename");
2585  char *category = NULL;
2586  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
2587  int catcount = 0;
2588 
2589  if (ast_strlen_zero(fn)) {
2590  astman_send_error(s, m, "Filename not specified");
2591  return 0;
2592  }
2593  if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
2594  astman_send_error(s, m, "Config file not found");
2595  return 0;
2596  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
2597  astman_send_error(s, m, "Config file has invalid format");
2598  return 0;
2599  }
2600  astman_start_ack(s, m);
2601  while ((category = ast_category_browse(cfg, category))) {
2602  astman_append(s, "Category-%06d: %s\r\n", catcount, category);
2603  catcount++;
2604  }
2605  if (catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
2606  astman_append(s, "Error: no categories found\r\n");
2607  }
2608  ast_config_destroy(cfg);
2609  astman_append(s, "\r\n");
2610 
2611  return 0;
2612 }
2613 
2614 
2615 
2616 
2617 /*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
2618 static void json_escape(char *out, const char *in)
2619 {
2620  for (; *in; in++) {
2621  if (*in == '\\' || *in == '\"') {
2622  *out++ = '\\';
2623  }
2624  *out++ = *in;
2625  }
2626  *out = '\0';
2627 }
2628 
2629 /*!
2630  * \internal
2631  * \brief Append a JSON escaped string to the manager stream.
2632  *
2633  * \param s AMI stream to append a string.
2634  * \param str String to append to the stream after JSON escaping it.
2635  *
2636  * \return Nothing
2637  */
2638 static void astman_append_json(struct mansession *s, const char *str)
2639 {
2640  char *buf;
2641 
2642  buf = ast_alloca(2 * strlen(str) + 1);
2643  json_escape(buf, str);
2644  astman_append(s, "%s", buf);
2645 }
2646 
2647 static int action_getconfigjson(struct mansession *s, const struct message *m)
2648 {
2649  struct ast_config *cfg;
2650  const char *fn = astman_get_header(m, "Filename");
2651  char *category = NULL;
2652  struct ast_variable *v;
2653  int comma1 = 0;
2654  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
2655 
2656  if (ast_strlen_zero(fn)) {
2657  astman_send_error(s, m, "Filename not specified");
2658  return 0;
2659  }
2660 
2661  if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
2662  astman_send_error(s, m, "Config file not found");
2663  return 0;
2664  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
2665  astman_send_error(s, m, "Config file has invalid format");
2666  return 0;
2667  }
2668 
2669  astman_start_ack(s, m);
2670  astman_append(s, "JSON: {");
2671  while ((category = ast_category_browse(cfg, category))) {
2672  int comma2 = 0;
2673 
2674  astman_append(s, "%s\"", comma1 ? "," : "");
2675  astman_append_json(s, category);
2676  astman_append(s, "\":[");
2677  comma1 = 1;
2678  for (v = ast_variable_browse(cfg, category); v; v = v->next) {
2679  astman_append(s, "%s\"", comma2 ? "," : "");
2680  astman_append_json(s, v->name);
2681  astman_append(s, "\":\"");
2682  astman_append_json(s, v->value);
2683  astman_append(s, "\"");
2684  comma2 = 1;
2685  }
2686  astman_append(s, "]");
2687  }
2688  astman_append(s, "}\r\n\r\n");
2689 
2690  ast_config_destroy(cfg);
2691 
2692  return 0;
2693 }
2694 
2695 /* helper function for action_updateconfig */
2696 static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
2697 {
2698  int x;
2699  char hdr[40];
2700  const char *action, *cat, *var, *value, *match, *line;
2701  struct ast_category *category;
2702  struct ast_variable *v;
2703  struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
2704  enum error_type result = 0;
2705 
2706  for (x = 0; x < 100000; x++) { /* 100000 = the max number of allowed updates + 1 */
2707  unsigned int object = 0;
2708 
2709  snprintf(hdr, sizeof(hdr), "Action-%06d", x);
2710  action = astman_get_header(m, hdr);
2711  if (ast_strlen_zero(action)) /* breaks the for loop if no action header */
2712  break; /* this could cause problems if actions come in misnumbered */
2713 
2714  snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
2715  cat = astman_get_header(m, hdr);
2716  if (ast_strlen_zero(cat)) { /* every action needs a category */
2717  result = UNSPECIFIED_CATEGORY;
2718  break;
2719  }
2720 
2721  snprintf(hdr, sizeof(hdr), "Var-%06d", x);
2722  var = astman_get_header(m, hdr);
2723 
2724  snprintf(hdr, sizeof(hdr), "Value-%06d", x);
2725  value = astman_get_header(m, hdr);
2726 
2727  if (!ast_strlen_zero(value) && *value == '>') {
2728  object = 1;
2729  value++;
2730  }
2731 
2732  snprintf(hdr, sizeof(hdr), "Match-%06d", x);
2733  match = astman_get_header(m, hdr);
2734 
2735  snprintf(hdr, sizeof(hdr), "Line-%06d", x);
2736  line = astman_get_header(m, hdr);
2737 
2738  if (!strcasecmp(action, "newcat")) {
2739  if (ast_category_get(cfg,cat)) { /* check to make sure the cat doesn't */
2740  result = FAILURE_NEWCAT; /* already exist */
2741  break;
2742  }
2743  if (!(category = ast_category_new(cat, dfn, -1))) {
2744  result = FAILURE_ALLOCATION;
2745  break;
2746  }
2747  if (ast_strlen_zero(match)) {
2748  ast_category_append(cfg, category);
2749  } else {
2750  if (ast_category_insert(cfg, category, match)) {
2751  result = FAILURE_NEWCAT;
2752  ast_category_destroy(category);
2753  break;
2754  }
2755  }
2756  } else if (!strcasecmp(action, "renamecat")) {
2757  if (ast_strlen_zero(value)) {
2758  result = UNSPECIFIED_ARGUMENT;
2759  break;
2760  }
2761  if (!(category = ast_category_get(cfg, cat))) {
2762  result = UNKNOWN_CATEGORY;
2763  break;
2764  }
2765  ast_category_rename(category, value);
2766  } else if (!strcasecmp(action, "delcat")) {
2767  if (ast_category_delete(cfg, cat)) {
2768  result = FAILURE_DELCAT;
2769  break;
2770  }
2771  } else if (!strcasecmp(action, "emptycat")) {
2772  if (ast_category_empty(cfg, cat)) {
2773  result = FAILURE_EMPTYCAT;
2774  break;
2775  }
2776  } else if (!strcasecmp(action, "update")) {
2777  if (ast_strlen_zero(var)) {
2778  result = UNSPECIFIED_ARGUMENT;
2779  break;
2780  }
2781  if (!(category = ast_category_get(cfg,cat))) {
2782  result = UNKNOWN_CATEGORY;
2783  break;
2784  }
2785  if (ast_variable_update(category, var, value, match, object)) {
2786  result = FAILURE_UPDATE;
2787  break;
2788  }
2789  } else if (!strcasecmp(action, "delete")) {
2790  if ((ast_strlen_zero(var) && ast_strlen_zero(line))) {
2791  result = UNSPECIFIED_ARGUMENT;
2792  break;
2793  }
2794  if (!(category = ast_category_get(cfg, cat))) {
2795  result = UNKNOWN_CATEGORY;
2796  break;
2797  }
2798  if (ast_variable_delete(category, var, match, line)) {
2799  result = FAILURE_DELETE;
2800  break;
2801  }
2802  } else if (!strcasecmp(action, "append")) {
2803  if (ast_strlen_zero(var)) {
2804  result = UNSPECIFIED_ARGUMENT;
2805  break;
2806  }
2807  if (!(category = ast_category_get(cfg, cat))) {
2808  result = UNKNOWN_CATEGORY;
2809  break;
2810  }
2811  if (!(v = ast_variable_new(var, value, dfn))) {
2812  result = FAILURE_ALLOCATION;
2813  break;
2814  }
2815  if (object || (match && !strcasecmp(match, "object"))) {
2816  v->object = 1;
2817  }
2818  ast_variable_append(category, v);
2819  } else if (!strcasecmp(action, "insert")) {
2820  if (ast_strlen_zero(var) || ast_strlen_zero(line)) {
2821  result = UNSPECIFIED_ARGUMENT;
2822  break;
2823  }
2824  if (!(category = ast_category_get(cfg, cat))) {
2825  result = UNKNOWN_CATEGORY;
2826  break;
2827  }
2828  if (!(v = ast_variable_new(var, value, dfn))) {
2829  result = FAILURE_ALLOCATION;
2830  break;
2831  }
2832  ast_variable_insert(category, v, line);
2833  }
2834  else {
2835  ast_log(LOG_WARNING, "Action-%06d: %s not handled\n", x, action);
2836  result = UNKNOWN_ACTION;
2837  break;
2838  }
2839  }
2840  ast_free(str1);
2841  ast_free(str2);
2842  return result;
2843 }
2844 
2845 static int action_updateconfig(struct mansession *s, const struct message *m)
2846 {
2847  struct ast_config *cfg;
2848  const char *sfn = astman_get_header(m, "SrcFilename");
2849  const char *dfn = astman_get_header(m, "DstFilename");
2850  int res;
2851  const char *rld = astman_get_header(m, "Reload");
2852  struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
2853  enum error_type result;
2854 
2855  if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
2856  astman_send_error(s, m, "Filename not specified");
2857  return 0;
2858  }
2859  if (!(cfg = ast_config_load2(sfn, "manager", config_flags))) {
2860  astman_send_error(s, m, "Config file not found");
2861  return 0;
2862  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
2863  astman_send_error(s, m, "Config file has invalid format");
2864  return 0;
2865  }
2866  result = handle_updates(s, m, cfg, dfn);
2867  if (!result) {
2868  ast_include_rename(cfg, sfn, dfn); /* change the include references from dfn to sfn, so things match up */
2869  res = ast_config_text_file_save(dfn, cfg, "Manager");
2870  ast_config_destroy(cfg);
2871  if (res) {
2872  astman_send_error(s, m, "Save of config failed");
2873  return 0;
2874  }
2875  astman_send_ack(s, m, NULL);
2876  if (!ast_strlen_zero(rld)) {
2877  if (ast_true(rld)) {
2878  rld = NULL;
2879  }
2880  ast_module_reload(rld);
2881  }
2882  } else {
2883  ast_config_destroy(cfg);
2884  switch(result) {
2885  case UNKNOWN_ACTION:
2886  astman_send_error(s, m, "Unknown action command");
2887  break;
2888  case UNKNOWN_CATEGORY:
2889  astman_send_error(s, m, "Given category does not exist");
2890  break;
2891  case UNSPECIFIED_CATEGORY:
2892  astman_send_error(s, m, "Category not specified");
2893  break;
2894  case UNSPECIFIED_ARGUMENT:
2895  astman_send_error(s, m, "Problem with category, value, or line (if required)");
2896  break;
2897  case FAILURE_ALLOCATION:
2898  astman_send_error(s, m, "Memory allocation failure, this should not happen");
2899  break;
2900  case FAILURE_NEWCAT:
2901  astman_send_error(s, m, "Create category did not complete successfully");
2902  break;
2903  case FAILURE_DELCAT:
2904  astman_send_error(s, m, "Delete category did not complete successfully");
2905  break;
2906  case FAILURE_EMPTYCAT:
2907  astman_send_error(s, m, "Empty category did not complete successfully");
2908  break;
2909  case FAILURE_UPDATE:
2910  astman_send_error(s, m, "Update did not complete successfully");
2911  break;
2912  case FAILURE_DELETE:
2913  astman_send_error(s, m, "Delete did not complete successfully");
2914  break;
2915  case FAILURE_APPEND:
2916  astman_send_error(s, m, "Append did not complete successfully");
2917  break;
2918  }
2919  }
2920  return 0;
2921 }
2922 
2923 static int action_createconfig(struct mansession *s, const struct message *m)
2924 {
2925  int fd;
2926  const char *fn = astman_get_header(m, "Filename");
2927  struct ast_str *filepath = ast_str_alloca(PATH_MAX);
2928  ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
2929  ast_str_append(&filepath, 0, "%s", fn);
2930 
2931  if ((fd = open(ast_str_buffer(filepath), O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
2932  close(fd);
2933  astman_send_ack(s, m, "New configuration file created successfully");
2934  } else {
2935  astman_send_error(s, m, strerror(errno));
2936  }
2937 
2938  return 0;
2939 }
2940 
2941 static int action_waitevent(struct mansession *s, const struct message *m)
2942 {
2943  const char *timeouts = astman_get_header(m, "Timeout");
2944  int timeout = -1;
2945  int x;
2946  int needexit = 0;
2947  const char *id = astman_get_header(m, "ActionID");
2948  char idText[256];
2949 
2950  if (!ast_strlen_zero(id)) {
2951  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2952  } else {
2953  idText[0] = '\0';
2954  }
2955 
2956  if (!ast_strlen_zero(timeouts)) {
2957  sscanf(timeouts, "%30i", &timeout);
2958  if (timeout < -1) {
2959  timeout = -1;
2960  }
2961  /* XXX maybe put an upper bound, or prevent the use of 0 ? */
2962  }
2963 
2964  ao2_lock(s->session);
2966  pthread_kill(s->session->waiting_thread, SIGURG);
2967  }
2968 
2969  if (s->session->managerid) { /* AMI-over-HTTP session */
2970  /*
2971  * Make sure the timeout is within the expire time of the session,
2972  * as the client will likely abort the request if it does not see
2973  * data coming after some amount of time.
2974  */
2975  time_t now = time(NULL);
2976  int max = s->session->sessiontimeout - now - 10;
2977 
2978  if (max < 0) { /* We are already late. Strange but possible. */
2979  max = 0;
2980  }
2981  if (timeout < 0 || timeout > max) {
2982  timeout = max;
2983  }
2984  if (!s->session->send_events) { /* make sure we record events */
2985  s->session->send_events = -1;
2986  }
2987  }
2988  ao2_unlock(s->session);
2989 
2990  /* XXX should this go inside the lock ? */
2991  s->session->waiting_thread = pthread_self(); /* let new events wake up this thread */
2992  ast_debug(1, "Starting waiting for an event!\n");
2993 
2994  for (x = 0; x < timeout || timeout < 0; x++) {
2995  ao2_lock(s->session);
2996  if (AST_RWLIST_NEXT(s->session->last_ev, eq_next)) {
2997  needexit = 1;
2998  }
2999  /* We can have multiple HTTP session point to the same mansession entry.
3000  * The way we deal with it is not very nice: newcomers kick out the previous
3001  * HTTP session. XXX this needs to be improved.
3002  */
3003  if (s->session->waiting_thread != pthread_self()) {
3004  needexit = 1;
3005  }
3006  if (s->session->needdestroy) {
3007  needexit = 1;
3008  }
3009  ao2_unlock(s->session);
3010  if (needexit) {
3011  break;
3012  }
3013  if (s->session->managerid == 0) { /* AMI session */
3014  if (ast_wait_for_input(s->session->fd, 1000)) {
3015  break;
3016  }
3017  } else { /* HTTP session */
3018  sleep(1);
3019  }
3020  }
3021  ast_debug(1, "Finished waiting for an event!\n");
3022 
3023  ao2_lock(s->session);
3024  if (s->session->waiting_thread == pthread_self()) {
3025  struct eventqent *eqe = s->session->last_ev;
3026  astman_send_response(s, m, "Success", "Waiting for Event completed.");
3027  while ((eqe = advance_event(eqe))) {
3028  if (((s->session->readperm & eqe->category) == eqe->category)
3029  && ((s->session->send_events & eqe->category) == eqe->category)
3030  && match_filter(s, eqe->eventdata)) {
3031  astman_append(s, "%s", eqe->eventdata);
3032  }
3033  s->session->last_ev = eqe;
3034  }
3035  astman_append(s,
3036  "Event: WaitEventComplete\r\n"
3037  "%s"
3038  "\r\n", idText);
3040  } else {
3041  ast_debug(1, "Abandoning event request!\n");
3042  }
3043  ao2_unlock(s->session);
3044 
3045  return 0;
3046 }
3047 
3048 static int action_listcommands(struct mansession *s, const struct message *m)
3049 {
3050  struct manager_action *cur;
3051  struct ast_str *temp = ast_str_alloca(256);
3052 
3053  astman_start_ack(s, m);
3055  AST_RWLIST_TRAVERSE(&actions, cur, list) {
3056  if ((s->session->writeperm & cur->authority) || cur->authority == 0) {
3057  astman_append(s, "%s: %s (Priv: %s)\r\n",
3058  cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
3059  }
3060  }
3062  astman_append(s, "\r\n");
3063 
3064  return 0;
3065 }
3066 
3067 static int action_events(struct mansession *s, const struct message *m)
3068 {
3069  const char *mask = astman_get_header(m, "EventMask");
3070  int res, x;
3071  const char *id = astman_get_header(m, "ActionID");
3072  char id_text[256];
3073 
3074  if (!ast_strlen_zero(id)) {
3075  snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
3076  } else {
3077  id_text[0] = '\0';
3078  }
3079 
3080  res = set_eventmask(s, mask);
3081  if (broken_events_action) {
3082  /* if this option is set we should not return a response on
3083  * error, or when all events are set */
3084 
3085  if (res > 0) {
3086  for (x = 0; x < ARRAY_LEN(perms); x++) {
3087  if (!strcasecmp(perms[x].label, "all") && res == perms[x].num) {
3088  return 0;
3089  }
3090  }
3091  astman_append(s, "Response: Success\r\n%s"
3092  "Events: On\r\n\r\n", id_text);
3093  } else if (res == 0)
3094  astman_append(s, "Response: Success\r\n%s"
3095  "Events: Off\r\n\r\n", id_text);
3096  return 0;
3097  }
3098 
3099  if (res > 0)
3100  astman_append(s, "Response: Success\r\n%s"
3101  "Events: On\r\n\r\n", id_text);
3102  else if (res == 0)
3103  astman_append(s, "Response: Success\r\n%s"
3104  "Events: Off\r\n\r\n", id_text);
3105  else
3106  astman_send_error(s, m, "Invalid event mask");
3107 
3108  return 0;
3109 }
3110 
3111 static int action_logoff(struct mansession *s, const struct message *m)
3112 {
3113  astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
3114  return -1;
3115 }
3116 
3117 static int action_login(struct mansession *s, const struct message *m)
3118 {
3119 
3120  /* still authenticated - don't process again */
3121  if (s->session->authenticated) {
3122  astman_send_ack(s, m, "Already authenticated");
3123  return 0;
3124  }
3125 
3126  if (authenticate(s, m)) {
3127  sleep(1);
3128  astman_send_error(s, m, "Authentication failed");
3129  return -1;
3130  }
3131  s->session->authenticated = 1;
3133  if (manager_displayconnects(s->session)) {
3134  ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
3135  }
3136  astman_send_ack(s, m, "Authentication accepted");
3140  struct ast_str *auth = ast_str_alloca(80);
3141  const char *cat_str = authority_to_str(EVENT_FLAG_SYSTEM, &auth);
3142  astman_append(s, "Event: FullyBooted\r\n"
3143  "Privilege: %s\r\n"
3144  "Status: Fully Booted\r\n\r\n", cat_str);
3145  }
3146  return 0;
3147 }
3148 
3149 static int action_challenge(struct mansession *s, const struct message *m)
3150 {
3151  const char *authtype = astman_get_header(m, "AuthType");
3152 
3153  if (!strcasecmp(authtype, "MD5")) {
3154  if (ast_strlen_zero(s->session->challenge)) {
3155  snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
3156  }
3157  mansession_lock(s);
3158  astman_start_ack(s, m);
3159  astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
3160  mansession_unlock(s);
3161  } else {
3162  astman_send_error(s, m, "Must specify AuthType");
3163  }
3164  return 0;
3165 }
3166 
3167 static int action_hangup(struct mansession *s, const struct message *m)
3168 {
3169  struct ast_channel *c = NULL;
3170  int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
3171  const char *name = astman_get_header(m, "Channel");
3172  const char *cause = astman_get_header(m, "Cause");
3173 
3174  if (ast_strlen_zero(name)) {
3175  astman_send_error(s, m, "No channel specified");
3176  return 0;
3177  }
3178 
3179  if (!ast_strlen_zero(cause)) {
3180  char *endptr;
3181  causecode = strtol(cause, &endptr, 10);
3182  if (causecode < 0 || causecode > 127 || *endptr != '\0') {
3183  ast_log(LOG_NOTICE, "Invalid 'Cause: %s' in manager action Hangup\n", cause);
3184  /* keep going, better to hangup without cause than to not hang up at all */
3185  causecode = 0; /* do not set channel's hangupcause */
3186  }
3187  }
3188 
3189  if (!(c = ast_channel_get_by_name(name))) {
3190  astman_send_error(s, m, "No such channel");
3191  return 0;
3192  }
3193 
3194  ast_channel_lock(c);
3195  if (causecode > 0) {
3196  ast_debug(1, "Setting hangupcause of channel %s to %d (is %d now)\n",
3197  c->name, causecode, c->hangupcause);
3198  c->hangupcause = causecode;
3199  }
3201  ast_channel_unlock(c);
3202 
3203  c = ast_channel_unref(c);
3204 
3205  astman_send_ack(s, m, "Channel Hungup");
3206 
3207  return 0;
3208 }
3209 
3210 static int action_setvar(struct mansession *s, const struct message *m)
3211 {
3212  struct ast_channel *c = NULL;
3213  const char *name = astman_get_header(m, "Channel");
3214  const char *varname = astman_get_header(m, "Variable");
3215  const char *varval = astman_get_header(m, "Value");
3216  int res = 0;
3217 
3218  if (ast_strlen_zero(varname)) {
3219  astman_send_error(s, m, "No variable specified");
3220  return 0;
3221  }
3222 
3223  if (!ast_strlen_zero(name)) {
3224  if (!(c = ast_channel_get_by_name(name))) {
3225  astman_send_error(s, m, "No such channel");
3226  return 0;
3227  }
3228  }
3229 
3230  res = pbx_builtin_setvar_helper(c, varname, S_OR(varval, ""));
3231 
3232  if (c) {
3233  c = ast_channel_unref(c);
3234  }
3235  if (res == 0) {
3236  astman_send_ack(s, m, "Variable Set");
3237  } else {
3238  astman_send_error(s, m, "Variable not set");
3239  }
3240  return 0;
3241 }
3242 
3243 static int action_getvar(struct mansession *s, const struct message *m)
3244 {
3245  struct ast_channel *c = NULL;
3246  const char *name = astman_get_header(m, "Channel");
3247  const char *varname = astman_get_header(m, "Variable");
3248  char *varval;
3249  char workspace[1024];
3250 
3251  if (ast_strlen_zero(varname)) {
3252  astman_send_error(s, m, "No variable specified");
3253  return 0;
3254  }
3255 
3256  /* We don't want users with insufficient permissions using certain functions. */
3258  astman_send_error(s, m, "GetVar Access Forbidden: Variable");
3259  return 0;
3260  }
3261 
3262  if (!ast_strlen_zero(name)) {
3263  if (!(c = ast_channel_get_by_name(name))) {
3264  astman_send_error(s, m, "No such channel");
3265  return 0;
3266  }
3267  }
3268 
3269  workspace[0] = '\0';
3270  if (varname[strlen(varname) - 1] == ')') {
3271  if (!c) {
3273  if (c) {
3274  ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
3275  } else
3276  ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
3277  } else {
3278  ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
3279  }
3280  varval = workspace;
3281  } else {
3282  pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
3283  }
3284 
3285  if (c) {
3286  c = ast_channel_unref(c);
3287  }
3288 
3289  astman_start_ack(s, m);
3290  astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, S_OR(varval, ""));
3291 
3292  return 0;
3293 }
3294 
3295 /*! \brief Manager "status" command to show channels */
3296 /* Needs documentation... */
3297 static int action_status(struct mansession *s, const struct message *m)
3298 {
3299  const char *name = astman_get_header(m, "Channel");
3300  const char *cvariables = astman_get_header(m, "Variables");
3301  char *variables = ast_strdupa(S_OR(cvariables, ""));
3302  struct ast_channel *c;
3303  char bridge[256];
3304  struct timeval now = ast_tvnow();
3305  long elapsed_seconds = 0;
3306  int channels = 0;
3307  int all = ast_strlen_zero(name); /* set if we want all channels */
3308  const char *id = astman_get_header(m, "ActionID");
3309  char idText[256];
3310  AST_DECLARE_APP_ARGS(vars,
3311  AST_APP_ARG(name)[100];
3312  );
3313  struct ast_str *str = ast_str_create(1000);
3314  struct ast_channel_iterator *iter = NULL;
3315 
3316  if (!ast_strlen_zero(id)) {
3317  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
3318  } else {
3319  idText[0] = '\0';
3320  }
3321 
3323  astman_send_error(s, m, "Status Access Forbidden: Variables");
3324  return 0;
3325  }
3326 
3327  if (all) {
3328  if (!(iter = ast_channel_iterator_all_new())) {
3329  ast_free(str);
3330  astman_send_error(s, m, "Memory Allocation Failure");
3331  return 1;
3332  }
3333  c = ast_channel_iterator_next(iter);
3334  } else {
3335  if (!(c = ast_channel_get_by_name(name))) {
3336  astman_send_error(s, m, "No such channel");
3337  ast_free(str);
3338  return 0;
3339  }
3340  }
3341 
3342  astman_send_ack(s, m, "Channel status will follow");
3343 
3344  if (!ast_strlen_zero(cvariables)) {
3345  AST_STANDARD_APP_ARGS(vars, variables);
3346  }
3347 
3348  /* if we look by name, we break after the first iteration */
3349  for (; c; c = ast_channel_iterator_next(iter)) {
3350  ast_channel_lock(c);
3351 
3352  if (!ast_strlen_zero(cvariables)) {
3353  int i;
3354  ast_str_reset(str);
3355  for (i = 0; i < vars.argc; i++) {
3356  char valbuf[512], *ret = NULL;
3357 
3358  if (vars.name[i][strlen(vars.name[i]) - 1] == ')') {
3359  if (ast_func_read(c, vars.name[i], valbuf, sizeof(valbuf)) < 0) {
3360  valbuf[0] = '\0';
3361  }
3362  ret = valbuf;
3363  } else {
3364  pbx_retrieve_variable(c, vars.name[i], &ret, valbuf, sizeof(valbuf), NULL);
3365  }
3366 
3367  ast_str_append(&str, 0, "Variable: %s=%s\r\n", vars.name[i], ret);
3368  }
3369  }
3370 
3371  channels++;
3372  if (c->_bridge) {
3373  snprintf(bridge, sizeof(bridge), "BridgedChannel: %s\r\nBridgedUniqueid: %s\r\n", c->_bridge->name, c->_bridge->uniqueid);
3374  } else {
3375  bridge[0] = '\0';
3376  }
3377  if (c->pbx) {
3378  if (c->cdr) {
3379  elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
3380  }
3381  astman_append(s,
3382  "Event: Status\r\n"
3383  "Privilege: Call\r\n"
3384  "Channel: %s\r\n"
3385  "CallerIDNum: %s\r\n"
3386  "CallerIDName: %s\r\n"
3387  "ConnectedLineNum: %s\r\n"
3388  "ConnectedLineName: %s\r\n"
3389  "Accountcode: %s\r\n"
3390  "ChannelState: %u\r\n"
3391  "ChannelStateDesc: %s\r\n"
3392  "Context: %s\r\n"
3393  "Extension: %s\r\n"
3394  "Priority: %d\r\n"
3395  "Seconds: %ld\r\n"
3396  "%s"
3397  "Uniqueid: %s\r\n"
3398  "%s"
3399  "%s"
3400  "\r\n",
3401  c->name,
3402  S_COR(c->caller.id.number.valid, c->caller.id.number.str, "<unknown>"),
3403  S_COR(c->caller.id.name.valid, c->caller.id.name.str, "<unknown>"),
3404  S_COR(c->connected.id.number.valid, c->connected.id.number.str, "<unknown>"),
3405  S_COR(c->connected.id.name.valid, c->connected.id.name.str, "<unknown>"),
3406  c->accountcode,
3407  c->_state,
3408  ast_state2str(c->_state), c->context,
3409  c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, ast_str_buffer(str), idText);
3410  } else {
3411  astman_append(s,
3412  "Event: Status\r\n"
3413  "Privilege: Call\r\n"
3414  "Channel: %s\r\n"
3415  "CallerIDNum: %s\r\n"
3416  "CallerIDName: %s\r\n"
3417  "ConnectedLineNum: %s\r\n"
3418  "ConnectedLineName: %s\r\n"
3419  "Account: %s\r\n"
3420  "State: %s\r\n"
3421  "%s"
3422  "Uniqueid: %s\r\n"
3423  "%s"
3424  "%s"
3425  "\r\n",
3426  c->name,
3427  S_COR(c->caller.id.number.valid, c->caller.id.number.str, "<unknown>"),
3428  S_COR(c->caller.id.name.valid, c->caller.id.name.str, "<unknown>"),
3429  S_COR(c->connected.id.number.valid, c->connected.id.number.str, "<unknown>"),
3430  S_COR(c->connected.id.name.valid, c->connected.id.name.str, "<unknown>"),
3431  c->accountcode,
3432  ast_state2str(c->_state), bridge, c->uniqueid,
3433  ast_str_buffer(str), idText);
3434  }
3435 
3436  ast_channel_unlock(c);
3437  c = ast_channel_unref(c);
3438 
3439  if (!all) {
3440  break;
3441  }
3442  }
3443 
3444  if (iter) {
3446  }
3447 
3448  astman_append(s,
3449  "Event: StatusComplete\r\n"
3450  "%s"
3451  "Items: %d\r\n"
3452  "\r\n", idText, channels);
3453 
3454  ast_free(str);
3455 
3456  return 0;
3457 }
3458 
3459 static int action_sendtext(struct mansession *s, const struct message *m)
3460 {
3461  struct ast_channel *c = NULL;
3462  const char *name = astman_get_header(m, "Channel");
3463  const char *textmsg = astman_get_header(m, "Message");
3464  int res = 0;
3465 
3466  if (ast_strlen_zero(name)) {
3467  astman_send_error(s, m, "No channel specified");
3468  return 0;
3469  }
3470 
3471  if (ast_strlen_zero(textmsg)) {
3472  astman_send_error(s, m, "No Message specified");
3473  return 0;
3474  }
3475 
3476  if (!(c = ast_channel_get_by_name(name))) {
3477  astman_send_error(s, m, "No such channel");
3478  return 0;
3479  }
3480 
3481  res = ast_sendtext(c, textmsg);
3482  c = ast_channel_unref(c);
3483 
3484  if (res >= 0) {
3485  astman_send_ack(s, m, "Success");
3486  } else {
3487  astman_send_error(s, m, "Failure");
3488  }
3489 
3490  return 0;
3491 }
3492 
3493 /*! \brief action_redirect: The redirect manager command */
3494 static int action_redirect(struct mansession *s, const struct message *m)
3495 {
3496  char buf[256];
3497  const char *name = astman_get_header(m, "Channel");
3498  const char *name2 = astman_get_header(m, "ExtraChannel");
3499  const char *exten = astman_get_header(m, "Exten");
3500  const char *exten2 = astman_get_header(m, "ExtraExten");
3501  const char *context = astman_get_header(m, "Context");
3502  const char *context2 = astman_get_header(m, "ExtraContext");
3503  const char *priority = astman_get_header(m, "Priority");
3504  const char *priority2 = astman_get_header(m, "ExtraPriority");
3505  struct ast_channel *chan;
3506  struct ast_channel *chan2;
3507  int pi = 0;
3508  int pi2 = 0;
3509  int res;
3510 
3511  if (ast_strlen_zero(name)) {
3512  astman_send_error(s, m, "Channel not specified");
3513  return 0;
3514  }
3515 
3516  if (ast_strlen_zero(context)) {
3517  astman_send_error(s, m, "Context not specified");
3518  return 0;
3519  }
3520  if (ast_strlen_zero(exten)) {
3521  astman_send_error(s, m, "Exten not specified");
3522  return 0;
3523  }
3524  if (ast_strlen_zero(priority)) {
3525  astman_send_error(s, m, "Priority not specified");
3526  return 0;
3527  }
3528  if (sscanf(priority, "%30d", &pi) != 1) {
3529  pi = ast_findlabel_extension(NULL, context, exten, priority, NULL);
3530  }
3531  if (pi < 1) {
3532  astman_send_error(s, m, "Priority is invalid");
3533  return 0;
3534  }
3535 
3536  if (!ast_strlen_zero(name2) && !ast_strlen_zero(context2)) {
3537  /* We have an ExtraChannel and an ExtraContext */
3538  if (ast_strlen_zero(exten2)) {
3539  astman_send_error(s, m, "ExtraExten not specified");
3540  return 0;
3541  }
3542  if (ast_strlen_zero(priority2)) {
3543  astman_send_error(s, m, "ExtraPriority not specified");
3544  return 0;
3545  }
3546  if (sscanf(priority2, "%30d", &pi2) != 1) {
3547  pi2 = ast_findlabel_extension(NULL, context2, exten2, priority2, NULL);
3548  }
3549  if (pi2 < 1) {
3550  astman_send_error(s, m, "ExtraPriority is invalid");
3551  return 0;
3552  }
3553  }
3554 
3555  chan = ast_channel_get_by_name(name);
3556  if (!chan) {
3557  snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
3558  astman_send_error(s, m, buf);
3559  return 0;
3560  }
3561  if (ast_check_hangup_locked(chan)) {
3562  astman_send_error(s, m, "Redirect failed, channel not up.");
3563  chan = ast_channel_unref(chan);
3564  return 0;
3565  }
3566 
3567  if (ast_strlen_zero(name2)) {
3568  /* Single channel redirect in progress. */
3569  if (chan->pbx) {
3570  ast_channel_lock(chan);
3571  /* don't let the after-bridge code run the h-exten */
3573  ast_channel_unlock(chan);
3574  }
3575  res = ast_async_goto(chan, context, exten, pi);
3576  if (!res) {
3577  astman_send_ack(s, m, "Redirect successful");
3578  } else {
3579  astman_send_error(s, m, "Redirect failed");
3580  }
3581  chan = ast_channel_unref(chan);
3582  return 0;
3583  }
3584 
3585  chan2 = ast_channel_get_by_name(name2);
3586  if (!chan2) {
3587  snprintf(buf, sizeof(buf), "ExtraChannel does not exist: %s", name2);
3588  astman_send_error(s, m, buf);
3589  chan = ast_channel_unref(chan);
3590  return 0;
3591  }
3592  if (ast_check_hangup_locked(chan2)) {
3593  astman_send_error(s, m, "Redirect failed, extra channel not up.");
3594  chan2 = ast_channel_unref(chan2);
3595  chan = ast_channel_unref(chan);
3596  return 0;
3597  }
3598 
3599  /* Dual channel redirect in progress. */
3600  if (chan->pbx) {
3601  ast_channel_lock(chan);
3602  /* don't let the after-bridge code run the h-exten */
3605  ast_channel_unlock(chan);
3606  }
3607  if (chan2->pbx) {
3608  ast_channel_lock(chan2);
3609  /* don't let the after-bridge code run the h-exten */
3612  ast_channel_unlock(chan2);
3613  }
3614  res = ast_async_goto(chan, context, exten, pi);
3615  if (!res) {
3616  if (!ast_strlen_zero(context2)) {
3617  res = ast_async_goto(chan2, context2, exten2, pi2);
3618  } else {
3619  res = ast_async_goto(chan2, context, exten, pi);
3620  }
3621  if (!res) {
3622  astman_send_ack(s, m, "Dual Redirect successful");
3623  } else {
3624  astman_send_error(s, m, "Secondary redirect failed");
3625  }
3626  } else {
3627  astman_send_error(s, m, "Redirect failed");
3628  }
3629 
3630  /* Release the bridge wait. */
3631  if (chan->pbx) {
3632  ast_channel_lock(chan);
3634  ast_channel_unlock(chan);
3635  }
3636  if (chan2->pbx) {
3637  ast_channel_lock(chan2);
3639  ast_channel_unlock(chan2);
3640  }
3641 
3642  chan2 = ast_channel_unref(chan2);
3643  chan = ast_channel_unref(chan);
3644  return 0;
3645 }
3646 
3647 static int action_atxfer(struct mansession *s, const struct message *m)
3648 {
3649  const char *name = astman_get_header(m, "Channel");
3650  const char *exten = astman_get_header(m, "Exten");
3651  const char *context = astman_get_header(m, "Context");
3652  struct ast_channel *chan = NULL;
3653  struct ast_call_feature *atxfer_feature = NULL;
3654  char *feature_code = NULL;
3655 
3656  if (ast_strlen_zero(name)) {
3657  astman_send_error(s, m, "No channel specified");
3658  return 0;
3659  }
3660  if (ast_strlen_zero(exten)) {
3661  astman_send_error(s, m, "No extension specified");
3662  return 0;
3663  }
3664 
3665  if (!(atxfer_feature = ast_find_call_feature("atxfer"))) {
3666  astman_send_error(s, m, "No attended transfer feature found");
3667  return 0;
3668  }
3669 
3670  if (!(chan = ast_channel_get_by_name(name))) {
3671  astman_send_error(s, m, "Channel specified does not exist");
3672  return 0;
3673  }
3674 
3675  if (!ast_strlen_zero(context)) {
3676  pbx_builtin_setvar_helper(chan, "TRANSFER_CONTEXT", context);
3677  }
3678 
3679  for (feature_code = atxfer_feature->exten; feature_code && *feature_code; ++feature_code) {
3680  struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *feature_code };
3681  ast_queue_frame(chan, &f);
3682  }
3683 
3684  for (feature_code = (char *)exten; feature_code && *feature_code; ++feature_code) {
3685  struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *feature_code };
3686  ast_queue_frame(chan, &f);
3687  }
3688 
3689  chan = ast_channel_unref(chan);
3690 
3691  astman_send_ack(s, m, "Atxfer successfully queued");
3692 
3693  return 0;
3694 }
3695 
3696 static int check_blacklist(const char *cmd)
3697 {
3698  char *cmd_copy, *cur_cmd;
3699  char *cmd_words[MAX_BLACKLIST_CMD_LEN] = { NULL, };
3700  int i;
3701 
3702  cmd_copy = ast_strdupa(cmd);
3703  for (i = 0; i < MAX_BLACKLIST_CMD_LEN && (cur_cmd = strsep(&cmd_copy, " ")); i++) {
3704  cur_cmd = ast_strip(cur_cmd);
3705  if (ast_strlen_zero(cur_cmd)) {
3706  i--;
3707  continue;
3708  }
3709 
3710  cmd_words[i] = cur_cmd;
3711  }
3712 
3713  for (i = 0; i < ARRAY_LEN(command_blacklist); i++) {
3714  int j, match = 1;
3715 
3716  for (j = 0; command_blacklist[i].words[j]; j++) {
3717  if (ast_strlen_zero(cmd_words[j]) || strcasecmp(cmd_words[j], command_blacklist[i].words[j])) {
3718  match = 0;
3719  break;
3720  }
3721  }
3722 
3723  if (match) {
3724  return 1;
3725  }
3726  }
3727 
3728  return 0;
3729 }
3730 
3731 /*! \brief Manager command "command" - execute CLI command */
3732 static int action_command(struct mansession *s, const struct message *m)
3733 {
3734  const char *cmd = astman_get_header(m, "Command");
3735  const char *id = astman_get_header(m, "ActionID");
3736  char *buf = NULL, *final_buf = NULL;
3737  char template[] = "/tmp/ast-ami-XXXXXX"; /* template for temporary file */
3738  int fd;
3739  off_t l;
3740 
3741  if (ast_strlen_zero(cmd)) {
3742  astman_send_error(s, m, "No command provided");
3743  return 0;
3744  }
3745 
3746  if (check_blacklist(cmd)) {
3747  astman_send_error(s, m, "Command blacklisted");
3748  return 0;
3749  }
3750 
3751  if ((fd = mkstemp(template)) < 0) {
3752  ast_log(AST_LOG_WARNING, "Failed to create temporary file for command: %s\n", strerror(errno));
3753  astman_send_error(s, m, "Command response construction error");
3754  return 0;
3755  }
3756 
3757  astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
3758  if (!ast_strlen_zero(id)) {
3759  astman_append(s, "ActionID: %s\r\n", id);
3760  }
3761  /* FIXME: Wedge a ActionID response in here, waiting for later changes */
3762  ast_cli_command(fd, cmd); /* XXX need to change this to use a FILE * */
3763  /* Determine number of characters available */
3764  if ((l = lseek(fd, 0, SEEK_END)) < 0) {
3765  ast_log(LOG_WARNING, "Failed to determine number of characters for command: %s\n", strerror(errno));
3766  goto action_command_cleanup;
3767  }
3768 
3769  /* This has a potential to overflow the stack. Hence, use the heap. */
3770  buf = ast_malloc(l + 1);
3771  final_buf = ast_malloc(l + 1);
3772 
3773  if (!buf || !final_buf) {
3774  ast_log(LOG_WARNING, "Failed to allocate memory for temporary buffer\n");
3775  goto action_command_cleanup;
3776  }
3777 
3778  if (lseek(fd, 0, SEEK_SET) < 0) {
3779  ast_log(LOG_WARNING, "Failed to set position on temporary file for command: %s\n", strerror(errno));
3780  goto action_command_cleanup;
3781  }
3782 
3783  if (read(fd, buf, l) < 0) {
3784  ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
3785  goto action_command_cleanup;
3786  }
3787 
3788  buf[l] = '\0';
3789  term_strip(final_buf, buf, l);
3790  final_buf[l] = '\0';
3791  astman_append(s, "%s", final_buf);
3792 
3793 action_command_cleanup:
3794 
3795  close(fd);
3796  unlink(template);
3797  astman_append(s, "--END COMMAND--\r\n\r\n");
3798 
3799  ast_free(buf);
3800  ast_free(final_buf);
3801 
3802  return 0;
3803 }
3804 
3805 /*! \brief helper function for originate */
3807  int timeout;
3808  format_t format; /*!< Codecs used for a call */
3810  AST_STRING_FIELD(tech);
3811  /*! data can contain a channel name, extension number, username, password, etc. */
3814  AST_STRING_FIELD(appdata);
3819  AST_STRING_FIELD(idtext);
3820  AST_STRING_FIELD(account);
3821  );
3822  int priority;
3824 };
3825 
3826 /*!
3827  * \internal
3828  *
3829  * \param doomed Struct to destroy.
3830  *
3831  * \return Nothing
3832  */
3834 {
3835  ast_variables_destroy(doomed->vars);
3837  ast_free(doomed);
3838 }
3839 
3840 static void *fast_originate(void *data)
3841 {
3842  struct fast_originate_helper *in = data;
3843  int res;
3844  int reason = 0;
3845  struct ast_channel *chan = NULL, *chans[1];
3846  char requested_channel[AST_CHANNEL_NAME];
3847 
3848  if (!ast_strlen_zero(in->app)) {
3849  res = ast_pbx_outgoing_app(in->tech, in->format, (char *) in->data,
3850  in->timeout, in->app, in->appdata, &reason, 1,
3851  S_OR(in->cid_num, NULL),
3852  S_OR(in->cid_name, NULL),
3853  in->vars, in->account, &chan);
3854  } else {
3855  res = ast_pbx_outgoing_exten(in->tech, in->format, (char *) in->data,
3856  in->timeout, in->context, in->exten, in->priority, &reason, 1,
3857  S_OR(in->cid_num, NULL),
3858  S_OR(in->cid_name, NULL),
3859  in->vars, in->account, &chan);
3860  }
3861  /* Any vars memory was passed to the ast_pbx_outgoing_xxx() calls. */
3862  in->vars = NULL;
3863 
3864  if (!chan) {
3865  snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
3866  }
3867  /* Tell the manager what happened with the channel */
3868  chans[0] = chan;
3869  ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans,
3870  "%s"
3871  "Response: %s\r\n"
3872  "Channel: %s\r\n"
3873  "Context: %s\r\n"
3874  "Exten: %s\r\n"
3875  "Reason: %d\r\n"
3876  "Uniqueid: %s\r\n"
3877  "CallerIDNum: %s\r\n"
3878  "CallerIDName: %s\r\n",
3879  in->idtext, res ? "Failure" : "Success",
3880  chan ? chan->name : requested_channel, in->context, in->exten, reason,
3881  chan ? chan->uniqueid : "<null>",
3882  S_OR(in->cid_num, "<unknown>"),
3883  S_OR(in->cid_name, "<unknown>")
3884  );
3885 
3886  /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
3887  if (chan) {
3888  ast_channel_unlock(chan);
3889  }
3891  return NULL;
3892 }
3893 
3894 static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
3895 {
3896  const char *unitamount;
3897  const char *unittype;
3898  struct ast_str *str = ast_str_alloca(32);
3899 
3900  memset(entry, 0, sizeof(*entry));
3901 
3902  ast_str_set(&str, 0, "UnitAmount(%u)", entry_num);
3903  unitamount = astman_get_header(m, ast_str_buffer(str));
3904 
3905  ast_str_set(&str, 0, "UnitType(%u)", entry_num);
3906  unittype = astman_get_header(m, ast_str_buffer(str));
3907 
3908  if (!ast_strlen_zero(unitamount) && (sscanf(unitamount, "%30u", &entry->amount) == 1)) {
3909  entry->valid_amount = 1;
3910  }
3911 
3912  if (!ast_strlen_zero(unittype) && sscanf(unittype, "%30u", &entry->type) == 1) {
3913  entry->valid_type = 1;
3914  }
3915 
3916  return 0;
3917 }
3918 
3919 static int action_aocmessage(struct mansession *s, const struct message *m)
3920 {
3921  const char *channel = astman_get_header(m, "Channel");
3922  const char *pchannel = astman_get_header(m, "ChannelPrefix");
3923  const char *msgtype = astman_get_header(m, "MsgType");
3924  const char *chargetype = astman_get_header(m, "ChargeType");
3925  const char *currencyname = astman_get_header(m, "CurrencyName");
3926  const char *currencyamount = astman_get_header(m, "CurrencyAmount");
3927  const char *mult = astman_get_header(m, "CurrencyMultiplier");
3928  const char *totaltype = astman_get_header(m, "TotalType");
3929  const char *aocbillingid = astman_get_header(m, "AOCBillingId");
3930  const char *association_id= astman_get_header(m, "ChargingAssociationId");
3931  const char *association_num = astman_get_header(m, "ChargingAssociationNumber");
3932  const char *association_plan = astman_get_header(m, "ChargingAssociationPlan");
3933 
3934  enum ast_aoc_type _msgtype;
3935  enum ast_aoc_charge_type _chargetype;
3937  enum ast_aoc_total_type _totaltype = AST_AOC_TOTAL;
3938  enum ast_aoc_billing_id _billingid = AST_AOC_BILLING_NA;
3939  unsigned int _currencyamount = 0;
3940  int _association_id = 0;
3941  unsigned int _association_plan = 0;
3942  struct ast_channel *chan = NULL;
3943 
3944  struct ast_aoc_decoded *decoded = NULL;
3945  struct ast_aoc_encoded *encoded = NULL;
3946  size_t encoded_size = 0;
3947 
3948  if (ast_strlen_zero(channel) && ast_strlen_zero(pchannel)) {
3949  astman_send_error(s, m, "Channel and PartialChannel are not specified. Specify at least one of these.");
3950  goto aocmessage_cleanup;
3951  }
3952 
3953  if (!(chan = ast_channel_get_by_name(channel)) && !ast_strlen_zero(pchannel)) {
3954  chan = ast_channel_get_by_name_prefix(pchannel, strlen(pchannel));
3955  }
3956 
3957  if (!chan) {
3958  astman_send_error(s, m, "No such channel");
3959  goto aocmessage_cleanup;
3960  }
3961 
3962  if (ast_strlen_zero(msgtype) || (strcasecmp(msgtype, "d") && strcasecmp(msgtype, "e"))) {
3963  astman_send_error(s, m, "Invalid MsgType");
3964  goto aocmessage_cleanup;
3965  }
3966 
3967  if (ast_strlen_zero(chargetype)) {
3968  astman_send_error(s, m, "ChargeType not specified");
3969  goto aocmessage_cleanup;
3970  }
3971 
3972  _msgtype = strcasecmp(msgtype, "d") ? AST_AOC_E : AST_AOC_D;
3973 
3974  if (!strcasecmp(chargetype, "NA")) {
3975  _chargetype = AST_AOC_CHARGE_NA;
3976  } else if (!strcasecmp(chargetype, "Free")) {
3977  _chargetype = AST_AOC_CHARGE_FREE;
3978  } else if (!strcasecmp(chargetype, "Currency")) {
3979  _chargetype = AST_AOC_CHARGE_CURRENCY;
3980  } else if (!strcasecmp(chargetype, "Unit")) {
3981  _chargetype = AST_AOC_CHARGE_UNIT;
3982  } else {
3983  astman_send_error(s, m, "Invalid ChargeType");
3984  goto aocmessage_cleanup;
3985  }
3986 
3987  if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
3988 
3989  if (ast_strlen_zero(currencyamount) || (sscanf(currencyamount, "%30u", &_currencyamount) != 1)) {
3990  astman_send_error(s, m, "Invalid CurrencyAmount, CurrencyAmount is a required when ChargeType is Currency");
3991  goto aocmessage_cleanup;
3992  }
3993 
3994  if (ast_strlen_zero(mult)) {
3995  astman_send_error(s, m, "ChargeMultiplier unspecified, ChargeMultiplier is required when ChargeType is Currency.");
3996  goto aocmessage_cleanup;
3997  } else if (!strcasecmp(mult, "onethousandth")) {
3999  } else if (!strcasecmp(mult, "onehundredth")) {
4000  _mult = AST_AOC_MULT_ONEHUNDREDTH;
4001  } else if (!strcasecmp(mult, "onetenth")) {
4002  _mult = AST_AOC_MULT_ONETENTH;
4003  } else if (!strcasecmp(mult, "one")) {
4004  _mult = AST_AOC_MULT_ONE;
4005  } else if (!strcasecmp(mult, "ten")) {
4006  _mult = AST_AOC_MULT_TEN;
4007  } else if (!strcasecmp(mult, "hundred")) {
4008  _mult = AST_AOC_MULT_HUNDRED;
4009  } else if (!strcasecmp(mult, "thousand")) {
4010  _mult = AST_AOC_MULT_THOUSAND;
4011  } else {
4012  astman_send_error(s, m, "Invalid ChargeMultiplier");
4013  goto aocmessage_cleanup;
4014  }
4015  }
4016 
4017  /* create decoded object and start setting values */
4018  if (!(decoded = ast_aoc_create(_msgtype, _chargetype, 0))) {
4019  astman_send_error(s, m, "Message Creation Failed");
4020  goto aocmessage_cleanup;
4021  }
4022 
4023  if (_msgtype == AST_AOC_D) {
4024  if (!ast_strlen_zero(totaltype) && !strcasecmp(totaltype, "subtotal")) {
4025  _totaltype = AST_AOC_SUBTOTAL;
4026  }
4027 
4028  if (ast_strlen_zero(aocbillingid)) {
4029  /* ignore this is optional */
4030  } else if (!strcasecmp(aocbillingid, "Normal")) {
4031  _billingid = AST_AOC_BILLING_NORMAL;
4032  } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
4033  _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
4034  } else if (!strcasecmp(aocbillingid, "CreditCard")) {
4035  _billingid = AST_AOC_BILLING_CREDIT_CARD;
4036  } else {
4037  astman_send_error(s, m, "Invalid AOC-D AOCBillingId");
4038  goto aocmessage_cleanup;
4039  }
4040  } else {
4041  if (ast_strlen_zero(aocbillingid)) {
4042  /* ignore this is optional */
4043  } else if (!strcasecmp(aocbillingid, "Normal")) {
4044  _billingid = AST_AOC_BILLING_NORMAL;
4045  } else if (!strcasecmp(aocbillingid, "ReverseCharge")) {
4046  _billingid = AST_AOC_BILLING_REVERSE_CHARGE;
4047  } else if (!strcasecmp(aocbillingid, "CreditCard")) {
4048  _billingid = AST_AOC_BILLING_CREDIT_CARD;
4049  } else if (!strcasecmp(aocbillingid, "CallFwdUnconditional")) {
4051  } else if (!strcasecmp(aocbillingid, "CallFwdBusy")) {
4052  _billingid = AST_AOC_BILLING_CALL_FWD_BUSY;
4053  } else if (!strcasecmp(aocbillingid, "CallFwdNoReply")) {
4054  _billingid = AST_AOC_BILLING_CALL_FWD_NO_REPLY;
4055  } else if (!strcasecmp(aocbillingid, "CallDeflection")) {
4056  _billingid = AST_AOC_BILLING_CALL_DEFLECTION;
4057  } else if (!strcasecmp(aocbillingid, "CallTransfer")) {
4058  _billingid = AST_AOC_BILLING_CALL_TRANSFER;
4059  } else {
4060  astman_send_error(s, m, "Invalid AOC-E AOCBillingId");
4061  goto aocmessage_cleanup;
4062  }
4063 
4064  if (!ast_strlen_zero(association_id) && (sscanf(association_id, "%30d", &_association_id) != 1)) {
4065  astman_send_error(s, m, "Invalid ChargingAssociationId");
4066  goto aocmessage_cleanup;
4067  }
4068  if (!ast_strlen_zero(association_plan) && (sscanf(association_plan, "%30u", &_association_plan) != 1)) {
4069  astman_send_error(s, m, "Invalid ChargingAssociationPlan");
4070  goto aocmessage_cleanup;
4071  }
4072 
4073  if (_association_id) {
4074  ast_aoc_set_association_id(decoded, _association_id);
4075  } else if (!ast_strlen_zero(association_num)) {
4076  ast_aoc_set_association_number(decoded, association_num, _association_plan);
4077  }
4078  }
4079 
4080  if (_chargetype == AST_AOC_CHARGE_CURRENCY) {
4081  ast_aoc_set_currency_info(decoded, _currencyamount, _mult, ast_strlen_zero(currencyname) ? NULL : currencyname);
4082  } else if (_chargetype == AST_AOC_CHARGE_UNIT) {
4083  struct ast_aoc_unit_entry entry;
4084  int i;
4085 
4086  /* multiple unit entries are possible, lets get them all */
4087  for (i = 0; i < 32; i++) {
4088  if (aocmessage_get_unit_entry(m, &entry, i)) {
4089  break; /* that's the end then */
4090  }
4091 
4092  ast_aoc_add_unit_entry(decoded, entry.valid_amount, entry.amount, entry.valid_type, entry.type);
4093  }
4094 
4095  /* at least one unit entry is required */
4096  if (!i) {
4097  astman_send_error(s, m, "Invalid UnitAmount(0), At least one valid unit entry is required when ChargeType is set to Unit");
4098  goto aocmessage_cleanup;
4099  }
4100 
4101  }
4102 
4103  ast_aoc_set_billing_id(decoded, _billingid);
4104  ast_aoc_set_total_type(decoded, _totaltype);
4105 
4106 
4107  if ((encoded = ast_aoc_encode(decoded, &encoded_size, NULL)) && !ast_indicate_data(chan, AST_CONTROL_AOC, encoded, encoded_size)) {
4108  astman_send_ack(s, m, "AOC Message successfully queued on channel");
4109  } else {
4110  astman_send_error(s, m, "Error encoding AOC message, could not queue onto channel");
4111  }
4112 
4113 aocmessage_cleanup:
4114 
4115  ast_aoc_destroy_decoded(decoded);
4116  ast_aoc_destroy_encoded(encoded);
4117 
4118  if (chan) {
4119  chan = ast_channel_unref(chan);
4120  }
4121  return 0;
4122 }
4123 
4124 static int action_originate(struct mansession *s, const struct message *m)
4125 {
4126  const char *name = astman_get_header(m, "Channel");
4127  const char *exten = astman_get_header(m, "Exten");
4128  const char *context = astman_get_header(m, "Context");
4129  const char *priority = astman_get_header(m, "Priority");
4130  const char *timeout = astman_get_header(m, "Timeout");
4131  const char *callerid = astman_get_header(m, "CallerID");
4132  const char *account = astman_get_header(m, "Account");
4133  const char *app = astman_get_header(m, "Application");
4134  const char *appdata = astman_get_header(m, "Data");
4135  const char *async = astman_get_header(m, "Async");
4136  const char *id = astman_get_header(m, "ActionID");
4137  const char *codecs = astman_get_header(m, "Codecs");
4138  struct ast_variable *vars;
4139  char *tech, *data;
4140  char *l = NULL, *n = NULL;
4141  int pi = 0;
4142  int res;
4143  int to = 30000;
4144  int reason = 0;
4145  char tmp[256];
4146  char tmp2[256];
4147  format_t format = AST_FORMAT_SLINEAR;
4148 
4149  pthread_t th;
4150  if (ast_strlen_zero(name)) {
4151  astman_send_error(s, m, "Channel not specified");
4152  return 0;
4153  }
4154  if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
4155  if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
4156  astman_send_error(s, m, "Invalid priority");
4157  return 0;
4158  }
4159  }
4160  if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%30d", &to) != 1)) {
4161  astman_send_error(s, m, "Invalid timeout");
4162  return 0;
4163  }
4164  ast_copy_string(tmp, name, sizeof(tmp));
4165  tech = tmp;
4166  data = strchr(tmp, '/');
4167  if (!data) {
4168  astman_send_error(s, m, "Invalid channel");
4169  return 0;
4170  }
4171  *data++ = '\0';
4172  ast_copy_string(tmp2, callerid, sizeof(tmp2));
4173  ast_callerid_parse(tmp2, &n, &l);
4174  if (n) {
4175  if (ast_strlen_zero(n)) {
4176  n = NULL;
4177  }
4178  }
4179  if (l) {
4181  if (ast_strlen_zero(l)) {
4182  l = NULL;
4183  }
4184  }
4185  if (!ast_strlen_zero(codecs)) {
4186  format = 0;
4187  ast_parse_allow_disallow(NULL, &format, codecs, 1);
4188  }
4189  if (!ast_strlen_zero(app) && s->session) {
4190  int bad_appdata = 0;
4191  /* To run the System application (or anything else that goes to
4192  * shell), you must have the additional System privilege */
4193  if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
4194  && (
4195  strcasestr(app, "system") || /* System(rm -rf /)
4196  TrySystem(rm -rf /) */
4197  strcasestr(app, "exec") || /* Exec(System(rm -rf /))
4198  TryExec(System(rm -rf /)) */
4199  strcasestr(app, "agi") || /* AGI(/bin/rm,-rf /)
4200  EAGI(/bin/rm,-rf /) */
4201  strcasestr(app, "mixmonitor") || /* MixMonitor(blah,,rm -rf) */
4202  strcasestr(app, "externalivr") || /* ExternalIVR(rm -rf) */
4203  (strstr(appdata, "SHELL") && (bad_appdata = 1)) || /* NoOp(${SHELL(rm -rf /)}) */
4204  (strstr(appdata, "EVAL") && (bad_appdata = 1)) /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
4205  )) {
4206  char error_buf[64];
4207  snprintf(error_buf, sizeof(error_buf), "Originate Access Forbidden: %s", bad_appdata ? "Data" : "Application");
4208  astman_send_error(s, m, error_buf);
4209  return 0;
4210  }
4211  }
4212  /* Allocate requested channel variables */
4213  vars = astman_get_variables(m);
4214 
4215  if (ast_true(async)) {
4216  struct fast_originate_helper *fast;
4217 
4218  fast = ast_calloc(1, sizeof(*fast));
4219  if (!fast || ast_string_field_init(fast, 252)) {
4220  ast_free(fast);
4221  ast_variables_destroy(vars);
4222  res = -1;
4223  } else {
4224  if (!ast_strlen_zero(id)) {
4225  ast_string_field_build(fast, idtext, "ActionID: %s\r\n", id);
4226  }
4227  ast_string_field_set(fast, tech, tech);
4228  ast_string_field_set(fast, data, data);
4229  ast_string_field_set(fast, app, app);
4230  ast_string_field_set(fast, appdata, appdata);
4231  ast_string_field_set(fast, cid_num, l);
4232  ast_string_field_set(fast, cid_name, n);
4233  ast_string_field_set(fast, context, context);
4234  ast_string_field_set(fast, exten, exten);
4235  ast_string_field_set(fast, account, account);
4236  fast->vars = vars;
4237  fast->format = format;
4238  fast->timeout = to;
4239  fast->priority = pi;
4240  if (ast_pthread_create_detached(&th, NULL, fast_originate, fast)) {
4242  res = -1;
4243  } else {
4244  res = 0;
4245  }
4246  }
4247  } else if (!ast_strlen_zero(app)) {
4248  res = ast_pbx_outgoing_app(tech, format, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
4249  /* Any vars memory was passed to ast_pbx_outgoing_app(). */
4250  } else {
4251  if (exten && context && pi) {
4252  res = ast_pbx_outgoing_exten(tech, format, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
4253  /* Any vars memory was passed to ast_pbx_outgoing_exten(). */
4254  } else {
4255  astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
4256  ast_variables_destroy(vars);
4257  return 0;
4258  }
4259  }
4260  if (!res) {
4261  astman_send_ack(s, m, "Originate successfully queued");
4262  } else {
4263  astman_send_error(s, m, "Originate failed");
4264  }
4265  return 0;
4266 }
4267 
4268 static int action_mailboxstatus(struct mansession *s, const struct message *m)
4269 {
4270  const char *mailbox = astman_get_header(m, "Mailbox");
4271  int ret;
4272 
4273  if (ast_strlen_zero(mailbox)) {
4274  astman_send_error(s, m, "Mailbox not specified");
4275  return 0;
4276  }
4277  ret = ast_app_has_voicemail(mailbox, NULL);
4278  astman_start_ack(s, m);
4279  astman_append(s, "Message: Mailbox Status\r\n"
4280  "Mailbox: %s\r\n"
4281  "Waiting: %d\r\n\r\n", mailbox, ret);
4282  return 0;
4283 }
4284 
4285 static int action_mailboxcount(struct mansession *s, const struct message *m)
4286 {
4287  const char *mailbox = astman_get_header(m, "Mailbox");
4288  int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;;
4289 
4290  if (ast_strlen_zero(mailbox)) {
4291  astman_send_error(s, m, "Mailbox not specified");
4292  return 0;
4293  }
4294  ast_app_inboxcount2(mailbox, &urgentmsgs, &newmsgs, &oldmsgs);
4295  astman_start_ack(s, m);
4296  astman_append(s, "Message: Mailbox Message Count\r\n"
4297  "Mailbox: %s\r\n"
4298  "UrgMessages: %d\r\n"
4299  "NewMessages: %d\r\n"
4300  "OldMessages: %d\r\n"
4301  "\r\n",
4302  mailbox, urgentmsgs, newmsgs, oldmsgs);
4303  return 0;
4304 }
4305 
4306 static int action_extensionstate(struct mansession *s, const struct message *m)
4307 {
4308  const char *exten = astman_get_header(m, "Exten");
4309  const char *context = astman_get_header(m, "Context");
4310  char hint[256] = "";
4311  int status;
4312  if (ast_strlen_zero(exten)) {
4313  astman_send_error(s, m, "Extension not specified");
4314  return 0;
4315  }
4316  if (ast_strlen_zero(context)) {
4317  context = "default";
4318  }
4319  status = ast_extension_state(NULL, context, exten);
4320  ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
4321  astman_start_ack(s, m);
4322  astman_append(s, "Message: Extension Status\r\n"
4323  "Exten: %s\r\n"
4324  "Context: %s\r\n"
4325  "Hint: %s\r\n"
4326  "Status: %d\r\n\r\n",
4327  exten, context, hint, status);
4328  return 0;
4329 }
4330 
4331 static int action_timeout(struct mansession *s, const struct message *m)
4332 {
4333  struct ast_channel *c;
4334  const char *name = astman_get_header(m, "Channel");
4335  double timeout = atof(astman_get_header(m, "Timeout"));
4336  struct timeval when = { timeout, 0 };
4337 
4338  if (ast_strlen_zero(name)) {
4339  astman_send_error(s, m, "No channel specified");
4340  return 0;
4341  }
4342 
4343  if (!timeout || timeout < 0) {
4344  astman_send_error(s, m, "No timeout specified");
4345  return 0;
4346  }
4347 
4348  if (!(c = ast_channel_get_by_name(name))) {
4349  astman_send_error(s, m, "No such channel");
4350  return 0;
4351  }
4352 
4353  when.tv_usec = (timeout - when.tv_sec) * 1000000.0;
4354 
4355  ast_channel_lock(c);
4357  ast_channel_unlock(c);
4358  c = ast_channel_unref(c);
4359 
4360  astman_send_ack(s, m, "Timeout Set");
4361 
4362  return 0;
4363 }
4364 
4365 static int whitefilter_cmp_fn(void *obj, void *arg, void *data, int flags)
4366 {
4367  regex_t *regex_filter = obj;
4368  const char *eventdata = arg;
4369  int *result = data;
4370 
4371  if (!regexec(regex_filter, eventdata, 0, NULL, 0)) {
4372  *result = 1;
4373  return (CMP_MATCH | CMP_STOP);
4374  }
4375 
4376  return 0;
4377 }
4378 
4379 static int blackfilter_cmp_fn(void *obj, void *arg, void *data, int flags)
4380 {
4381  regex_t *regex_filter = obj;
4382  const char *eventdata = arg;
4383  int *result = data;
4384 
4385  if (!regexec(regex_filter, eventdata, 0, NULL, 0)) {
4386  *result = 0;
4387  return (CMP_MATCH | CMP_STOP);
4388  }
4389 
4390  *result = 1;
4391  return 0;
4392 }
4393 
4394 static int match_filter(struct mansession *s, char *eventdata)
4395 {
4396  int result = 0;
4397 
4398  ast_debug(3, "Examining event:\n%s\n", eventdata);
4400  return 1; /* no filtering means match all */
4402  /* white filters only: implied black all filter processed first, then white filters */
4403  ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
4405  /* black filters only: implied white all filter processed first, then black filters */
4406  ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
4407  } else {
4408  /* white and black filters: implied black all filter processed first, then white filters, and lastly black filters */
4409  ao2_t_callback_data(s->session->whitefilters, OBJ_NODATA, whitefilter_cmp_fn, eventdata, &result, "find filter in session filter container");
4410  if (result) {
4411  result = 0;
4412  ao2_t_callback_data(s->session->blackfilters, OBJ_NODATA, blackfilter_cmp_fn, eventdata, &result, "find filter in session filter container");
4413  }
4414  }
4415 
4416  return result;
4417 }
4418 
4419 /*!
4420  * Send any applicable events to the client listening on this socket.
4421  * Wait only for a finite time on each event, and drop all events whether
4422  * they are successfully sent or not.
4423  */
4424 static int process_events(struct mansession *s)
4425 {
4426  int ret = 0;
4427 
4428  ao2_lock(s->session);
4429  if (s->session->f != NULL) {
4430  struct eventqent *eqe = s->session->last_ev;
4431 
4432  while ((eqe = advance_event(eqe))) {
4433  if (!ret && s->session->authenticated &&
4434  (s->session->readperm & eqe->category) == eqe->category &&
4435  (s->session->send_events & eqe->category) == eqe->category) {
4436  if (match_filter(s, eqe->eventdata)) {
4437  if (send_string(s, eqe->eventdata) < 0)
4438  ret = -1; /* don't send more */
4439  }
4440  }
4441  s->session->last_ev = eqe;
4442  }
4443  }
4444  ao2_unlock(s->session);
4445  return ret;
4446 }
4447 
4448 static int action_userevent(struct mansession *s, const struct message *m)
4449 {
4450  const char *event = astman_get_header(m, "UserEvent");
4451  struct ast_str *body = ast_str_thread_get(&userevent_buf, 16);
4452  int x;
4453 
4454  ast_str_reset(body);
4455 
4456  for (x = 0; x < m->hdrcount; x++) {
4457  if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
4458  ast_str_append(&body, 0, "%s\r\n", m->headers[x]);
4459  }
4460  }
4461 
4462  astman_send_ack(s, m, "Event Sent");
4463  manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, ast_str_buffer(body));
4464  return 0;
4465 }
4466 
4467 /*! \brief Show PBX core settings information */
4468 static int action_coresettings(struct mansession *s, const struct message *m)
4469 {
4470  const char *actionid = astman_get_header(m, "ActionID");
4471  char idText[150];
4472 
4473  if (!ast_strlen_zero(actionid)) {
4474  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
4475  } else {
4476  idText[0] = '\0';
4477  }
4478 
4479  astman_append(s, "Response: Success\r\n"
4480  "%s"
4481  "AMIversion: %s\r\n"
4482  "AsteriskVersion: %s\r\n"
4483  "SystemName: %s\r\n"
4484  "CoreMaxCalls: %d\r\n"
4485  "CoreMaxLoadAvg: %f\r\n"
4486  "CoreRunUser: %s\r\n"
4487  "CoreRunGroup: %s\r\n"
4488  "CoreMaxFilehandles: %d\r\n"
4489  "CoreRealTimeEnabled: %s\r\n"
4490  "CoreCDRenabled: %s\r\n"
4491  "CoreHTTPenabled: %s\r\n"
4492  "\r\n",
4493  idText,
4494  AMI_VERSION,
4495  ast_get_version(),
4505  );
4506  return 0;
4507 }
4508 
4509 /*! \brief Show PBX core status information */
4510 static int action_corestatus(struct mansession *s, const struct message *m)
4511 {
4512  const char *actionid = astman_get_header(m, "ActionID");
4513  char idText[150];
4514  char startuptime[150], startupdate[150];
4515  char reloadtime[150], reloaddate[150];
4516  struct ast_tm tm;
4517 
4518  if (!ast_strlen_zero(actionid)) {
4519  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
4520  } else {
4521  idText[0] = '\0';
4522  }
4523 
4524  ast_localtime(&ast_startuptime, &tm, NULL);
4525  ast_strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
4526  ast_strftime(startupdate, sizeof(startupdate), "%Y-%m-%d", &tm);
4527  ast_localtime(&ast_lastreloadtime, &tm, NULL);
4528  ast_strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
4529  ast_strftime(reloaddate, sizeof(reloaddate), "%Y-%m-%d", &tm);
4530 
4531  astman_append(s, "Response: Success\r\n"
4532  "%s"
4533  "CoreStartupDate: %s\r\n"
4534  "CoreStartupTime: %s\r\n"
4535  "CoreReloadDate: %s\r\n"
4536  "CoreReloadTime: %s\r\n"
4537  "CoreCurrentCalls: %d\r\n"
4538  "\r\n",
4539  idText,
4540  startupdate,
4541  startuptime,
4542  reloaddate,
4543  reloadtime,
4545  );
4546  return 0;
4547 }
4548 
4549 /*! \brief Send a reload event */
4550 static int action_reload(struct mansession *s, const struct message *m)
4551 {
4552  const char *module = astman_get_header(m, "Module");
4553  int res = ast_module_reload(S_OR(module, NULL));
4554 
4555  switch (res) {
4556  case -1:
4557  astman_send_error(s, m, "A reload is in progress");
4558  break;
4559  case 0:
4560  astman_send_error(s, m, "No such module");
4561  break;
4562  case 1:
4563  astman_send_error(s, m, "Module does not support reload");
4564  break;
4565  case 2:
4566  astman_send_ack(s, m, "Module Reloaded");
4567  break;
4568  default:
4569  astman_send_error(s, m, "An unknown error occurred");
4570  break;
4571  }
4572  return 0;
4573 }
4574 
4575 /*! \brief Manager command "CoreShowChannels" - List currently defined channels
4576  * and some information about them. */
4577 static int action_coreshowchannels(struct mansession *s, const struct message *m)
4578 {
4579  const char *actionid = astman_get_header(m, "ActionID");
4580  char idText[256];
4581  struct ast_channel *c = NULL;
4582  int numchans = 0;
4583  int duration, durh, durm, durs;
4584  struct ast_channel_iterator *iter;
4585 
4586  if (!ast_strlen_zero(actionid)) {
4587  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
4588  } else {
4589  idText[0] = '\0';
4590  }
4591 
4592  if (!(iter = ast_channel_iterator_all_new())) {
4593  astman_send_error(s, m, "Memory Allocation Failure");
4594  return 1;
4595  }
4596 
4597  astman_send_listack(s, m, "Channels will follow", "start");
4598 
4599  for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
4600  struct ast_channel *bc;
4601  char durbuf[10] = "";
4602 
4603  ast_channel_lock(c);
4604 
4605  bc = ast_bridged_channel(c);
4606  if (c->cdr && !ast_tvzero(c->cdr->start)) {
4607  duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
4608  durh = duration / 3600;
4609  durm = (duration % 3600) / 60;
4610  durs = duration % 60;
4611  snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
4612  }
4613 
4614  astman_append(s,
4615  "Event: CoreShowChannel\r\n"
4616  "%s"
4617  "Channel: %s\r\n"
4618  "UniqueID: %s\r\n"
4619  "Context: %s\r\n"
4620  "Extension: %s\r\n"
4621  "Priority: %d\r\n"
4622  "ChannelState: %u\r\n"
4623  "ChannelStateDesc: %s\r\n"
4624  "Application: %s\r\n"
4625  "ApplicationData: %s\r\n"
4626  "CallerIDnum: %s\r\n"
4627  "CallerIDname: %s\r\n"
4628  "ConnectedLineNum: %s\r\n"
4629  "ConnectedLineName: %s\r\n"
4630  "Duration: %s\r\n"
4631  "AccountCode: %s\r\n"
4632  "BridgedChannel: %s\r\n"
4633  "BridgedUniqueID: %s\r\n"
4634  "\r\n", idText, c->name, c->uniqueid, c->context, c->exten, c->priority, c->_state,
4635  ast_state2str(c->_state), c->appl ? c->appl : "", c->data ? S_OR(c->data, "") : "",
4636  S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""),
4637  S_COR(c->caller.id.name.valid, c->caller.id.name.str, ""),
4639  S_COR(c->connected.id.name.valid, c->connected.id.name.str, ""),
4640  durbuf, S_OR(c->accountcode, ""), bc ? bc->name : "", bc ? bc->uniqueid : "");
4641 
4642  ast_channel_unlock(c);
4643 
4644  numchans++;
4645  }
4646 
4647  astman_append(s,
4648  "Event: CoreShowChannelsComplete\r\n"
4649  "EventList: Complete\r\n"
4650  "ListItems: %d\r\n"
4651  "%s"
4652  "\r\n", numchans, idText);
4653 
4655 
4656  return 0;
4657 }
4658 
4659 /* Manager function to check if module is loaded */
4660 static int manager_modulecheck(struct mansession *s, const struct message *m)
4661 {
4662  int res;
4663  const char *module = astman_get_header(m, "Module");
4664  const char *id = astman_get_header(m, "ActionID");
4665  char idText[256];
4666 #if !defined(LOW_MEMORY)
4667  const char *version;
4668 #endif
4669  char filename[PATH_MAX];
4670  char *cut;
4671 
4672  ast_copy_string(filename, module, sizeof(filename));
4673  if ((cut = strchr(filename, '.'))) {
4674  *cut = '\0';
4675  } else {
4676  cut = filename + strlen(filename);
4677  }
4678  snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".so");
4679  ast_log(LOG_DEBUG, "**** ModuleCheck .so file %s\n", filename);
4680  res = ast_module_check(filename);
4681  if (!res) {
4682  astman_send_error(s, m, "Module not loaded");
4683  return 0;
4684  }
4685  snprintf(cut, (sizeof(filename) - strlen(filename)) - 1, ".c");
4686  ast_log(LOG_DEBUG, "**** ModuleCheck .c file %s\n", filename);
4687 #if !defined(LOW_MEMORY)
4688  version = ast_file_version_find(filename);
4689 #endif
4690 
4691  if (!ast_strlen_zero(id)) {
4692  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
4693  } else {
4694  idText[0] = '\0';
4695  }
4696  astman_append(s, "Response: Success\r\n%s", idText);
4697 #if !defined(LOW_MEMORY)
4698  astman_append(s, "Version: %s\r\n\r\n", version ? version : "");
4699 #endif
4700  return 0;
4701 }
4702 
4703 static int manager_moduleload(struct mansession *s, const struct message *m)
4704 {
4705  int res;
4706  const char *module = astman_get_header(m, "Module");
4707  const char *loadtype = astman_get_header(m, "LoadType");
4708 
4709  if (!loadtype || strlen(loadtype) == 0) {
4710  astman_send_error(s, m, "Incomplete ModuleLoad action.");
4711  }
4712  if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0) {
4713  astman_send_error(s, m, "Need module name");
4714  }
4715 
4716  if (!strcasecmp(loadtype, "load")) {
4717  res = ast_load_resource(module);
4718  if (res) {
4719  astman_send_error(s, m, "Could not load module.");
4720  } else {
4721  astman_send_ack(s, m, "Module loaded.");
4722  }
4723  } else if (!strcasecmp(loadtype, "unload")) {
4724  res = ast_unload_resource(module, AST_FORCE_SOFT);
4725  if (res) {
4726  astman_send_error(s, m, "Could not unload module.");
4727  } else {
4728  astman_send_ack(s, m, "Module unloaded.");
4729  }
4730  } else if (!strcasecmp(loadtype, "reload")) {
4731  if (!ast_strlen_zero(module)) {
4732  res = ast_module_reload(module);
4733  if (res == 0) {
4734  astman_send_error(s, m, "No such module.");
4735  } else if (res == 1) {
4736  astman_send_error(s, m, "Module does not support reload action.");
4737  } else {
4738  astman_send_ack(s, m, "Module reloaded.");
4739  }
4740  } else {
4741  ast_module_reload(NULL); /* Reload all modules */
4742  astman_send_ack(s, m, "All modules reloaded");
4743  }
4744  } else
4745  astman_send_error(s, m, "Incomplete ModuleLoad action.");
4746  return 0;
4747 }
4748 
4749 /*
4750  * Done with the action handlers here, we start with the code in charge
4751  * of accepting connections and serving them.
4752  * accept_thread() forks a new thread for each connection, session_do(),
4753  * which in turn calls get_input() repeatedly until a full message has
4754  * been accumulated, and then invokes process_message() to pass it to
4755  * the appropriate handler.
4756  */
4757 
4758 /*
4759  * Process an AMI message, performing desired action.
4760  * Return 0 on success, -1 on error that require the session to be destroyed.
4761  */
4762 static int process_message(struct mansession *s, const struct message *m)
4763 {
4764  int ret = 0;
4765  struct manager_action *act_found;
4766  const char *user;
4767  const char *action;
4768 
4769  action = __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY);
4770  if (ast_strlen_zero(action)) {
4771  report_req_bad_format(s, "NONE");
4772  mansession_lock(s);
4773  astman_send_error(s, m, "Missing action in request");
4774  mansession_unlock(s);
4775  return 0;
4776  }
4777 
4778  if (!s->session->authenticated
4779  && strcasecmp(action, "Login")
4780  && strcasecmp(action, "Logoff")
4781  && strcasecmp(action, "Challenge")) {
4782  if (!s->session->authenticated) {
4783  report_req_not_allowed(s, action);
4784  }
4785  mansession_lock(s);
4786  astman_send_error(s, m, "Permission denied");
4787  mansession_unlock(s);
4788  return 0;
4789  }
4790 
4791  if (!allowmultiplelogin
4792  && !s->session->authenticated
4793  && (!strcasecmp(action, "Login")
4794  || !strcasecmp(action, "Challenge"))) {
4795  user = astman_get_header(m, "Username");
4796 
4797  if (!ast_strlen_zero(user) && check_manager_session_inuse(user)) {
4799  sleep(1);
4800  mansession_lock(s);
4801  astman_send_error(s, m, "Login Already In Use");
4802  mansession_unlock(s);
4803  return -1;
4804  }
4805  }
4806 
4807  act_found = action_find(action);
4808  if (act_found) {
4809  /* Found the requested AMI action. */
4810  int acted = 0;
4811 
4812  if ((s->session->writeperm & act_found->authority)
4813  || act_found->authority == 0) {
4814  /* We have the authority to execute the action. */
4815  ao2_lock(act_found);
4816  if (act_found->registered && act_found->func) {
4817  ast_debug(1, "Running action '%s'\n", act_found->action);
4818  ++act_found->active_count;
4819  ao2_unlock(act_found);
4820  ret = act_found->func(s, m);
4821  acted = 1;
4822  ao2_lock(act_found);
4823  --act_found->active_count;
4824  }
4825  ao2_unlock(act_found);
4826  }
4827  if (!acted) {
4828  /*
4829  * We did not execute the action because access was denied, it
4830  * was no longer registered, or no action was really registered.
4831  * Complain about it and leave.
4832  */
4833  report_req_not_allowed(s, action);
4834  mansession_lock(s);
4835  astman_send_error(s, m, "Permission denied");
4836  mansession_unlock(s);
4837  }
4838  ao2_t_ref(act_found, -1, "done with found action object");
4839  } else {
4840  char buf[512];
4841 
4842  report_req_bad_format(s, action);
4843  snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
4844  mansession_lock(s);
4845  astman_send_error(s, m, buf);
4846  mansession_unlock(s);
4847  }
4848  if (ret) {
4849  return ret;
4850  }
4851  /* Once done with our message, deliver any pending events unless the
4852  requester doesn't want them as part of this response.
4853  */
4854  if (ast_strlen_zero(astman_get_header(m, "SuppressEvents"))) {
4855  return process_events(s);
4856  } else {
4857  return ret;
4858  }
4859 }
4860 
4861 /*!
4862  * Read one full line (including crlf) from the manager socket.
4863  * \note \verbatim
4864  * \r\n is the only valid terminator for the line.
4865  * (Note that, later, '\0' will be considered as the end-of-line marker,
4866  * so everything between the '\0' and the '\r\n' will not be used).
4867  * Also note that we assume output to have at least "maxlen" space.
4868  * \endverbatim
4869  */
4870 static int get_input(struct mansession *s, char *output)
4871 {
4872  int res, x;
4873  int maxlen = sizeof(s->session->inbuf) - 1;
4874  char *src = s->session->inbuf;
4875  int timeout = -1;
4876  time_t now;
4877 
4878  /*
4879  * Look for \r\n within the buffer. If found, copy to the output
4880  * buffer and return, trimming the \r\n (not used afterwards).
4881  */
4882  for (x = 0; x < s->session->inlen; x++) {
4883  int cr; /* set if we have \r */
4884  if (src[x] == '\r' && x+1 < s->session->inlen && src[x + 1] == '\n') {
4885  cr = 2; /* Found. Update length to include \r\n */
4886  } else if (src[x] == '\n') {
4887  cr = 1; /* also accept \n only */
4888  } else {
4889  continue;
4890  }
4891  memmove(output, src, x); /*... but trim \r\n */
4892  output[x] = '\0'; /* terminate the string */
4893  x += cr; /* number of bytes used */
4894  s->session->inlen -= x; /* remaining size */
4895  memmove(src, src + x, s->session->inlen); /* remove used bytes */
4896  return 1;
4897  }
4898  if (s->session->inlen >= maxlen) {
4899  /* no crlf found, and buffer full - sorry, too long for us */
4900  ast_log(LOG_WARNING, "Discarding message from %s. Line too long: %.25s...\n", ast_inet_ntoa(s->session->sin.sin_addr), src);
4901  s->session->inlen = 0;
4903  }
4904  res = 0;
4905  while (res == 0) {
4906  /* calculate a timeout if we are not authenticated */
4907  if (!s->session->authenticated) {
4908  if(time(&now) == -1) {
4909  ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
4910  return -1;
4911  }
4912 
4913  timeout = (authtimeout - (now - s->session->authstart)) * 1000;
4914  if (timeout < 0) {
4915  /* we have timed out */
4916  return 0;
4917  }
4918  }
4919 
4920  ao2_lock(s->session);
4921  if (s->session->pending_event) {
4922  s->session->pending_event = 0;
4923  ao2_unlock(s->session);
4924  return 0;
4925  }
4926  s->session->waiting_thread = pthread_self();
4927  ao2_unlock(s->session);
4928 
4929  res = ast_wait_for_input(s->session->fd, timeout);
4930 
4931  ao2_lock(s->session);
4933  ao2_unlock(s->session);
4934  }
4935  if (res < 0) {
4936  /* If we get a signal from some other thread (typically because
4937  * there are new events queued), return 0 to notify the caller.
4938  */
4939  if (errno == EINTR || errno == EAGAIN) {
4940  return 0;
4941  }
4942  ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
4943  return -1;
4944  }
4945 
4946  ao2_lock(s->session);
4947  res = fread(src + s->session->inlen, 1, maxlen - s->session->inlen, s->session->f);
4948  if (res < 1) {
4949  res = -1; /* error return */
4950  } else {
4951  s->session->inlen += res;
4952  src[s->session->inlen] = '\0';
4953  res = 0;
4954  }
4955  ao2_unlock(s->session);
4956  return res;
4957 }
4958 
4959 /*!
4960  * \internal
4961  * \brief Error handling for sending parse errors. This function handles locking, and clearing the
4962  * parse error flag.
4963  *
4964  * \param s AMI session to process action request.
4965  * \param m Message that's in error.
4966  * \param error Error message to send.
4967  */
4968 static void handle_parse_error(struct mansession *s, struct message *m, char *error)
4969 {
4970  mansession_lock(s);
4971  astman_send_error(s, m, error);
4972  s->parsing = MESSAGE_OKAY;
4973  mansession_unlock(s);
4974 }
4975 
4976 /*!
4977  * \internal
4978  * \brief Read and process an AMI action request.
4979  *
4980  * \param s AMI session to process action request.
4981  *
4982  * \retval 0 Retain AMI connection for next command.
4983  * \retval -1 Drop AMI connection due to logoff or connection error.
4984  */
4985 static int do_message(struct mansession *s)
4986 {
4987  struct message m = { 0 };
4988  char header_buf[sizeof(s->session->inbuf)] = { '\0' };
4989  int res;
4990  int idx;
4991  int hdr_loss;
4992  time_t now;
4993 
4994  hdr_loss = 0;
4995  for (;;) {
4996  /* Check if any events are pending and do them if needed */
4997  if (process_events(s)) {
4998  res = -1;
4999  break;
5000  }
5001  res = get_input(s, header_buf);
5002  if (res == 0) {
5003  /* No input line received. */
5004  if (!s->session->authenticated) {
5005  if (time(&now) == -1) {
5006  ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
5007  res = -1;
5008  break;
5009  }
5010 
5011  if (now - s->session->authstart > authtimeout) {
5012  if (displayconnects) {
5013  ast_verb(2, "Client from %s, failed to authenticate in %d seconds\n", ast_inet_ntoa(s->session->sin.sin_addr), authtimeout);
5014  }
5015  res = -1;
5016  break;
5017  }
5018  }
5019  continue;
5020  } else if (res > 0) {
5021  /* Input line received. */
5022  if (ast_strlen_zero(header_buf)) {
5023  if (hdr_loss) {
5024  mansession_lock(s);
5025  astman_send_error(s, &m, "Too many lines in message or allocation failure");
5026  mansession_unlock(s);
5027  res = 0;
5028  } else {
5029  switch (s->parsing) {
5030  case MESSAGE_OKAY:
5031  res = process_message(s, &m) ? -1 : 0;
5032  break;
5033  case MESSAGE_LINE_TOO_LONG:
5034  handle_parse_error(s, &m, "Failed to parse message: line too long");
5035  res = 0;
5036  break;
5037  }
5038  }
5039  break;
5040  } else if (m.hdrcount < ARRAY_LEN(m.headers)) {
5041  m.headers[m.hdrcount] = ast_strdup(header_buf);
5042  if (!m.headers[m.hdrcount]) {
5043  /* Allocation failure. */
5044  hdr_loss = 1;
5045  } else {
5046  ++m.hdrcount;
5047  }
5048  } else {
5049  /* Too many lines in message. */
5050  hdr_loss = 1;
5051  }
5052  } else {
5053  /* Input error. */
5054  break;
5055  }
5056  }
5057 
5058  /* Free AMI request headers. */
5059  for (idx = 0; idx < m.hdrcount; ++idx) {
5060  ast_free((void *) m.headers[idx]);
5061  }
5062  return res;
5063 }
5064 
5065 /*! \brief The body of the individual manager session.
5066  * Call get_input() to read one line at a time
5067  * (or be woken up on new events), collect the lines in a
5068  * message until found an empty line, and execute the request.
5069  * In any case, deliver events asynchronously through process_events()
5070  * (called from here if no line is available, or at the end of
5071  * process_message(). )
5072  */
5073 static void *session_do(void *data)
5074 {
5075  struct ast_tcptls_session_instance *ser = data;
5076  struct mansession_session *session;
5077  struct mansession s = {
5078  .tcptls_session = data,
5079  };
5080  int flags;
5081  int res;
5082  struct sockaddr_in ser_remote_address_tmp;
5083  struct protoent *p;
5084 
5085  if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= authlimit) {
5086  fclose(ser->f);
5088  goto done;
5089  }
5090 
5091  ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
5092  session = build_mansession(ser_remote_address_tmp);
5093 
5094  if (session == NULL) {
5095  fclose(ser->f);
5097  goto done;
5098  }
5099 
5100  /* here we set TCP_NODELAY on the socket to disable Nagle's algorithm.
5101  * This is necessary to prevent delays (caused by buffering) as we
5102  * write to the socket in bits and pieces. */
5103  p = getprotobyname("tcp");
5104  if (p) {
5105  int arg = 1;
5106  if( setsockopt(ser->fd, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
5107  ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\nSome manager actions may be slow to respond.\n", strerror(errno));
5108  }
5109  } else {
5110  ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY, getprotobyname(\"tcp\") failed\nSome manager actions may be slow to respond.\n");
5111  }
5112 
5113  /* make sure socket is non-blocking */
5114  flags = fcntl(ser->fd, F_GETFL);
5115  flags |= O_NONBLOCK;
5116  fcntl(ser->fd, F_SETFL, flags);
5117 
5118  ao2_lock(session);
5119  /* Hook to the tail of the event queue */
5120  session->last_ev = grab_last();
5121 
5122  ast_mutex_init(&s.lock);
5123 
5124  /* these fields duplicate those in the 'ser' structure */
5125  session->fd = s.fd = ser->fd;
5126  session->f = s.f = ser->f;
5127  session->sin = ser_remote_address_tmp;
5128  s.session = session;
5129 
5131 
5132  if(time(&session->authstart) == -1) {
5133  ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
5135  ao2_unlock(session);
5136  session_destroy(session);
5137  goto done;
5138  }
5139  ao2_unlock(session);
5140 
5141  /*
5142  * We cannot let the stream exclusively wait for data to arrive.
5143  * We have to wake up the task to send async events.
5144  */
5146 
5148  ast_tvnow(), authtimeout * 1000);
5149 
5150  astman_append(&s, "Asterisk Call Manager/%s\r\n", AMI_VERSION); /* welcome prompt */
5151  for (;;) {
5152  if ((res = do_message(&s)) < 0 || s.write_error) {
5153  break;
5154  }
5155  if (session->authenticated) {
5157  }
5158  }
5159  /* session is over, explain why and terminate */
5160  if (session->authenticated) {
5161  if (manager_displayconnects(session)) {
5162  ast_verb(2, "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
5163  }
5164  } else {
5166  if (displayconnects) {
5167  ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
5168  }
5169  }
5170 
5171  session_destroy(session);
5172 
5173  ast_mutex_destroy(&s.lock);
5174 done:
5175  ao2_ref(ser, -1);
5176  ser = NULL;
5177  return NULL;
5178 }
5179 
5180 /*! \brief remove at most n_max stale session from the list. */
5181 static void purge_sessions(int n_max)
5182 {
5183  struct mansession_session *session;
5184  time_t now = time(NULL);
5185  struct ao2_iterator i;
5186 
5187  if (!sessions) {
5188  return;
5189  }
5190 
5191  i = ao2_iterator_init(sessions, 0);
5192  while ((session = ao2_iterator_next(&i)) && n_max > 0) {
5193  ao2_lock(session);
5194  if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
5195  if (session->authenticated && (VERBOSITY_ATLEAST(2)) && manager_displayconnects(session)) {
5196  ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
5197  session->username, ast_inet_ntoa(session->sin.sin_addr));
5198  }
5199  ao2_unlock(session);
5200  session_destroy(session);
5201  n_max--;
5202  } else {
5203  ao2_unlock(session);
5204  unref_mansession(session);
5205  }
5206  }
5208 }
5209 
5210 /*
5211  * events are appended to a queue from where they
5212  * can be dispatched to clients.
5213  */
5214 static int append_event(const char *str, int category)
5215 {
5216  struct eventqent *tmp = ast_malloc(sizeof(*tmp) + strlen(str));
5217  static int seq; /* sequence number */
5218 
5219  if (!tmp) {
5220  return -1;
5221  }
5222 
5223  /* need to init all fields, because ast_malloc() does not */
5224  tmp->usecount = 0;
5225  tmp->category = category;
5226  tmp->seq = ast_atomic_fetchadd_int(&seq, 1);
5227  tmp->tv = ast_tvnow();
5228  AST_RWLIST_NEXT(tmp, eq_next) = NULL;
5229  strcpy(tmp->eventdata, str);
5230 
5231  AST_RWLIST_WRLOCK(&all_events);
5232  AST_RWLIST_INSERT_TAIL(&all_events, tmp, eq_next);
5233  AST_RWLIST_UNLOCK(&all_events);
5234 
5235  return 0;
5236 }
5237 
5239 
5240 static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
5241 {
5242  struct manager_channel_variable *var;
5243 
5244  AST_RWLIST_RDLOCK(&channelvars);
5245  AST_LIST_TRAVERSE(&channelvars, var, entry) {
5246  const char *val;
5247  struct ast_str *res;
5248 
5249  if (var->isfunc) {
5251  if (res && ast_func_read2(chan, var->name, &res, 0) == 0) {
5252  val = ast_str_buffer(res);
5253  } else {
5254  val = NULL;
5255  }
5256  } else {
5257  val = pbx_builtin_getvar_helper(chan, var->name);
5258  }
5259  ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", chan->name, var->name, val ? val : "");
5260  }
5261  AST_RWLIST_UNLOCK(&channelvars);
5262 }
5263 
5264 /* XXX see if can be moved inside the function */
5266 #define MANAGER_EVENT_BUF_INITSIZE 256
5267 
5268 int __ast_manager_event_multichan(int category, const char *event, int chancount, struct
5269  ast_channel **chans, const char *file, int line, const char *func, const char *fmt, ...)
5270 {
5271  struct mansession_session *session;
5272  struct manager_custom_hook *hook;
5273  struct ast_str *auth = ast_str_alloca(80);
5274  const char *cat_str;
5275  va_list ap;
5276  struct timeval now;
5277  struct ast_str *buf;
5278  int i;
5279 
5281  return 0;
5282  }
5283 
5285  return -1;
5286  }
5287 
5288  cat_str = authority_to_str(category, &auth);
5289  ast_str_set(&buf, 0,
5290  "Event: %s\r\nPrivilege: %s\r\n",
5291  event, cat_str);
5292 
5293  if (timestampevents) {
5294  now = ast_tvnow();
5295  ast_str_append(&buf, 0,
5296  "Timestamp: %ld.%06lu\r\n",
5297  (long)now.tv_sec, (unsigned long) now.tv_usec);
5298  }
5299  if (manager_debug) {
5300  static int seq;
5301  ast_str_append(&buf, 0,
5302  "SequenceNumber: %d\r\n",
5303  ast_atomic_fetchadd_int(&seq, 1));
5304  ast_str_append(&buf, 0,
5305  "File: %s\r\nLine: %d\r\nFunc: %s\r\n", file, line, func);
5306  }
5307 
5308  va_start(ap, fmt);
5309  ast_str_append_va(&buf, 0, fmt, ap);
5310  va_end(ap);
5311  for (i = 0; i < chancount; i++) {
5312  append_channel_vars(&buf, chans[i]);
5313  }
5314 
5315  ast_str_append(&buf, 0, "\r\n");
5316 
5317  append_event(ast_str_buffer(buf), category);
5318 
5319  /* Wake up any sleeping sessions */
5320  if (sessions) {
5321  struct ao2_iterator i;
5322  i = ao2_iterator_init(sessions, 0);
5323  while ((session = ao2_iterator_next(&i))) {
5324  ao2_lock(session);
5325  if (session->waiting_thread != AST_PTHREADT_NULL) {
5326  pthread_kill(session->waiting_thread, SIGURG);
5327  } else {
5328  /* We have an event to process, but the mansession is
5329  * not waiting for it. We still need to indicate that there
5330  * is an event waiting so that get_input processes the pending
5331  * event instead of polling.
5332  */
5333  session->pending_event = 1;
5334  }
5335  ao2_unlock(session);
5336  unref_mansession(session);
5337  }
5339  }
5340 
5343  AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
5344  hook->helper(category, event, ast_str_buffer(buf));
5345  }
5347  }
5348 
5349  return 0;
5350 }
5351 
5352 /*
5353  * support functions to register/unregister AMI action handlers,
5354  */
5355 int ast_manager_unregister(char *action)
5356 {
5357  struct manager_action *cur;
5358 
5361  if (!strcasecmp(action, cur->action)) {
5363  break;
5364  }
5365  }
5368 
5369  if (cur) {
5370  time_t now;
5371 
5372  /*
5373  * We have removed the action object from the container so we
5374  * are no longer in a hurry.
5375  */
5376  ao2_lock(cur);
5377  cur->registered = 0;
5378  ao2_unlock(cur);
5379 
5380  /*
5381  * Wait up to 5 seconds for any active invocations to complete
5382  * before returning. We have to wait instead of blocking
5383  * because we may be waiting for ourself to complete.
5384  */
5385  now = time(NULL);
5386  while (cur->active_count) {
5387  if (5 <= time(NULL) - now) {
5388  ast_debug(1,
5389  "Unregister manager action %s timed out waiting for %u active instances to complete\n",
5390  action, cur->active_count);
5391  break;
5392  }
5393 
5394  sched_yield();
5395  }
5396 
5397  ao2_t_ref(cur, -1, "action object removed from list");
5398  ast_verb(2, "Manager unregistered action %s\n", action);
5399  }
5400 
5401  return 0;
5402 }
5403 
5404 static int manager_state_cb(char *context, char *exten, int state, void *data)
5405 {
5406  /* Notify managers of change */
5407  char hint[512];
5408  ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten);
5409 
5410  manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nHint: %s\r\nStatus: %d\r\n", exten, context, hint, state);
5411  return 0;
5412 }
5413 
5415 {
5416  struct manager_action *cur, *prev = NULL;
5417 
5419  AST_RWLIST_TRAVERSE(&actions, cur, list) {
5420  int ret;
5421 
5422  ret = strcasecmp(cur->action, act->action);
5423  if (ret == 0) {
5424  ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
5426  return -1;
5427  }
5428  if (ret > 0) { /* Insert these alphabetically */
5429  prev = cur;
5430  break;
5431  }
5432  }
5433 
5434  ao2_t_ref(act, +1, "action object added to list");
5435  act->registered = 1;
5436  if (prev) {
5437  AST_RWLIST_INSERT_AFTER(&actions, prev, act, list);
5438  } else {
5439  AST_RWLIST_INSERT_HEAD(&actions, act, list);
5440  }
5441 
5442  ast_verb(2, "Manager registered action %s\n", act->action);
5443 
5445 
5446  return 0;
5447 }
5448 
5449 /*!
5450  * \internal
5451  * \brief Destroy the registered AMI action object.
5452  *
5453  * \param obj Object to destroy.
5454  *
5455  * \return Nothing
5456  */
5457 static void action_destroy(void *obj)
5458 {
5459  struct manager_action *doomed = obj;
5460 
5461  if (doomed->synopsis) {
5462  /* The string fields were initialized. */
5464  }
5465 }
5466 
5467 /*! \brief register a new command with manager, including online help. This is
5468  the preferred way to register a manager command */
5469 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
5470 {
5471  struct manager_action *cur;
5472 
5473  cur = ao2_alloc(sizeof(*cur), action_destroy);
5474  if (!cur) {
5475  return -1;
5476  }
5477  if (ast_string_field_init(cur, 128)) {
5478  ao2_t_ref(cur, -1, "action object creation failed");
5479  return -1;
5480  }
5481 
5482  cur->action = action;
5483  cur->authority = auth;
5484  cur->func = func;
5485 #ifdef AST_XML_DOCS
5486  if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
5487  char *tmpxml;
5488 
5489  tmpxml = ast_xmldoc_build_synopsis("manager", action, NULL);
5490  ast_string_field_set(cur, synopsis, tmpxml);
5491  ast_free(tmpxml);
5492 
5493  tmpxml = ast_xmldoc_build_syntax("manager", action, NULL);
5494  ast_string_field_set(cur, syntax, tmpxml);
5495  ast_free(tmpxml);
5496 
5497  tmpxml = ast_xmldoc_build_description("manager", action, NULL);
5498  ast_string_field_set(cur, description, tmpxml);
5499  ast_free(tmpxml);
5500 
5501  tmpxml = ast_xmldoc_build_seealso("manager", action, NULL);
5502  ast_string_field_set(cur, seealso, tmpxml);
5503  ast_free(tmpxml);
5504 
5505  tmpxml = ast_xmldoc_build_arguments("manager", action, NULL);
5506  ast_string_field_set(cur, arguments, tmpxml);
5507  ast_free(tmpxml);
5508 
5509  cur->docsrc = AST_XML_DOC;
5510  } else
5511 #endif
5512  {
5513  ast_string_field_set(cur, synopsis, synopsis);
5514  ast_string_field_set(cur, description, description);
5515 #ifdef AST_XML_DOCS
5516  cur->docsrc = AST_STATIC_DOC;
5517 #endif
5518  }
5519  if (ast_manager_register_struct(cur)) {
5520  ao2_t_ref(cur, -1, "action object registration failed");
5521  return -1;
5522  }
5523 
5524  ao2_t_ref(cur, -1, "action object registration successful");
5525  return 0;
5526 }
5527 /*! @}
5528  END Doxygen group */
5529 
5530 /*
5531  * The following are support functions for AMI-over-http.
5532  * The common entry point is generic_http_callback(),
5533  * which extracts HTTP header and URI fields and reformats
5534  * them into AMI messages, locates a proper session
5535  * (using the mansession_id Cookie or GET variable),
5536  * and calls process_message() as for regular AMI clients.
5537  * When done, the output (which goes to a temporary file)
5538  * is read back into a buffer and reformatted as desired,
5539  * then fed back to the client over the original socket.
5540  */
5545  FORMAT_XML,
5546 };
5548 static const char * const contenttype[] = {
5549  [FORMAT_RAW] = "plain",
5550  [FORMAT_HTML] = "html",
5551  [FORMAT_XML] = "xml",
5552 };
5553 
5554 /*!
5555  * locate an http session in the list. The search key (ident) is
5556  * the value of the mansession_id cookie (0 is not valid and means
5557  * a session on the AMI socket).
5558  */
5559 static struct mansession_session *find_session(uint32_t ident, int incinuse)
5560 {
5561  struct mansession_session *session;
5562  struct ao2_iterator i;
5563 
5564  if (ident == 0) {
5565  return NULL;
5566  }
5567 
5568  i = ao2_iterator_init(sessions, 0);
5569  while ((session = ao2_iterator_next(&i))) {
5570  ao2_lock(session);
5571  if (session->managerid == ident && !session->needdestroy) {
5572  ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
5573  break;
5574  }
5575  ao2_unlock(session);
5576  unref_mansession(session);
5577  }
5579 
5580  return session;
5581 }
5582 
5583 /*!
5584  * locate an http session in the list.
5585  * The search keys (nonce) and (username) is value from received
5586  * "Authorization" http header.
5587  * As well as in find_session() function, the value of the nonce can't be zero.
5588  * (0 meansi, that the session used for AMI socket connection).
5589  * Flag (stale) is set, if client used valid, but old, nonce value.
5590  *
5591  */
5592 static struct mansession_session *find_session_by_nonce(const char *username, unsigned long nonce, int *stale)
5593 {
5594  struct mansession_session *session;
5595  struct ao2_iterator i;
5596 
5597  if (nonce == 0 || username == NULL || stale == NULL) {
5598  return NULL;
5599  }
5600 
5601  i = ao2_iterator_init(sessions, 0);
5602  while ((session = ao2_iterator_next(&i))) {
5603  ao2_lock(session);
5604  if (!strcasecmp(session->username, username) && session->managerid == nonce) {
5605  *stale = 0;
5606  break;
5607  } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
5608  *stale = 1;
5609  break;
5610  }
5611  ao2_unlock(session);
5612  unref_mansession(session);
5613  }
5615  return session;
5616 }
5618 int astman_is_authed(uint32_t ident)
5619 {
5620  int authed;
5621  struct mansession_session *session;
5622 
5623  if (!(session = find_session(ident, 0)))
5624  return 0;
5625 
5626  authed = (session->authenticated != 0);
5627 
5628  ao2_unlock(session);
5629  unref_mansession(session);
5630 
5631  return authed;
5632 }
5634 int astman_verify_session_readpermissions(uint32_t ident, int perm)
5635 {
5636  int result = 0;
5637  struct mansession_session *session;
5638  struct ao2_iterator i;
5639 
5640  if (ident == 0) {
5641  return 0;
5642  }
5643 
5644  i = ao2_iterator_init(sessions, 0);
5645  while ((session = ao2_iterator_next(&i))) {
5646  ao2_lock(session);
5647  if ((session->managerid == ident) && (session->readperm & perm)) {
5648  result = 1;
5649  ao2_unlock(session);
5650  unref_mansession(session);
5651  break;
5652  }
5653  ao2_unlock(session);
5654  unref_mansession(session);
5655  }
5657  return result;
5658 }
5660 int astman_verify_session_writepermissions(uint32_t ident, int perm)
5661 {
5662  int result = 0;
5663  struct mansession_session *session;
5664  struct ao2_iterator i;
5665 
5666  if (ident == 0) {
5667  return 0;
5668  }
5669 
5670  i = ao2_iterator_init(sessions, 0);
5671  while ((session = ao2_iterator_next(&i))) {
5672  ao2_lock(session);
5673  if ((session->managerid == ident) && (session->writeperm & perm)) {
5674  result = 1;
5675  ao2_unlock(session);
5676  unref_mansession(session);
5677  break;
5678  }
5679  ao2_unlock(session);
5680  unref_mansession(session);
5681  }
5683  return result;
5684 }
5685 
5686 /*
5687  * convert to xml with various conversion:
5688  * mode & 1 -> lowercase;
5689  * mode & 2 -> replace non-alphanumeric chars with underscore
5690  */
5691 static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
5692 {
5693  /* store in a local buffer to avoid calling ast_str_append too often */
5694  char buf[256];
5695  char *dst = buf;
5696  int space = sizeof(buf);
5697  /* repeat until done and nothing to flush */
5698  for ( ; *src || dst != buf ; src++) {
5699  if (*src == '\0' || space < 10) { /* flush */
5700  *dst++ = '\0';
5701  ast_str_append(out, 0, "%s", buf);
5702  dst = buf;
5703  space = sizeof(buf);
5704  if (*src == '\0') {
5705  break;
5706  }
5707  }
5708 
5709  if ( (mode & 2) && !isalnum(*src)) {
5710  *dst++ = '_';
5711  space--;
5712  continue;
5713  }
5714  switch (*src) {
5715  case '<':
5716  strcpy(dst, "&lt;");
5717  dst += 4;
5718  space -= 4;
5719  break;
5720  case '>':
5721  strcpy(dst, "&gt;");
5722  dst += 4;
5723  space -= 4;
5724  break;
5725  case '\"':
5726  strcpy(dst, "&quot;");
5727  dst += 6;
5728  space -= 6;
5729  break;
5730  case '\'':
5731  strcpy(dst, "&apos;");
5732  dst += 6;
5733  space -= 6;
5734  break;
5735  case '&':
5736  strcpy(dst, "&amp;");
5737  dst += 5;
5738  space -= 5;
5739  break;
5740 
5741  default:
5742  *dst++ = mode ? tolower(*src) : *src;
5743  space--;
5744  }
5745  }
5746 }
5749  char *varname;
5750  int count;
5751 };
5753 static int variable_count_hash_fn(const void *vvc, const int flags)
5754 {
5755  const struct variable_count *vc = vvc;
5756 
5757  return ast_str_hash(vc->varname);
5758 }
5760 static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
5761 {
5762  /* Due to the simplicity of struct variable_count, it makes no difference
5763  * if you pass in objects or strings, the same operation applies. This is
5764  * due to the fact that the hash occurs on the first element, which means
5765  * the address of both the struct and the string are exactly the same. */
5766  struct variable_count *vc = obj;
5767  char *str = vstr;
5768  return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
5769 }
5770 
5771 /*! \brief Convert the input into XML or HTML.
5772  * The input is supposed to be a sequence of lines of the form
5773  * Name: value
5774  * optionally followed by a blob of unformatted text.
5775  * A blank line is a section separator. Basically, this is a
5776  * mixture of the format of Manager Interface and CLI commands.
5777  * The unformatted text is considered as a single value of a field
5778  * named 'Opaque-data'.
5779  *
5780  * At the moment the output format is the following (but it may
5781  * change depending on future requirements so don't count too
5782  * much on it when writing applications):
5783  *
5784  * General: the unformatted text is used as a value of
5785  * XML output: to be completed
5786  *
5787  * \verbatim
5788  * Each section is within <response type="object" id="xxx">
5789  * where xxx is taken from ajaxdest variable or defaults to unknown
5790  * Each row is reported as an attribute Name="value" of an XML
5791  * entity named from the variable ajaxobjtype, default to "generic"
5792  * \endverbatim
5793  *
5794  * HTML output:
5795  * each Name-value pair is output as a single row of a two-column table.
5796  * Sections (blank lines in the input) are separated by a <HR>
5797  *
5798  */
5799 static void xml_translate(struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
5800 {
5801  struct ast_variable *v;
5802  const char *dest = NULL;
5803  char *var, *val;
5804  const char *objtype = NULL;
5805  int in_data = 0; /* parsing data */
5806  int inobj = 0;
5807  int xml = (format == FORMAT_XML);
5808  struct variable_count *vc = NULL;
5809  struct ao2_container *vco = NULL;
5810 
5811  if (xml) {
5812  /* dest and objtype need only for XML format */
5813  for (v = get_vars; v; v = v->next) {
5814  if (!strcasecmp(v->name, "ajaxdest")) {
5815  dest = v->value;
5816  } else if (!strcasecmp(v->name, "ajaxobjtype")) {
5817  objtype = v->value;
5818  }
5819  }
5820  if (ast_strlen_zero(dest)) {
5821  dest = "unknown";
5822  }
5823  if (ast_strlen_zero(objtype)) {
5824  objtype = "generic";
5825  }
5826  }
5827 
5828  /* we want to stop when we find an empty line */
5829  while (in && *in) {
5830  val = strsep(&in, "\r\n"); /* mark start and end of line */
5831  if (in && *in == '\n') { /* remove trailing \n if any */
5832  in++;
5833  }
5834  ast_trim_blanks(val);
5835  ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
5836  if (ast_strlen_zero(val)) {
5837  /* empty line */
5838  if (in_data) {
5839  /* close data in Opaque mode */
5840  ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
5841  in_data = 0;
5842  }
5843 
5844  if (inobj) {
5845  /* close block */
5846  ast_str_append(out, 0, xml ? " /></response>\n" :
5847  "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
5848  inobj = 0;
5849  ao2_ref(vco, -1);
5850  vco = NULL;
5851  }
5852  continue;
5853  }
5854 
5855  if (!inobj) {
5856  /* start new block */
5857  if (xml) {
5858  ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
5859  }
5861  inobj = 1;
5862  }
5863 
5864  if (in_data) {
5865  /* Process data field in Opaque mode. This is a
5866  * followup, so we re-add line feeds. */
5867  ast_str_append(out, 0, xml ? "\n" : "<br>\n");
5868  xml_copy_escape(out, val, 0); /* data field */
5869  continue;
5870  }
5871 
5872  /* We expect "Name: value" line here */
5873  var = strsep(&val, ":");
5874  if (val) {
5875  /* found the field name */
5876  val = ast_skip_blanks(val);
5877  ast_trim_blanks(var);
5878  } else {
5879  /* field name not found, switch to opaque mode */
5880  val = var;
5881  var = "Opaque-data";
5882  in_data = 1;
5883  }
5884 
5885 
5886  ast_str_append(out, 0, xml ? " " : "<tr><td>");
5887  if ((vc = ao2_find(vco, var, 0))) {
5888  vc->count++;
5889  } else {
5890  /* Create a new entry for this one */
5891  vc = ao2_alloc(sizeof(*vc), NULL);
5892  vc->varname = var;
5893  vc->count = 1;
5894  ao2_link(vco, vc);
5895  }
5896 
5897  xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
5898  if (vc->count > 1) {
5899  ast_str_append(out, 0, "-%d", vc->count);
5900  }
5901  ao2_ref(vc, -1);
5902  ast_str_append(out, 0, xml ? "='" : "</td><td>");
5903  xml_copy_escape(out, val, 0); /* data field */
5904  if (!in_data || !*in) {
5905  ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
5906  }
5907  }
5908 
5909  if (inobj) {
5910  ast_str_append(out, 0, xml ? " /></response>\n" :
5911  "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
5912  ao2_ref(vco, -1);
5913  }
5914 }
5916 static void close_mansession_file(struct mansession *s)
5917 {
5918  if (s->f) {
5919  if (fclose(s->f)) {
5920  ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
5921  }
5922  s->f = NULL;
5923  s->fd = -1;
5924  } else if (s->fd != -1) {
5925  /*
5926  * Issuing shutdown() is necessary here to avoid a race
5927  * condition where the last data written may not appear
5928  * in the TCP stream. See ASTERISK-23548
5929  */
5930  shutdown(s->fd, SHUT_RDWR);
5931  if (close(s->fd)) {
5932  ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
5933  }
5934  s->fd = -1;
5935  } else {
5936  ast_log(LOG_ERROR, "Attempted to close file/file descriptor on mansession without a valid file or file descriptor.\n");
5937  }
5938 }
5940 static void process_output(struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
5941 {
5942  char *buf;
5943  size_t l;
5944 
5945  if (!s->f)
5946  return;
5947 
5948  /* Ensure buffer is NULL-terminated */
5949  fprintf(s->f, "%c", 0);
5950  fflush(s->f);
5951 
5952  if ((l = ftell(s->f)) > 0) {
5953  if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s->fd, 0))) {
5954  ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n");
5955  } else {
5956  if (format == FORMAT_XML || format == FORMAT_HTML) {
5957  xml_translate(out, buf, params, format);
5958  } else {
5959  ast_str_append(out, 0, "%s", buf);
5960  }
5961  munmap(buf, l);
5962  }
5963  } else if (format == FORMAT_XML || format == FORMAT_HTML) {
5964  xml_translate(out, "", params, format);
5965  }
5966 
5968 }
5970 static int generic_http_callback(struct ast_tcptls_session_instance *ser,
5971  enum ast_http_method method,
5972  enum output_format format,
5973  struct sockaddr_in *remote_address, const char *uri,
5974  struct ast_variable *get_params,
5975  struct ast_variable *headers)
5976 {
5977  struct mansession s = { .session = NULL, .tcptls_session = ser };
5978  struct mansession_session *session = NULL;
5979  uint32_t ident = 0;
5980  int blastaway = 0;
5981  struct ast_variable *v, *cookies, *params = get_params;
5982  char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
5983  struct ast_str *http_header = NULL, *out = NULL;
5984  struct message m = { 0 };
5985  unsigned int idx;
5986  size_t hdrlen;
5987 
5988  if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
5989  ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
5990  return -1;
5991  }
5992 
5993  cookies = ast_http_get_cookies(headers);
5994  for (v = cookies; v; v = v->next) {
5995  if (!strcasecmp(v->name, "mansession_id")) {
5996  sscanf(v->value, "%30x", &ident);
5997  break;
5998  }
5999  }
6000  if (cookies) {
6001  ast_variables_destroy(cookies);
6002  }
6003 
6004  if (!(session = find_session(ident, 1))) {
6005 
6006  /**/
6007  /* Create new session.
6008  * While it is not in the list we don't need any locking
6009  */
6010  if (!(session = build_mansession(*remote_address))) {
6011  ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
6012  return -1;
6013  }
6014  ao2_lock(session);
6015  session->sin = *remote_address;
6016  session->fd = -1;
6017  session->waiting_thread = AST_PTHREADT_NULL;
6018  session->send_events = 0;
6019  session->inuse = 1;
6020  /*!\note There is approximately a 1 in 1.8E19 chance that the following
6021  * calculation will produce 0, which is an invalid ID, but due to the
6022  * properties of the rand() function (and the constantcy of s), that
6023  * won't happen twice in a row.
6024  */
6025  while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
6026  session->last_ev = grab_last();
6027  AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
6028  }
6029  ao2_unlock(session);
6030 
6031  http_header = ast_str_create(128);
6032  out = ast_str_create(2048);
6033 
6034  ast_mutex_init(&s.lock);
6035 
6036  if (http_header == NULL || out == NULL) {
6037  ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
6038  goto generic_callback_out;
6039  }
6040 
6041  s.session = session;
6042  s.fd = mkstemp(template); /* create a temporary file for command output */
6043  unlink(template);
6044  if (s.fd <= -1) {
6045  ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
6046  goto generic_callback_out;
6047  }
6048  s.f = fdopen(s.fd, "w+");
6049  if (!s.f) {
6050  ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
6051  ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
6052  close(s.fd);
6053  goto generic_callback_out;
6054  }
6055 
6056  if (method == AST_HTTP_POST) {
6057  params = ast_http_get_post_vars(ser, headers);
6058  }
6059 
6060  for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
6061  hdrlen = strlen(v->name) + strlen(v->value) + 3;
6062  m.headers[m.hdrcount] = ast_malloc(hdrlen);
6063  if (!m.headers[m.hdrcount]) {
6064  /* Allocation failure */
6065  continue;
6066  }
6067  snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
6068  ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
6069  ++m.hdrcount;
6070  }
6071 
6072  if (process_message(&s, &m)) {
6073  if (session->authenticated) {
6074  if (manager_displayconnects(session)) {
6075  ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
6076  }
6077  } else {
6078  if (displayconnects) {
6079  ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
6080  }
6081  }
6082  session->needdestroy = 1;
6083  }
6084 
6085  /* Free request headers. */
6086  for (idx = 0; idx < m.hdrcount; ++idx) {
6087  ast_free((void *) m.headers[idx]);
6088  m.headers[idx] = NULL;
6089  }
6090 
6091  ast_str_append(&http_header, 0,
6092  "Content-type: text/%s\r\n"
6093  "Cache-Control: no-cache;\r\n"
6094  "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
6095  "Pragma: SuppressEvents\r\n",
6096  contenttype[format],
6097  session->managerid, httptimeout);
6098 
6099  if (format == FORMAT_XML) {
6100  ast_str_append(&out, 0, "<ajax-response>\n");
6101  } else if (format == FORMAT_HTML) {
6102  /*
6103  * When handling AMI-over-HTTP in HTML format, we provide a simple form for
6104  * debugging purposes. This HTML code should not be here, we
6105  * should read from some config file...
6106  */
6107 
6108 #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
6109 #define TEST_STRING \
6110  "<form action=\"manager\" method=\"post\">\n\
6111  Action: <select name=\"action\">\n\
6112  <option value=\"\">-----&gt;</option>\n\
6113  <option value=\"login\">login</option>\n\
6114  <option value=\"command\">Command</option>\n\
6115  <option value=\"waitevent\">waitevent</option>\n\
6116  <option value=\"listcommands\">listcommands</option>\n\
6117  </select>\n\
6118  or <input name=\"action\"><br/>\n\
6119  CLI Command <input name=\"command\"><br>\n\
6120  user <input name=\"username\"> pass <input type=\"password\" name=\"secret\"><br>\n\
6121  <input type=\"submit\">\n</form>\n"
6122 
6123  ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
6124  ast_str_append(&out, 0, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
6125  ast_str_append(&out, 0, ROW_FMT, "<h1>Manager Tester</h1>");
6126  ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
6127  }
6128 
6129  process_output(&s, &out, params, format);
6130 
6131  if (format == FORMAT_XML) {
6132  ast_str_append(&out, 0, "</ajax-response>\n");
6133  } else if (format == FORMAT_HTML) {
6134  ast_str_append(&out, 0, "</table></body>\r\n");
6135  }
6136 
6137  ao2_lock(session);
6138  /* Reset HTTP timeout. If we're not authenticated, keep it extremely short */
6139  session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
6140 
6141  if (session->needdestroy) {
6142  if (session->inuse == 1) {
6143  ast_debug(1, "Need destroy, doing it now!\n");
6144  blastaway = 1;
6145  } else {
6146  ast_debug(1, "Need destroy, but can't do it yet!\n");
6147  if (session->waiting_thread != AST_PTHREADT_NULL) {
6148  pthread_kill(session->waiting_thread, SIGURG);
6149  }
6150  session->inuse--;
6151  }
6152  } else {
6153  session->inuse--;
6154  }
6155  ao2_unlock(session);
6156 
6157  ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
6158  http_header = out = NULL;
6159 
6160 generic_callback_out:
6161  ast_mutex_destroy(&s.lock);
6162 
6163  /* Clear resource */
6164 
6165  if (method == AST_HTTP_POST && params) {
6166  ast_variables_destroy(params);
6167  }
6168  ast_free(http_header);
6169  ast_free(out);
6170 
6171  if (session && blastaway) {
6172  session_destroy(session);
6173  } else if (session && session->f) {
6174  fclose(session->f);
6175  session->f = NULL;
6176  }
6177 
6178  return 0;
6179 }
6181 static int auth_http_callback(struct ast_tcptls_session_instance *ser,
6182  enum ast_http_method method,
6183  enum output_format format,
6184  struct sockaddr_in *remote_address, const char *uri,
6185  struct ast_variable *get_params,
6186  struct ast_variable *headers)
6187 {
6188  struct mansession_session *session = NULL;
6189  struct mansession s = { .session = NULL, .tcptls_session = ser };
6190  struct ast_variable *v, *params = get_params;
6191  char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
6192  struct ast_str *http_header = NULL, *out = NULL;
6193  size_t result_size = 512;
6194  struct message m = { 0 };
6195  unsigned int idx;
6196  size_t hdrlen;
6197 
6198  time_t time_now = time(NULL);
6199  unsigned long nonce = 0, nc;
6200  struct ast_http_digest d = { NULL, };
6201  struct ast_manager_user *user = NULL;
6202  int stale = 0;
6203  char resp_hash[256]="";
6204  /* Cache for user data */
6205  char u_username[80];
6206  int u_readperm;
6207  int u_writeperm;
6208  int u_writetimeout;
6209  int u_displayconnects;
6210  struct ast_sockaddr addr;
6211 
6212  if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
6213  ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
6214  return -1;
6215  }
6216 
6217  /* Find "Authorization: " header */
6218  for (v = headers; v; v = v->next) {
6219  if (!strcasecmp(v->name, "Authorization")) {
6220  break;
6221  }
6222  }
6223 
6224  if (!v || ast_strlen_zero(v->value)) {
6225  goto out_401; /* Authorization Header not present - send auth request */
6226  }
6227 
6228  /* Digest found - parse */
6229  if (ast_string_field_init(&d, 128)) {
6230  ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
6231  return -1;
6232  }
6233 
6234  if (ast_parse_digest(v->value, &d, 0, 1)) {
6235  /* Error in Digest - send new one */
6236  nonce = 0;
6237  goto out_401;
6238  }
6239  if (sscanf(d.nonce, "%30lx", &nonce) != 1) {
6240  ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
6241  nonce = 0;
6242  goto out_401;
6243  }
6244 
6247  if(!user) {
6249  ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
6250  nonce = 0;
6251  goto out_401;
6252  }
6253 
6254  ast_sockaddr_from_sin(&addr, remote_address);
6255  /* --- We have User for this auth, now check ACL */
6256  if (user->ha && !ast_apply_ha(user->ha, &addr)) {
6258  ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
6259  ast_http_error(ser, 403, "Permission denied", "Permission denied\n");
6260  return -1;
6261  }
6262 
6263  /* --- We have auth, so check it */
6264 
6265  /* compute the expected response to compare with what we received */
6266  {
6267  char a2[256];
6268  char a2_hash[256];
6269  char resp[256];
6270 
6271  /* XXX Now request method are hardcoded in A2 */
6272  snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
6273  ast_md5_hash(a2_hash, a2);
6274 
6275  if (d.qop) {
6276  /* RFC 2617 */
6277  snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
6278  } else {
6279  /* RFC 2069 */
6280  snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
6281  }
6282  ast_md5_hash(resp_hash, resp);
6283  }
6284 
6285  if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
6286  /* Something was wrong, so give the client to try with a new challenge */
6288  nonce = 0;
6289  goto out_401;
6290  }
6291 
6292  /*
6293  * User are pass Digest authentication.
6294  * Now, cache the user data and unlock user list.
6295  */
6296  ast_copy_string(u_username, user->username, sizeof(u_username));
6297  u_readperm = user->readperm;
6298  u_writeperm = user->writeperm;
6299  u_displayconnects = user->displayconnects;
6300  u_writetimeout = user->writetimeout;
6302 
6303  if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
6304  /*
6305  * Create new session.
6306  * While it is not in the list we don't need any locking
6307  */
6308  if (!(session = build_mansession(*remote_address))) {
6309  ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
6310  return -1;
6311  }
6312  ao2_lock(session);
6313 
6314  ast_copy_string(session->username, u_username, sizeof(session->username));
6315  session->managerid = nonce;
6316  session->last_ev = grab_last();
6318 
6319  session->readperm = u_readperm;
6320  session->writeperm = u_writeperm;
6321  session->writetimeout = u_writetimeout;
6322 
6323  if (u_displayconnects) {
6324  ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
6325  }
6326  session->noncetime = session->sessionstart = time_now;
6327  session->authenticated = 1;
6328  } else if (stale) {
6329  /*
6330  * Session found, but nonce is stale.
6331  *
6332  * This could be because an old request (w/old nonce) arrived.
6333  *
6334  * This may be as the result of http proxy usage (separate delay or
6335  * multipath) or in a situation where a page was refreshed too quickly
6336  * (seen in Firefox).
6337  *
6338  * In this situation, we repeat the 401 auth with the current nonce
6339  * value.
6340  */
6341  nonce = session->managerid;
6342  ao2_unlock(session);
6343  stale = 1;
6344  goto out_401;
6345  } else {
6346  sscanf(d.nc, "%30lx", &nc);
6347  if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
6348  /*
6349  * Nonce time expired (> 2 minutes) or something wrong with nonce
6350  * counter.
6351  *
6352  * Create new nonce key and resend Digest auth request. Old nonce
6353  * is saved for stale checking...
6354  */
6355  session->nc = 0; /* Reset nonce counter */
6356  session->oldnonce = session->managerid;
6357  nonce = session->managerid = ast_random();
6358  session->noncetime = time_now;
6359  ao2_unlock(session);
6360  stale = 1;
6361  goto out_401;
6362  } else {
6363  session->nc = nc; /* All OK, save nonce counter */
6364  }
6365  }
6366 
6367 
6368  /* Reset session timeout. */
6369  session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
6370  ao2_unlock(session);
6371 
6372  ast_mutex_init(&s.lock);
6373  s.session = session;
6374  s.fd = mkstemp(template); /* create a temporary file for command output */
6375  unlink(template);
6376  if (s.fd <= -1) {
6377  ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
6378  goto auth_callback_out;
6379  }
6380  s.f = fdopen(s.fd, "w+");
6381  if (!s.f) {
6382  ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
6383  ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
6384  close(s.fd);
6385  goto auth_callback_out;
6386  }
6387 
6388  if (method == AST_HTTP_POST) {
6389  params = ast_http_get_post_vars(ser, headers);
6390  }
6391 
6392  for (v = params; v && m.hdrcount < ARRAY_LEN(m.headers); v = v->next) {
6393  hdrlen = strlen(v->name) + strlen(v->value) + 3;
6394  m.headers[m.hdrcount] = ast_malloc(hdrlen);
6395  if (!m.headers[m.hdrcount]) {
6396  /* Allocation failure */
6397  continue;
6398  }
6399  snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
6400  ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
6401  ++m.hdrcount;
6402  }
6403 
6404  if (process_message(&s, &m)) {
6405  if (u_displayconnects) {
6406  ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
6407  }
6408 
6409  session->needdestroy = 1;
6410  }
6411 
6412  /* Free request headers. */
6413  for (idx = 0; idx < m.hdrcount; ++idx) {
6414  ast_free((void *) m.headers[idx]);
6415  m.headers[idx] = NULL;
6416  }
6417 
6418  if (s.f) {
6419  result_size = ftell(s.f); /* Calculate approx. size of result */
6420  }
6421 
6422  http_header = ast_str_create(80);
6423  out = ast_str_create(result_size * 2 + 512);
6424 
6425  if (http_header == NULL || out == NULL) {
6426  ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
6427  goto auth_callback_out;
6428  }
6429 
6430  ast_str_append(&http_header, 0, "Content-type: text/%s\r\n", contenttype[format]);
6431 
6432  if (format == FORMAT_XML) {
6433  ast_str_append(&out, 0, "<ajax-response>\n");
6434  } else if (format == FORMAT_HTML) {
6435  ast_str_append(&out, 0,
6436  "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
6437  "<html><head>\r\n"
6438  "<title>Asterisk&trade; Manager Interface</title>\r\n"
6439  "</head><body style=\"background-color: #ffffff;\">\r\n"
6440  "<form method=\"POST\">\r\n"
6441  "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
6442  "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
6443  "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
6444  "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
6445  }
6446 
6447  process_output(&s, &out, params, format);
6448 
6449  if (format == FORMAT_XML) {
6450  ast_str_append(&out, 0, "</ajax-response>\n");
6451  } else if (format == FORMAT_HTML) {
6452  ast_str_append(&out, 0, "</table></form></body></html>\r\n");
6453  }
6454 
6455  ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
6456  http_header = out = NULL;
6457 
6458 auth_callback_out:
6459  ast_mutex_destroy(&s.lock);
6460 
6461  /* Clear resources and unlock manager session */
6462  if (method == AST_HTTP_POST && params) {
6463  ast_variables_destroy(params);
6464  }
6465 
6466  ast_free(http_header);
6467  ast_free(out);
6468 
6469  ao2_lock(session);
6470  if (session->f) {
6471  fclose(session->f);
6472  }
6473  session->f = NULL;
6474  session->fd = -1;
6475  ao2_unlock(session);
6476 
6477  if (session->needdestroy) {
6478  ast_debug(1, "Need destroy, doing it now!\n");
6479  session_destroy(session);
6480  }
6482  return 0;
6483 
6484 out_401:
6485  if (!nonce) {
6486  nonce = ast_random();
6487  }
6488 
6489  ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
6491  return 0;
6492 }
6494 static int manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
6495 {
6496  int retval;
6497  struct sockaddr_in ser_remote_address_tmp;
6498 
6499  ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
6500  retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
6501  ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
6502  return retval;
6503 }
6505 static int mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
6506 {
6507  int retval;
6508  struct sockaddr_in ser_remote_address_tmp;
6509 
6510  ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
6511  retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
6512  ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
6513  return retval;
6514 }
6516 static int rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
6517 {
6518  int retval;
6519  struct sockaddr_in ser_remote_address_tmp;
6520 
6521  ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
6522  retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
6523  ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
6524  return retval;
6525 }
6527 static struct ast_http_uri rawmanuri = {
6528  .description = "Raw HTTP Manager Event Interface",
6529  .uri = "rawman",
6530  .callback = rawman_http_callback,
6531  .data = NULL,
6532  .key = __FILE__,
6533 };
6535 static struct ast_http_uri manageruri = {
6536  .description = "HTML Manager Event Interface",
6537  .uri = "manager",
6538  .callback = manager_http_callback,
6539  .data = NULL,
6540  .key = __FILE__,
6541 };
6543 static struct ast_http_uri managerxmluri = {
6544  .description = "XML Manager Event Interface",
6545  .uri = "mxml",
6546  .callback = mxml_http_callback,
6547  .data = NULL,
6548  .key = __FILE__,
6549 };
6550 
6551 
6552 /* Callback with Digest authentication */
6553 static int auth_manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
6554 {
6555  int retval;
6556  struct sockaddr_in ser_remote_address_tmp;
6557 
6558  ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
6559  retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers);
6560  ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
6561  return retval;
6562 }
6564 static int auth_mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
6565 {
6566  int retval;
6567  struct sockaddr_in ser_remote_address_tmp;
6568 
6569  ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
6570  retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers);
6571  ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
6572  return retval;
6573 }
6575 static int auth_rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
6576 {
6577  int retval;
6578  struct sockaddr_in ser_remote_address_tmp;
6579 
6580  ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp);
6581  retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers);
6582  ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp);
6583  return retval;
6584 }
6586 static struct ast_http_uri arawmanuri = {
6587  .description = "Raw HTTP Manager Event Interface w/Digest authentication",
6588  .uri = "arawman",
6589  .has_subtree = 0,
6590  .callback = auth_rawman_http_callback,
6591  .data = NULL,
6592  .key = __FILE__,
6593 };
6595 static struct ast_http_uri amanageruri = {
6596  .description = "HTML Manager Event Interface w/Digest authentication",
6597  .uri = "amanager",
6598  .has_subtree = 0,
6599  .callback = auth_manager_http_callback,
6600  .data = NULL,
6601  .key = __FILE__,
6602 };
6604 static struct ast_http_uri amanagerxmluri = {
6605  .description = "XML Manager Event Interface w/Digest authentication",
6606  .uri = "amxml",
6607  .has_subtree = 0,
6608  .callback = auth_mxml_http_callback,
6609  .data = NULL,
6610  .key = __FILE__,
6611 };
6613 static int webregged = 0;
6614 
6615 /*! \brief cleanup code called at each iteration of server_root,
6616  * guaranteed to happen every 5 seconds at most
6617  */
6618 static void purge_old_stuff(void *data)
6619 {
6620  purge_sessions(1);
6621  purge_events();
6622 }
6625 static struct ast_tcptls_session_args ami_desc = {
6626  .accept_fd = -1,
6627  .master = AST_PTHREADT_NULL,
6628  .tls_cfg = NULL,
6629  .poll_timeout = 5000, /* wake up every 5 seconds */
6630  .periodic_fn = purge_old_stuff,
6631  .name = "AMI server",
6632  .accept_fn = ast_tcptls_server_root, /* thread doing the accept() */
6633  .worker_fn = session_do, /* thread handling the session */
6634 };
6636 static struct ast_tcptls_session_args amis_desc = {
6637  .accept_fd = -1,
6638  .master = AST_PTHREADT_NULL,
6639  .tls_cfg = &ami_tls_cfg,
6640  .poll_timeout = -1, /* the other does the periodic cleanup */
6641  .name = "AMI TLS server",
6642  .accept_fn = ast_tcptls_server_root, /* thread doing the accept() */
6643  .worker_fn = session_do, /* thread handling the session */
6644 };
6645 
6646 /*! \brief CLI command manager show settings */
6647 static char *handle_manager_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
6648 {
6649  switch (cmd) {
6650  case CLI_INIT:
6651  e->command = "manager show settings";
6652  e->usage =
6653  "Usage: manager show settings\n"
6654  " Provides detailed list of the configuration of the Manager.\n";
6655  return NULL;
6656  case CLI_GENERATE:
6657  return NULL;
6658  }
6659 #define FORMAT " %-25.25s %-15.15s\n"
6660 #define FORMAT2 " %-25.25s %-15d\n"
6661  if (a->argc != 3) {
6662  return CLI_SHOWUSAGE;
6663  }
6664  ast_cli(a->fd, "\nGlobal Settings:\n");
6665  ast_cli(a->fd, "----------------\n");
6666  ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled));
6667  ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled));
6668  ast_cli(a->fd, FORMAT, "TCP Bindaddress:", manager_enabled != 0 ? ast_sockaddr_stringify(&ami_desc.local_address) : "Disabled");
6669  ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout);
6670  ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled));
6671  ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ami_tls_cfg.enabled != 0 ? ast_sockaddr_stringify(&amis_desc.local_address) : "Disabled");
6672  ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile);
6673  ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile);
6674  ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher);
6675  ast_cli(a->fd, FORMAT, "Allow multiple login:", AST_CLI_YESNO(allowmultiplelogin));
6676  ast_cli(a->fd, FORMAT, "Display connects:", AST_CLI_YESNO(displayconnects));
6677  ast_cli(a->fd, FORMAT, "Timestamp events:", AST_CLI_YESNO(timestampevents));
6678  ast_cli(a->fd, FORMAT, "Channel vars:", S_OR(manager_channelvars, ""));
6679  ast_cli(a->fd, FORMAT, "Debug:", AST_CLI_YESNO(manager_debug));
6680 #undef FORMAT
6681 #undef FORMAT2
6682 
6683  return CLI_SUCCESS;
6684 }
6686 static struct ast_cli_entry cli_manager[] = {
6687  AST_CLI_DEFINE(handle_showmancmd, "Show a manager interface command"),
6688  AST_CLI_DEFINE(handle_showmancmds, "List manager interface commands"),
6689  AST_CLI_DEFINE(handle_showmanconn, "List connected manager interface users"),
6690  AST_CLI_DEFINE(handle_showmaneventq, "List manager interface queued events"),
6691  AST_CLI_DEFINE(handle_showmanagers, "List configured manager users"),
6692  AST_CLI_DEFINE(handle_showmanager, "Display information on a specific manager user"),
6693  AST_CLI_DEFINE(handle_mandebug, "Show, enable, disable debugging of the manager code"),
6694  AST_CLI_DEFINE(handle_manager_reload, "Reload manager configurations"),
6695  AST_CLI_DEFINE(handle_manager_show_settings, "Show manager global settings"),
6696 };
6697 
6698 /*!
6699  * \internal
6700  * \brief Load the config channelvars variable.
6701  *
6702  * \param var Config variable to load.
6703  *
6704  * \return Nothing
6705  */
6706 static void load_channelvars(struct ast_variable *var)
6707 {
6708  struct manager_channel_variable *mcv;
6709  char *remaining = ast_strdupa(var->value);
6710  char *next;
6711 
6712  ast_free(manager_channelvars);
6713  manager_channelvars = ast_strdup(var->value);
6714 
6715  /*
6716  * XXX TODO: To allow dialplan functions to have more than one
6717  * parameter requires eliminating the '|' as a separator so we
6718  * could use AST_STANDARD_APP_ARGS() to separate items.
6719  */
6720  free_channelvars();
6721  AST_RWLIST_WRLOCK(&channelvars);
6722  while ((next = strsep(&remaining, ",|"))) {
6723  if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
6724  break;
6725  }
6726  strcpy(mcv->name, next); /* SAFE */
6727  if (strchr(next, '(')) {
6728  mcv->isfunc = 1;
6729  }
6730  AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
6731  }
6732  AST_RWLIST_UNLOCK(&channelvars);
6733 }
6734 
6735 /*! \internal \brief Free a user record. Should already be removed from the list */
6736 static void manager_free_user(struct ast_manager_user *user)
6737 {
6738  ast_free(user->a1_hash);
6739  ast_free(user->secret);
6740  if (user->whitefilters) {
6741  ao2_t_ref(user->whitefilters, -1, "decrement ref for white container, should be last one");
6742  }
6743  if (user->blackfilters) {
6744  ao2_t_ref(user->blackfilters, -1, "decrement ref for black container, should be last one");
6745  }
6746  ast_free_ha(user->ha);
6747  ast_free(user);
6748 }
6749 
6750 /*! \internal \brief Clean up resources on Asterisk shutdown */
6751 static void manager_shutdown(void)
6752 {
6753  struct ast_manager_user *user;
6754 
6755  ast_manager_unregister("Ping");
6756  ast_manager_unregister("Events");
6757  ast_manager_unregister("Logoff");
6758  ast_manager_unregister("Login");
6759  ast_manager_unregister("Challenge");
6760  ast_manager_unregister("Hangup");
6761  ast_manager_unregister("Status");
6762  ast_manager_unregister("Setvar");
6763  ast_manager_unregister("Getvar");
6764  ast_manager_unregister("GetConfig");
6765  ast_manager_unregister("GetConfigJSON");
6766  ast_manager_unregister("UpdateConfig");
6767  ast_manager_unregister("CreateConfig");
6768  ast_manager_unregister("ListCategories");
6769  ast_manager_unregister("Redirect");
6770  ast_manager_unregister("Atxfer");
6771  ast_manager_unregister("Originate");
6772  ast_manager_unregister("Command");
6773  ast_manager_unregister("ExtensionState");
6774  ast_manager_unregister("AbsoluteTimeout");
6775  ast_manager_unregister("MailboxStatus");
6776  ast_manager_unregister("MailboxCount");
6777  ast_manager_unregister("ListCommands");
6778  ast_manager_unregister("SendText");
6779  ast_manager_unregister("UserEvent");
6780  ast_manager_unregister("WaitEvent");
6781  ast_manager_unregister("CoreSettings");
6782  ast_manager_unregister("CoreStatus");
6783  ast_manager_unregister("Reload");
6784  ast_manager_unregister("CoreShowChannels");
6785  ast_manager_unregister("ModuleLoad");
6786  ast_manager_unregister("ModuleCheck");
6787  ast_manager_unregister("AOCMessage");
6788  ast_manager_unregister("Filter");
6789  ast_cli_unregister_multiple(cli_manager, ARRAY_LEN(cli_manager));
6790 
6791  ast_tcptls_server_stop(&ami_desc);
6792  ast_tcptls_server_stop(&amis_desc);
6793 
6795  ami_tls_cfg.certfile = NULL;
6797  ami_tls_cfg.pvtfile = NULL;
6799  ami_tls_cfg.cipher = NULL;
6800 
6801  /*
6802  * We cannot destroy the global sessions container.
6803  * References to it have no protection against shutdown.
6804  */
6805 
6806  while ((user = AST_LIST_REMOVE_HEAD(&users, list))) {
6807  manager_free_user(user);
6808  }
6809 }
6811 static void manager_set_defaults(void)
6812 {
6813  manager_enabled = DEFAULT_ENABLED;
6814  webmanager_enabled = DEFAULT_WEBENABLED;
6815  manager_debug = DEFAULT_MANAGERDEBUG;
6816  displayconnects = DEFAULT_DISPLAYCONNECTS;
6817  broken_events_action = DEFAULT_BROKENEVENTSACTION;
6818  timestampevents = DEFAULT_TIMESTAMPEVENTS;
6819  httptimeout = DEFAULT_HTTPTIMEOUT;
6820  authtimeout = DEFAULT_AUTHTIMEOUT;
6821  authlimit = DEFAULT_AUTHLIMIT;
6822 
6823  /* default values */
6825  sizeof(global_realm));
6827  ast_sockaddr_setnull(&amis_desc.local_address);
6828 
6829  ami_tls_cfg.enabled = 0;
6836 
6837  free_channelvars();
6838 }
6840 static int __init_manager(int reload)
6841 {
6842  struct ast_config *ucfg = NULL, *cfg = NULL;
6843  const char *val;
6844  char *cat = NULL;
6845  int newhttptimeout = DEFAULT_HTTPTIMEOUT;
6846  struct ast_manager_user *user = NULL;
6847  struct ast_variable *var;
6848  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
6849  char a1[256];
6850  char a1_hash[256];
6851  struct sockaddr_in ami_desc_local_address_tmp = { 0, };
6852  struct sockaddr_in amis_desc_local_address_tmp = { 0, };
6853  int tls_was_enabled = 0;
6854 
6855  if (!reload) {
6857 
6858  /* Register default actions */
6863  ast_manager_register_xml("Challenge", 0, action_challenge);
6881  ast_manager_register_xml("ListCommands", 0, action_listcommands);
6884  ast_manager_register_xml("WaitEvent", 0, action_waitevent);
6892 
6893  ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
6894  ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
6895 
6896  /* Append placeholder event so master_eventq never runs dry */
6897  if (append_event("Event: Placeholder\r\n\r\n", 0)) {
6898  return -1;
6899  }
6900 
6901  /* If you have a NULL hash fn, you only need a single bucket */
6903  if (!sessions) {
6904  return -1;
6905  }
6906 
6907  /* Initialize all settings before first configuration load. */
6909  }
6910 
6911  cfg = ast_config_load2("manager.conf", "manager", config_flags);
6912  if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
6913  return 0;
6914  } else if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
6915  ast_log(LOG_NOTICE, "Unable to open AMI configuration manager.conf, or configuration is invalid.\n");
6916  return 0;
6917  }
6918 
6919  if (reload) {
6920  /* Reset all settings before reloading configuration */
6921  tls_was_enabled = ami_tls_cfg.enabled;
6923  }
6924 
6925  ami_desc_local_address_tmp.sin_family = AF_INET;
6926  amis_desc_local_address_tmp.sin_family = AF_INET;
6927 
6928  ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT);
6929 
6930  for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
6931  val = var->value;
6932 
6933  /* read tls config options while preventing unsupported options from being set */
6934  if (strcasecmp(var->name, "tlscafile")
6935  && strcasecmp(var->name, "tlscapath")
6936  && strcasecmp(var->name, "tlscadir")
6937  && strcasecmp(var->name, "tlsverifyclient")
6938  && strcasecmp(var->name, "tlsdontverifyserver")
6939  && strcasecmp(var->name, "tlsclientmethod")
6940  && strcasecmp(var->name, "sslclientmethod")
6941  && !ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
6942  continue;
6943  }
6944 
6945  if (!strcasecmp(var->name, "enabled")) {
6946  manager_enabled = ast_true(val);
6947  } else if (!strcasecmp(var->name, "webenabled")) {
6948  webmanager_enabled = ast_true(val);
6949  } else if (!strcasecmp(var->name, "port")) {
6950  ami_desc_local_address_tmp.sin_port = htons(atoi(val));
6951  } else if (!strcasecmp(var->name, "bindaddr")) {
6952  if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) {
6953  ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
6954  memset(&ami_desc_local_address_tmp.sin_addr, 0,
6955  sizeof(ami_desc_local_address_tmp.sin_addr));
6956  }
6957  } else if (!strcasecmp(var->name, "brokeneventsaction")) {
6958  broken_events_action = ast_true(val);
6959  } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
6960  allowmultiplelogin = ast_true(val);
6961  } else if (!strcasecmp(var->name, "displayconnects")) {
6962  displayconnects = ast_true(val);
6963  } else if (!strcasecmp(var->name, "timestampevents")) {
6964  timestampevents = ast_true(val);
6965  } else if (!strcasecmp(var->name, "debug")) {
6966  manager_debug = ast_true(val);
6967  } else if (!strcasecmp(var->name, "httptimeout")) {
6968  newhttptimeout = atoi(val);
6969  } else if (!strcasecmp(var->name, "authtimeout")) {
6970  int timeout = atoi(var->value);
6971 
6972  if (timeout < 1) {
6973  ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", var->value);
6974  } else {
6975  authtimeout = timeout;
6976  }
6977  } else if (!strcasecmp(var->name, "authlimit")) {
6978  int limit = atoi(var->value);
6979 
6980  if (limit < 1) {
6981  ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", var->value);
6982  } else {
6983  authlimit = limit;
6984  }
6985  } else if (!strcasecmp(var->name, "channelvars")) {
6986  load_channelvars(var);
6987  } else {
6988  ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
6989  var->name, val);
6990  }
6991  }
6992 
6993  ast_sockaddr_to_sin(&amis_desc.local_address, &amis_desc_local_address_tmp);
6994 
6995  /* if the amis address has not been set, default is the same as non secure ami */
6996  if (!amis_desc_local_address_tmp.sin_addr.s_addr) {
6997  amis_desc_local_address_tmp.sin_addr =
6998  ami_desc_local_address_tmp.sin_addr;
6999  }
7000 
7001  if (!amis_desc_local_address_tmp.sin_port) {
7002  amis_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_TLS_PORT);
7003  }
7004 
7005  if (manager_enabled) {
7006  ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp);
7007  ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp);
7008  }
7009 
7011 
7012  /* First, get users from users.conf */
7013  ucfg = ast_config_load2("users.conf", "manager", config_flags);
7014  if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
7015  const char *hasmanager;
7016  int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
7017 
7018  while ((cat = ast_category_browse(ucfg, cat))) {
7019  if (!strcasecmp(cat, "general")) {
7020  continue;
7021  }
7022 
7023  hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
7024  if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
7025  const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
7026  const char *user_read = ast_variable_retrieve(ucfg, cat, "read");
7027  const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
7028  const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
7029  const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
7030 
7031  /* Look for an existing entry,
7032  * if none found - create one and add it to the list
7033  */
7034  if (!(user = get_manager_by_name_locked(cat))) {
7035  if (!(user = ast_calloc(1, sizeof(*user)))) {
7036  break;
7037  }
7038 
7039  /* Copy name over */
7040  ast_copy_string(user->username, cat, sizeof(user->username));
7041  /* Insert into list */
7042  AST_LIST_INSERT_TAIL(&users, user, list);
7043  user->ha = NULL;
7044  user->keep = 1;
7045  user->readperm = -1;
7046  user->writeperm = -1;
7047  /* Default displayconnect from [general] */
7049  user->writetimeout = 100;
7050  }
7051 
7052  if (!user_secret) {
7053  user_secret = ast_variable_retrieve(ucfg, "general", "secret");
7054  }
7055  if (!user_read) {
7056  user_read = ast_variable_retrieve(ucfg, "general", "read");
7057  }
7058  if (!user_write) {
7059  user_write = ast_variable_retrieve(ucfg, "general", "write");
7060  }
7061  if (!user_displayconnects) {
7062  user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
7063  }
7064  if (!user_writetimeout) {
7065  user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
7066  }
7067 
7068  if (!ast_strlen_zero(user_secret)) {
7069  ast_free(user->secret);
7070  user->secret = ast_strdup(user_secret);
7071  }
7072 
7073  if (user_read) {
7074  user->readperm = get_perm(user_read);
7075  }
7076  if (user_write) {
7077  user->writeperm = get_perm(user_write);
7078  }
7079  if (user_displayconnects) {
7080  user->displayconnects = ast_true(user_displayconnects);
7081  }
7082  if (user_writetimeout) {
7083  int value = atoi(user_writetimeout);
7084  if (value < 100) {
7085  ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value);
7086  } else {
7087  user->writetimeout = value;
7088  }
7089  }
7090  }
7091  }
7092  ast_config_destroy(ucfg);
7093  }
7094 
7095  /* cat is NULL here in any case */
7096 
7097  while ((cat = ast_category_browse(cfg, cat))) {
7098  struct ast_ha *oldha;
7099 
7100  if (!strcasecmp(cat, "general")) {
7101  continue;
7102  }
7103 
7104  /* Look for an existing entry, if none found - create one and add it to the list */
7105  if (!(user = get_manager_by_name_locked(cat))) {
7106  if (!(user = ast_calloc(1, sizeof(*user)))) {
7107  break;
7108  }
7109  /* Copy name over */
7110  ast_copy_string(user->username, cat, sizeof(user->username));
7111 
7112  user->ha = NULL;
7113  user->readperm = 0;
7114  user->writeperm = 0;
7115  /* Default displayconnect from [general] */
7117  user->writetimeout = 100;
7118  user->whitefilters = ao2_container_alloc(1, NULL, NULL);
7119  user->blackfilters = ao2_container_alloc(1, NULL, NULL);
7120  if (!user->whitefilters || !user->blackfilters) {
7121  manager_free_user(user);
7122  break;
7123  }
7124 
7125  /* Insert into list */
7126  AST_RWLIST_INSERT_TAIL(&users, user, list);
7127  } else {
7128  ao2_t_callback(user->whitefilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all white filters");
7129  ao2_t_callback(user->blackfilters, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "unlink all black filters");
7130  }
7131 
7132  /* Make sure we keep this user and don't destroy it during cleanup */
7133  user->keep = 1;
7134  oldha = user->ha;
7135  user->ha = NULL;
7136 
7137  var = ast_variable_browse(cfg, cat);
7138  for (; var; var = var->next) {
7139  if (!strcasecmp(var->name, "secret")) {
7140  ast_free(user->secret);
7141  user->secret = ast_strdup(var->value);
7142  } else if (!strcasecmp(var->name, "deny") ||
7143  !strcasecmp(var->name, "permit")) {
7144  user->ha = ast_append_ha(var->name, var->value, user->ha, NULL);
7145  } else if (!strcasecmp(var->name, "read") ) {
7146  user->readperm = get_perm(var->value);
7147  } else if (!strcasecmp(var->name, "write") ) {
7148  user->writeperm = get_perm(var->value);
7149  } else if (!strcasecmp(var->name, "displayconnects") ) {
7150  user->displayconnects = ast_true(var->value);
7151  } else if (!strcasecmp(var->name, "writetimeout")) {
7152  int value = atoi(var->value);
7153  if (value < 100) {
7154  ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
7155  } else {
7156  user->writetimeout = value;
7157  }
7158  } else if (!strcasecmp(var->name, "eventfilter")) {
7159  const char *value = var->value;
7160  regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
7161  if (new_filter) {
7162  int is_blackfilter;
7163  if (value[0] == '!') {
7164  is_blackfilter = 1;
7165  value++;
7166  } else {
7167  is_blackfilter = 0;
7168  }
7169  if (regcomp(new_filter, value, 0)) { /* XXX: the only place we use non-REG_EXTENDED */
7170  ao2_t_ref(new_filter, -1, "failed to make regex");
7171  } else {
7172  if (is_blackfilter) {
7173  ao2_t_link(user->blackfilters, new_filter, "link new filter into black user container");
7174  } else {
7175  ao2_t_link(user->whitefilters, new_filter, "link new filter into white user container");
7176  }
7177  }
7178  }
7179  } else {
7180  ast_debug(1, "%s is an unknown option.\n", var->name);
7181  }
7182  }
7183  ast_free_ha(oldha);
7184  }
7185  ast_config_destroy(cfg);
7186 
7187  /* Perform cleanup - essentially prune out old users that no longer exist */
7188  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
7189  if (user->keep) { /* valid record. clear flag for the next round */
7190  user->keep = 0;
7191 
7192  /* Calculate A1 for Digest auth */
7193  snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
7194  ast_md5_hash(a1_hash,a1);
7195  ast_free(user->a1_hash);
7196  user->a1_hash = ast_strdup(a1_hash);
7197  continue;
7198  }
7199  /* We do not need to keep this user so take them out of the list */
7201  ast_debug(4, "Pruning user '%s'\n", user->username);
7202  manager_free_user(user);
7203  }
7205 
7207 
7208  if (webmanager_enabled && manager_enabled) {
7209  if (!webregged) {
7210  ast_http_uri_link(&rawmanuri);
7211  ast_http_uri_link(&manageruri);
7212  ast_http_uri_link(&managerxmluri);
7213 
7214  ast_http_uri_link(&arawmanuri);
7215  ast_http_uri_link(&amanageruri);
7216  ast_http_uri_link(&amanagerxmluri);
7217  webregged = 1;
7218  }
7219  } else {
7220  if (webregged) {
7221  ast_http_uri_unlink(&rawmanuri);
7222  ast_http_uri_unlink(&manageruri);
7223  ast_http_uri_unlink(&managerxmluri);
7224 
7225  ast_http_uri_unlink(&arawmanuri);
7226  ast_http_uri_unlink(&amanageruri);
7227  ast_http_uri_unlink(&amanagerxmluri);
7228  webregged = 0;
7229  }
7230  }
7231 
7232  if (newhttptimeout > 0) {
7233  httptimeout = newhttptimeout;
7234  }
7235 
7236  manager_event(EVENT_FLAG_SYSTEM, "Reload",
7237  "Module: Manager\r\n"
7238  "Status: %s\r\n"
7239  "Message: Manager reload Requested\r\n",
7240  manager_enabled ? "Enabled" : "Disabled");
7241 
7242  ast_tcptls_server_start(&ami_desc);
7243  if (tls_was_enabled && !ami_tls_cfg.enabled) {
7244  ast_tcptls_server_stop(&amis_desc);
7245  } else if (ast_ssl_setup(amis_desc.tls_cfg)) {
7246  ast_tcptls_server_start(&amis_desc);
7247  }
7248 
7249  return 0;
7250 }
7251 
7252 /* clear out every entry in the channelvar list */
7253 static void free_channelvars(void)
7254 {
7255  struct manager_channel_variable *var;
7256  AST_RWLIST_WRLOCK(&channelvars);
7257  while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) {
7258  ast_free(var);
7259  }
7260  AST_RWLIST_UNLOCK(&channelvars);
7261 }
7263 int init_manager(void)
7264 {
7265  return __init_manager(0);
7266 }
7268 int reload_manager(void)
7269 {
7270  return __init_manager(1);
7271 }
7273 int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
7274 {
7275  AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
7276 
7277  return 0;
7278 }
7280 int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
7281 {
7282  return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
7283 }
7285 struct ast_datastore *astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
7286 {
7287  struct ast_datastore *datastore = NULL;
7288 
7289  if (info == NULL)
7290  return NULL;
7291 
7292  AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
7293  if (datastore->info != info) {
7294  continue;
7295  }
7296 
7297  if (uid == NULL) {
7298  /* matched by type only */
7299  break;
7300  }
7301 
7302  if ((datastore->uid != NULL) && !strcasecmp(uid, datastore->uid)) {
7303  /* Matched by type AND uid */
7304  break;
7305  }
7306  }
7308 
7309  return datastore;
7310 }
static char user[512]
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:471
helper function for originate
Definition: manager.c:3806
const ast_string_field cnonce
Definition: utils.h:714
static int action_challenge(struct mansession *s, const struct message *m)
Definition: manager.c:3149
char exten[FEATURE_MAX_LEN]
Definition: features.h:69
static int get_input(struct mansession *s, char *output)
Definition: manager.c:4870
struct timeval tv
Definition: manager.c:882
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:81
static char * handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:1466
struct ao2_container * blackfilters
Definition: manager.c:1049
struct ast_datastore * astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a session.
Definition: manager.c:7284
FILE * f
Definition: manager.c:1015
static int action_command(struct mansession *s, const struct message *m)
Manager command &quot;command&quot; - execute CLI command.
Definition: manager.c:3732
char username[80]
Definition: manager.c:1040
int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
Definition: config.c:897
#define AST_RWLIST_NEXT
Definition: linkedlists.h:440
int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
If an extension hint exists, return non-zero.
Definition: pbx.c:5362
int ast_security_event_report(const struct ast_security_event_common *sec)
Report a security event.
struct ao2_container * whitefilters
Definition: manager.c:1048
#define ast_channel_lock(chan)
Definition: channel.h:2466
#define EVENT_FLAG_CDR
Definition: manager.h:81
char * pvtfile
Definition: tcptls.h:88
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
Definition: pbx.c:4177
static void close_mansession_file(struct mansession *s)
Definition: manager.c:5915
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
static const char * __astman_get_header(const struct message *m, char *var, int mode)
Return a matching header value.
Definition: manager.c:1823
char valid_amount
Definition: aoc.h:179
Main Channel structure associated with a channel.
Definition: channel.h:742
static int action_originate(struct mansession *s, const struct message *m)
Definition: manager.c:4124
An attempt at basic password authentication failed.
#define AST_CERTFILE
Definition: tcptls.h:68
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
static int check_blacklist(const char *cmd)
Definition: manager.c:3696
char * str
Subscriber phone number (Malloced)
Definition: channel.h:241
enum ast_security_event_type event_type
The security event sub-type.
struct ast_party_connected_line connected
Channel Connected Line ID information.
Definition: channel.h:811
static void astman_append_json(struct mansession *s, const char *str)
Definition: manager.c:2638
static int action_mailboxstatus(struct mansession *s, const struct message *m)
Definition: manager.c:4268
Security Event Reporting API.
static const int DEFAULT_DISPLAYCONNECTS
Definition: manager.c:891
uint32_t version
int ast_category_delete(struct ast_config *cfg, const char *category)
Definition: config.c:976
Asterisk locking-related definitions:
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:2068
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1715
Asterisk main include file. File version handling, generic pbx functions.
#define ao2_link(arg1, arg2)
Definition: astobj2.h:785
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
Definition: astobj2.c:470
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
Definition: config.c:625
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static void mansession_unlock(struct mansession *s)
Unlock the &#39;mansession&#39; structure.
Definition: manager.c:2157
int ast_realtime_enabled(void)
Check if there&#39;s any realtime engines loaded.
Definition: config.c:2601
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
char * strsep(char **str, const char *delims)
FYI FWIW, Successful authentication has occurred.
#define HSMC_FORMAT
const ast_string_field tech
Definition: manager.c:3821
const ast_string_field account
Definition: manager.c:3821
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition: loader.c:947
char username[80]
Definition: manager.c:980
int priority
Definition: channel.h:841
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Definition: linkedlists.h:332
void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text)
Send HTTP error message and close socket.
Definition: http.c:506
const char * expected_response
Response expected to be received.
const ast_string_field uniqueid
Definition: channel.h:787
void ast_manager_unregister_hook(struct manager_custom_hook *hook)
Delete a custom hook to be called when an event is fired.
Definition: manager.c:1100
void ast_tcptls_server_start(struct ast_tcptls_session_args *desc)
This is a generic (re)start routine for a TCP server, which does the socket/bind/listen and starts a ...
Definition: tcptls.c:964
#define ast_strdup(a)
Definition: astmm.h:109
int astman_verify_session_readpermissions(uint32_t ident, int perm)
Verify a session&#39;s read permissions against a permission mask.
Definition: manager.c:5633
static void astman_start_ack(struct mansession *s, const struct message *m)
Definition: manager.c:2140
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
Definition: ast_expr2.c:325
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Allocate and initialize an object.
Definition: astobj2.h:429
int ast_ssl_setup(struct ast_tls_config *cfg)
Set up an SSL server.
Definition: tcptls.c:850
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:422
int ast_aoc_add_unit_entry(struct ast_aoc_decoded *decoded, const unsigned int amount_is_present, const unsigned int amount, const unsigned int type_is_present, const unsigned int type)
Adds a unit entry into the list of units.
Definition: aoc.c:846
static struct ast_threadstorage userevent_buf
Definition: manager.c:2060
#define AST_RWLIST_INSERT_AFTER
Definition: linkedlists.h:687
static int action_reload(struct mansession *s, const struct message *m)
Send a reload event.
Definition: manager.c:4550
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
Asterisk version information.
struct ast_party_id id
Connected party ID.
Definition: channel.h:403
static int displayconnects
Definition: manager.c:899
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
static struct ast_variable * man_do_variable_value(struct ast_variable *head, const char *hdr_val)
Definition: manager.c:1874
static int action_userevent(struct mansession *s, const struct message *m)
Definition: manager.c:4448
static int webregged
Definition: manager.c:6612
int ast_careful_fwrite(FILE *f, int fd, const char *s, size_t len, int timeoutms)
Write data to a file stream with a timeout.
Definition: utils.c:1369
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
Registered hooks can call this function to invoke actions and they will receive responses through reg...
Definition: manager.c:1950
static void report_invalid_user(const struct mansession *s, const char *username)
Definition: manager.c:2194
#define ast_test_flag(p, flag)
Definition: utils.h:63
void ast_manager_register_hook(struct manager_custom_hook *hook)
Add a custom hook to be called when an event is fired.
Definition: manager.c:1092
struct mansession_session::mansession_datastores datastores
void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval offset)
Set when to hang a channel up.
Definition: channel.c:871
#define GET_HEADER_LAST_MATCH
Definition: manager.c:1807
void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm, const unsigned long nonce, const unsigned long opaque, int stale, const char *text)
Send http &quot;401 Unauthorized&quot; response and close socket.
Definition: http.c:468
struct ast_party_name name
Subscriber name.
Definition: channel.h:290
An attempt at challenge/response auth failed.
static void json_escape(char *out, const char *in)
Definition: manager.c:2618
static int action_ping(struct mansession *s, const struct message *m)
Definition: manager.c:2519
const char * ast_get_version(void)
Retrieve the Asterisk version string.
Definition: version.c:14
#define HSMCONN_FORMAT1
int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
executes a read operation on a function
Definition: pbx.c:4216
pthread_t waiting_thread
Definition: manager.c:975
#define HSMCONN_FORMAT2
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
int ast_apply_ha(const struct ast_ha *ha, const struct ast_sockaddr *addr)
Apply a set of rules to a given IP address.
Definition: acl.c:518
int reload_manager(void)
Called by Asterisk module functions and the CLI command.
Definition: manager.c:7267
#define ao2_iterator_next(arg1)
Definition: astobj2.h:1126
int ast_app_has_voicemail(const char *mailbox, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to &quot;INBOX&quot;. If folder is &quot;INBOX&quot;, includes the number of messages in the &quot;Urgent&quot; folder.
Definition: app.c:421
static int __init_manager(int reload)
Definition: manager.c:6839
#define ast_set_flag(p, flag)
Definition: utils.h:70
int ast_check_hangup_locked(struct ast_channel *chan)
Definition: channel.c:820
descriptor for a cli entry.
Definition: cli.h:165
static struct ast_manager_user * get_manager_by_name_locked(const char *name)
Definition: manager.c:1435
const int argc
Definition: cli.h:154
#define LOG_WARNING
Definition: logger.h:144
static struct permalias perms[]
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
Definition: time.h:56
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
Definition: http.c:544
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
int num
Definition: manager.c:1174
time_t authstart
Definition: manager.c:991
#define EVENT_FLAG_COMMAND
Definition: manager.h:75
int lineno
Definition: config.h:87
void ast_verbose(const char *fmt,...)
Definition: logger.c:1568
static int action_login(struct mansession *s, const struct message *m)
Definition: manager.c:3117
static int authenticate(struct mansession *s, const struct message *m)
Definition: manager.c:2422
#define VERBOSITY_ATLEAST(level)
Definition: logger.h:241
struct ast_tcptls_session_args * parent
Definition: tcptls.h:208
#define AST_FRAME_DTMF
Definition: frame.h:128
static char * handle_showmanagers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:1637
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
char * ast_xmldoc_build_description(const char *type, const char *name, const char *module)
Generate description documentation from XML.
Definition: xmldoc.c:1899
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1570
struct eventqent * last_ev
Definition: manager.c:989
const char * action
Definition: manager.h:140
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
error_type
Definition: manager.c:844
int ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
Inserts new category.
Definition: config.c:730
unsigned int type
Definition: aoc.h:182
struct ast_datastore_info * info
Definition: datastore.h:57
static int get_perm(const char *instr)
Definition: manager.c:1278
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
static int ast_manager_register_struct(struct manager_action *act)
Definition: manager.c:5414
int object
Definition: config.h:88
#define AST_LOG_WARNING
Definition: logger.h:149
ast_security_event_transport_type
Transport types.
#define var
Definition: ast_expr2f.c:606
void MD5Final(unsigned char digest[16], struct MD5Context *context)
Definition: md5.c:122
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
Definition: strings.h:792
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:100
Checking against an IP access control list failed.
static int action_createconfig(struct mansession *s, const struct message *m)
Definition: manager.c:2923
struct sockaddr_in sin
Definition: manager.c:970
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
Definition: http.c:574
#define EVENT_FLAG_CALL
Definition: manager.h:72
void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
Definition: config.c:380
Definition: cli.h:146
static int authtimeout
Definition: manager.c:907
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:176
static int auth_manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:6552
Structure for a data store type.
Definition: datastore.h:31
Configuration File Parser.
char * term_strip(char *outbuf, const char *inbuf, int maxout)
Definition: term.c:287
#define EVENT_FLAG_DTMF
Definition: manager.h:79
static void report_req_not_allowed(const struct mansession *s, const char *action)
Definition: manager.c:2298
char * str
Subscriber name (Malloced)
Definition: channel.h:214
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4447
int ast_config_text_file_save(const char *filename, const struct ast_config *cfg, const char *generator)
Definition: config.c:1977
static int manager_moduleload(struct mansession *s, const struct message *m)
Definition: manager.c:4703
static void report_session_limit(const struct mansession *s)
Definition: manager.c:2389
#define ao2_t_callback_data(arg1, arg2, arg3, arg4, arg5, arg6)
ao2_callback_data() is a generic function that applies cb_fn() to all objects in a container...
Definition: astobj2.h:942
struct ast_security_event_common common
Common security event descriptor elements.
static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
Definition: manager.c:2105
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
static int action_aocmessage(struct mansession *s, const struct message *m)
Definition: manager.c:3919
struct ast_ha * ha
Definition: manager.c:1042
static const int DEFAULT_AUTHTIMEOUT
Definition: manager.c:895
const char * response
Response received.
#define EVENT_FLAG_LOG
Definition: manager.h:73
#define EVENT_FLAG_TEST
Definition: manager.h:88
static int process_events(struct mansession *s)
Definition: manager.c:4424
static int action_getconfigjson(struct mansession *s, const struct message *m)
Definition: manager.c:2647
#define EVENT_FLAG_AOC
Definition: manager.h:87
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:235
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
arguments for the accepting thread
Definition: tcptls.h:123
static char * handle_manager_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager show settings.
Definition: manager.c:6646
#define ast_mutex_lock(a)
Definition: lock.h:155
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2135
struct ast_cdr * cdr
Definition: channel.h:766
static const int DEFAULT_MANAGERDEBUG
Definition: manager.c:897
#define ao2_unlock(a)
Definition: astobj2.h:497
ast_mutex_t lock
Definition: manager.c:1020
const char * ast_config_AST_RUN_USER
Definition: asterisk.c:271
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
Definition: astobj2.c:818
static const char * authority_to_str(int authority, struct ast_str **res)
Convert authority code to a list of options. Note that the EVENT_FLAG_ALL authority will always be re...
Definition: manager.c:1235
#define ast_str_alloca(init_len)
Definition: strings.h:608
const ast_string_field username
Definition: utils.h:714
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:90
struct ast_security_event_common common
Common security event descriptor elements.
#define MAXHOSTNAMELEN
Definition: network.h:69
Structure for a data store object.
Definition: datastore.h:54
A request was made that is not allowed.
ast_aoc_currency_multiplier
Defines the currency multiplier for an aoc message.
Definition: aoc.h:34
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: config.c:586
const char * str
Definition: app_jack.c:144
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
static void session_destructor(void *obj)
Definition: manager.c:1345
struct ast_security_event_common common
Common security event descriptor elements.
static const char *const contenttype[]
Definition: manager.c:5547
const char * ast_state2str(enum ast_channel_state)
Gives the string form of a given channel state.
Definition: channel.c:1007
#define MAX_BLACKLIST_CMD_LEN
Descriptor for a manager session, either on the AMI socket or over HTTP.
Definition: manager.c:927
static struct ast_tcptls_session_args ami_desc
Definition: manager.c:6624
static void report_failed_challenge_response(const struct mansession *s, const char *response, const char *expected_response)
Definition: manager.c:2358
#define MANAGER_EVENT_BUF_INITSIZE
Definition: manager.c:5266
int check_manager_enabled(void)
Check if AMI is enabled.
Definition: manager.c:1107
const char * data
Definition: channel.h:755
user descriptor, as read from the config file.
Definition: manager.c:1039
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
static int unauth_sessions
Definition: manager.c:914
Definitions to aid in the use of thread local storage.
static int action_sendtext(struct mansession *s, const struct message *m)
Definition: manager.c:3459
#define EVENT_FLAG_CC
Definition: manager.h:86
char * ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
Generate synopsis documentation from XML.
Definition: xmldoc.c:1894
int value
Definition: syslog.c:39
Generic support for tcp/tls servers in Asterisk.
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
int __ast_manager_event_multichan(int category, const char *event, int chancount, struct ast_channel **chans, const char *file, int line, const char *func, const char *contents,...)
Definition: manager.c:5268
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:841
#define AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION
Event descriptor version.
#define LOG_DEBUG
Definition: logger.h:122
struct ao2_container * blackfilters
Definition: manager.c:995
list of users found in the config file
ast_aoc_total_type
Definition: aoc.h:82
static int append_event(const char *str, int category)
Definition: manager.c:5214
static int action_atxfer(struct mansession *s, const struct message *m)
Definition: manager.c:3647
#define EVENT_FLAG_DIALPLAN
Definition: manager.h:82
static int rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:6515
#define AST_FILE_MODE
Definition: asterisk.h:36
static void process_output(struct mansession *s, struct ast_str **out, struct ast_variable *params, enum output_format format)
Definition: manager.c:5939
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
Socket address structure.
Definition: netsock2.h:63
char * ast_xmldoc_build_arguments(const char *type, const char *name, const char *module)
Generate the [arguments] tag based on type of node (&#39;application&#39;, &#39;function&#39; or &#39;agi&#39;) and name...
Definition: xmldoc.c:1761
static char cid_num[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:157
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: config.c:2499
static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
Definition: manager.c:3894
static struct manager_action * action_find(const char *name)
Definition: manager.c:1075
#define ast_verb(level,...)
Definition: logger.h:243
#define EVENT_FLAG_ORIGINATE
Definition: manager.h:83
static struct mansession_session * unref_mansession(struct mansession_session *s)
Unreference manager session object. If no more references, then go ahead and delete it...
Definition: manager.c:1330
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
#define AST_SEC_EVT(e)
const char * appl
Definition: channel.h:754
void MD5Init(struct MD5Context *context)
Definition: md5.c:59
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
Definition: lock.h:603
static void manager_free_user(struct ast_manager_user *user)
Definition: manager.c:6735
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:65
static int auth_mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:6563
static char * handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager list eventq.
Definition: manager.c:1748
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Definition: pbx.c:10475
static const int DEFAULT_BROKENEVENTSACTION
Definition: manager.c:894
const char * uid
Definition: datastore.h:55
static int process_message(struct mansession *s, const struct message *m)
Definition: manager.c:4762
int ast_module_check(const char *name)
Check if module with the name given is loaded.
Definition: loader.c:1255
static struct ast_http_uri arawmanuri
Definition: manager.c:6585
String fields in structures.
Utility functions.
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
Definition: netsock2.h:106
static int httptimeout
Definition: manager.c:902
#define ao2_t_link(arg1, arg2, arg3)
Add an object to a container.
Definition: astobj2.h:784
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
Definition: channel.c:1808
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:1860
static struct mansession_session * find_session(uint32_t ident, int incinuse)
Definition: manager.c:5558
int option_maxfiles
Definition: asterisk.c:185
enum ast_doc_src docsrc
Definition: manager.h:153
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category structure.
Definition: config.c:673
#define TEST_STRING
const char * ast_config_AST_SYSTEM_NAME
Definition: asterisk.c:273
static int mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:6504
#define CONFIG_STATUS_FILEMISSING
Definition: config.h:50
int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan)
set the charging accociation number for an AOC-E message
Definition: aoc.c:925
static int action_events(struct mansession *s, const struct message *m)
Definition: manager.c:3067
time_t sessiontimeout
Definition: manager.c:979
static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
Definition: manager.c:5240
void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, const int fd, unsigned int static_content)
Generic function for sending http/1.1 response.
Definition: http.c:393
static struct ast_threadstorage manager_event_buf
Definition: manager.c:5265
internal representation of acl entries In principle user applications would have no need for this...
Definition: acl.h:48
const char * ast_config_AST_RUN_GROUP
Definition: asterisk.c:272
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
An attempt at basic password auth failed.
struct ast_party_id id
Caller party ID.
Definition: channel.h:370
static int action_getconfig(struct mansession *s, const struct message *m)
Definition: manager.c:2537
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name)
Retrieve a category if it exists.
Definition: config.c:709
Support for Private Asterisk HTTP Servers.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
static void destroy_fast_originate_helper(struct fast_originate_helper *doomed)
Definition: manager.c:3833
static int check_manager_session_inuse(const char *name)
Definition: manager.c:1418
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:703
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
static const int DEFAULT_ENABLED
Definition: manager.c:889
const ast_string_field uri
Definition: utils.h:714
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
struct ao2_container * whitefilters
Definition: manager.c:994
const char * request_type
Request type that was made.
struct ast_variable * ast_variables_reverse(struct ast_variable *var)
Reverse a variable list.
Definition: config.c:562
int astman_is_authed(uint32_t ident)
Determinie if a manager session ident is authenticated.
Definition: manager.c:5617
static int manager_modulecheck(struct mansession *s, const struct message *m)
Definition: manager.c:4660
void ast_category_destroy(struct ast_category *cat)
Definition: config.c:762
Generic Advice of Charge encode and decode routines.
static int blackfilter_cmp_fn(void *obj, void *arg, void *data, int flags)
Definition: manager.c:4379
const char * value
Definition: config.h:79
unsigned int isfunc
Definition: manager.c:1027
static void report_inval_password(const struct mansession *s, const char *username)
Definition: manager.c:2246
void * ast_tcptls_server_root(void *)
Definition: tcptls.c:693
static const char app[]
Definition: app_adsiprog.c:49
General Asterisk PBX channel definitions.
static const int DEFAULT_TIMESTAMPEVENTS
Definition: manager.c:892
Asterisk file paths, configured in asterisk.conf.
const char * src
Definition: frame.h:158
#define ast_sockaddr_from_sin(addr, sin)
Converts a struct sockaddr_in to a struct ast_sockaddr.
Definition: netsock2.h:642
static void * session_do(void *data)
The body of the individual manager session. Call get_input() to read one line at a time (or be woken ...
Definition: manager.c:5073
const ast_string_field response
Definition: utils.h:714
const int fd
Definition: cli.h:153
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:249
#define ast_manager_register_xml(a, b, c)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:172
#define AST_PTHREADT_NULL
Definition: lock.h:65
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
const int n
Definition: cli.h:159
struct ast_aoc_encoded * ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
encodes a decoded aoc structure so it can be passed on the wire
Definition: aoc.c:519
Access Control of various sorts.
Request received with bad formatting.
#define ASTMAN_APPEND_BUF_INITSIZE
initial allocated size for the astman_append_buf
Definition: manager.c:2063
Request denied because of a session limit.
unsigned int registered
TRUE if the AMI action is registered and the callback can be called.
Definition: manager.h:162
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:155
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:220
static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
Definition: manager.c:2696
static int action_coreshowchannels(struct mansession *s, const struct message *m)
Manager command &quot;CoreShowChannels&quot; - List currently defined channels and some information about them...
Definition: manager.c:4577
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:83
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: asterisk.c:998
long int ast_random(void)
Definition: utils.c:1640
#define GET_HEADER_SKIP_EMPTY
Definition: manager.c:1808
#define ao2_lock(a)
Definition: astobj2.h:488
mansession_message_parsing
Definition: manager.c:1002
#define AST_SECURITY_EVENT_FAILED_ACL_VERSION
Event descriptor version.
enum mansession_message_parsing parsing
Definition: manager.c:1017
static char * handle_showmanager(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:1573
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:565
struct timeval ast_lastreloadtime
Definition: asterisk.c:219
static int action_logoff(struct mansession *s, const struct message *m)
Definition: manager.c:3111
static int auth_rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:6574
char * a1_hash
Definition: manager.c:1050
const ast_string_field cid_num
Definition: manager.c:3821
static struct mansession_session * find_session_by_nonce(const char *username, unsigned long nonce, int *stale)
Definition: manager.c:5591
int ast_manager_register2(const char *action, int authority, int(*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
Register a manager command with the manager interface.
Definition: manager.c:5469
const ast_string_field exten
Definition: manager.c:3821
static struct ast_http_uri managerxmluri
Definition: manager.c:6542
static struct ast_http_uri manageruri
Definition: manager.c:6534
A set of macros to manage forward-linked lists.
const char * name
Definition: config.h:77
unsigned int active_count
Definition: manager.h:164
ast_cli_command
calling arguments for new-style handlers.
Definition: cli.h:145
struct ast_security_event_common common
Common security event descriptor elements.
struct timeval sessionstart_tv
Definition: manager.c:978
static int manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:6493
#define EVENT_FLAG_AGI
Definition: manager.h:84
struct ast_security_event_common common
Common security event descriptor elements.
static struct channel_usage channels
struct ast_channel * _bridge
Definition: channel.h:748
static struct ast_tls_config ami_tls_cfg
Definition: manager.c:6623
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
struct ast_variable * vars
Definition: manager.c:3823
ast_aoc_charge_type
Definition: aoc.h:69
static struct eventqent * advance_event(struct eventqent *e)
Definition: manager.c:1793
#define MSG_MOREDATA
send a response with an optional message, and terminate it with an empty line. m is used only to grab...
Definition: manager.c:2104
static int authlimit
Definition: manager.c:908
static int timestampevents
Definition: manager.c:901
void ast_tcptls_stream_set_exclusive_input(struct ast_tcptls_stream *stream, int exclusive_input)
Set the TCP/TLS stream I/O if it can exclusively depend upon the set timeouts.
Definition: tcptls.c:107
static struct ast_tcptls_session_args amis_desc
Definition: manager.c:6635
struct ast_tcptls_stream * stream_cookie
Definition: tcptls.h:218
static void manager_shutdown(void)
Definition: manager.c:6750
Core PBX routines and definitions.
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel&#39;s frame queue.
Definition: channel.c:1558
list of actions registered
Definition: manager.c:1058
void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
Send response in manager transaction.
Definition: manager.c:2125
#define AMI_VERSION
Definition: manager.h:57
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:542
int ast_app_inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Determine number of urgent/new/old messages in a mailbox.
Definition: app.c:455
int usecount
Definition: manager.c:879
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Definition: term.c:184
const char *const * argv
Definition: cli.h:155
static int action_listcommands(struct mansession *s, const struct message *m)
Definition: manager.c:3048
void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len)
Definition: md5.c:74
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION
Event descriptor version.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
static int reload(void)
Definition: app_amd.c:497
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:451
#define GET_HEADER_FIRST_MATCH
Definition: manager.c:1806
static enum ast_security_event_transport_type mansession_get_transport(const struct mansession *s)
Definition: manager.c:2179
struct ast_tcptls_session_instance * tcptls_session
Definition: manager.c:1014
int ast_aoc_set_billing_id(struct ast_aoc_decoded *decoded, const enum ast_aoc_billing_id id)
set the billing id for a AOC-D or AST_AOC_E message
Definition: aoc.c:893
ast_aoc_type
Definition: aoc.h:62
static struct ast_threadstorage astman_append_buf
Definition: manager.c:2059
static const char * user_authority_to_str(int authority, struct ast_str **res)
Convert authority code to a list of options for a user. This will only display those authority codes ...
Definition: manager.c:1213
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
int ast_pbx_outgoing_exten(const char *type, format_t format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
Definition: pbx.c:9375
#define EVENT_FLAG_CONFIG
Definition: manager.h:78
static int strings_to_mask(const char *string)
Definition: manager.c:1299
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
static char * handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager list commands.
Definition: manager.c:1680
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
int64_t format_t
Definition: frame_defs.h:32
static int action_mailboxcount(struct mansession *s, const struct message *m)
Definition: manager.c:4285
static int set_eventmask(struct mansession *s, const char *eventmask)
Rather than braindead on,off this now can also accept a specific int mask value or a &#39;...
Definition: manager.c:2166
static struct @350 args
static int manager_debug
Definition: manager.c:906
#define CLI_SHOWUSAGE
Definition: cli.h:44
const char * ast_config_AST_CONFIG_DIR
Definition: asterisk.c:256
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
Retrieve the value of a builtin variable or variable from the channel variable stack.
Definition: pbx.c:3434
double option_maxload
Definition: asterisk.c:183
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition: config.c:483
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
Definition: pbx.c:5405
static struct ast_threadstorage manager_event_funcbuf
Definition: manager.c:5238
#define EVENT_FLAG_USER
Definition: manager.h:77
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
enum ast_channel_state _state
Definition: channel.h:839
struct ast_channel * ast_bridged_channel(struct ast_channel *chan)
Find bridged channel.
Definition: channel.c:7160
const ast_string_field appdata
Definition: manager.c:3821
#define FORMAT
struct ast_variable * astman_get_variables(const struct message *m)
Get a linked list of the Variable: headers.
Definition: manager.c:1918
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode)
Unload a module.
Definition: loader.c:551
variable_orders
Definition: manager.h:251
static void report_failed_acl(const struct mansession *s, const char *username)
Definition: manager.c:2220
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:909
const char * description
Definition: http.h:93
static void xml_translate(struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
Convert the input into XML or HTML. The input is supposed to be a sequence of lines of the form Name:...
Definition: manager.c:5798
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:210
const ast_string_field name
Definition: channel.h:787
const char * words[AST_MAX_CMD_LEN]
Definition: manager.c:929
time_t noncetime
Definition: manager.c:993
An attempt at challenge/response authentication failed.
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:97
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define EVENT_FLAG_AGENT
Definition: manager.h:76
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
static int action_waitevent(struct mansession *s, const struct message *m)
Definition: manager.c:2941
const ast_string_field nc
Definition: utils.h:714
#define LOG_NOTICE
Definition: logger.h:133
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
Definition: strings.h:122
static int action_timeout(struct mansession *s, const struct message *m)
Definition: manager.c:4331
static char * synopsis
Definition: func_enum.c:156
int ast_softhangup_nolock(struct ast_channel *chan, int reason)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2733
static const int DEFAULT_WEBENABLED
Definition: manager.c:890
struct ast_bridge * bridge
Definition: channel.h:865
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:696
int write_error
Definition: manager.c:1018
static int action_getvar(struct mansession *s, const struct message *m)
Definition: manager.c:3243
static int match_filter(struct mansession *s, char *eventdata)
Definition: manager.c:4394
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
#define ast_channel_unlock(chan)
Definition: channel.h:2467
static void event_filter_destructor(void *obj)
Definition: manager.c:1339
struct timeval start
Definition: cdr.h:100
int errno
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
static const char name[]
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
Definition: utils.c:564
int ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:721
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
int astman_verify_session_writepermissions(uint32_t ident, int perm)
Verify a session&#39;s write permissions against a permission mask.
Definition: manager.c:5659
#define AST_CHANNEL_NAME
Definition: channel.h:137
const ast_string_field cid_name
Definition: manager.c:3821
static void report_auth_success(const struct mansession *s)
Definition: manager.c:2272
int ast_aoc_set_total_type(struct ast_aoc_decoded *decoded, const enum ast_aoc_total_type type)
Sets the type of total for a AOC-D message.
Definition: aoc.c:776
unsigned int flags
Definition: frame.h:166
int(* func)(struct mansession *s, const struct message *m)
Definition: manager.h:151
#define EVENT_FLAG_HOOKRESPONSE
Definition: manager.h:85
static struct ast_format f[]
Definition: format_g726.c:181
const char * word
Definition: cli.h:157
static int broken_events_action
Definition: manager.c:903
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:182
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:829
int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
Add a datastore to a session.
Definition: manager.c:7272
unsigned long nc
Definition: manager.c:997
struct ast_security_event_common common
Common security event descriptor elements.
uint32_t managerid
Definition: manager.c:976
const char * ast_get_http_method(enum ast_http_method method) attribute_pure
Return http method name string.
Definition: http.c:153
static void action_destroy(void *obj)
Definition: manager.c:5457
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2351
int ast_str_append_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Append to a dynamic string using a va_list.
Definition: strings.h:809
char * ast_xmldoc_printable(const char *bwinput, int withcolors)
Colorize and put delimiters (instead of tags) to the xmldoc output.
Definition: xmldoc.c:315
char valid_type
Definition: aoc.h:181
char inbuf[1025]
Definition: manager.c:985
int ast_variable_update(struct ast_category *category, const char *variable, const char *value, const char *match, unsigned int object)
Update variable value within a config.
Definition: config.c:942
static int action_status(struct mansession *s, const struct message *m)
Manager &quot;status&quot; command to show channels.
Definition: manager.c:3297
static void purge_old_stuff(void *data)
cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most ...
Definition: manager.c:6617
#define DEFAULT_MANAGER_TLS_PORT
Definition: manager.h:59
static int send_string(struct mansession *s, char *string)
Definition: manager.c:2029
structure to hold users read from users.conf
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
Definition: astobj2.c:833
static int action_coresettings(struct mansession *s, const struct message *m)
Show PBX core settings information.
Definition: manager.c:4468
int check_webmanager_enabled(void)
Check if AMI/HTTP is enabled.
Definition: manager.c:1112
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:367
Structure used to handle boolean flags.
Definition: utils.h:200
static size_t get_params(va_list ap, const char ***params_ptr, const char ***vals_ptr, int warn)
Helper function to parse a va_list object into 2 dynamic arrays of strings, parameters and values...
char * ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
Get the syntax for a specified application or function.
Definition: xmldoc.c:1156
char * ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
Parse the &lt;see-also&gt; node content.
Definition: xmldoc.c:1461
int category
Definition: manager.c:880
char * certfile
Definition: tcptls.h:87
#define ast_clear_flag(p, flag)
Definition: utils.h:77
const ast_string_field data
Definition: manager.c:3821
Definition: md5.h:26
const ast_string_field context
Definition: manager.c:3821
static char cid_name[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:158
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:414
#define DEFAULT_REALM
Definition: manager.c:911
const char * usage
Definition: cli.h:171
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
Invalid account ID specified (invalid username, for example)
struct ast_aoc_decoded * ast_aoc_create(const enum ast_aoc_type msg_type, const enum ast_aoc_charge_type charge_type, const enum ast_aoc_request requests)
creates a ast_aoc_decode object of a specific message type
Definition: aoc.c:145
void ast_free_ha(struct ast_ha *ha)
Free a list of HAs.
Definition: acl.c:223
struct timeval ast_startuptime
Definition: asterisk.c:218
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:436
#define EVENT_FLAG_REPORTING
Definition: manager.h:80
#define CLI_SUCCESS
Definition: cli.h:43
static void parsing(int size, unsigned char *buf, struct unistimsession *pte, struct sockaddr_in *addr_from)
const ast_string_field nonce
Definition: utils.h:714
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
struct ast_security_event_common common
Common security event descriptor elements.
static struct ast_http_uri amanageruri
Definition: manager.c:6594
struct ast_security_event_common common
Common security event descriptor elements.
#define AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION
Event descriptor version.
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:726
int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
Remove a datastore from a session.
Definition: manager.c:7279
static void load_channelvars(struct ast_variable *var)
Definition: manager.c:6705
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:666
static struct ast_cli_entry cli_manager[]
Definition: manager.c:6685
struct ast_flags ast_options
Definition: asterisk.c:178
struct ast_variable * astman_get_variables_order(const struct message *m, enum variable_orders order)
Get a linked list of the Variable: headers with order specified.
Definition: manager.c:1923
#define DEFAULT_MANAGER_PORT
Definition: manager.h:58
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
Definition: manager.c:5759
static int do_message(struct mansession *s)
Definition: manager.c:4985
static int chancount
Definition: channel.c:102
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1053
unsigned int seq
Definition: manager.c:881
static struct eventqent * grab_last(void)
Definition: manager.c:1121
Standard Command Line Interface.
static struct ast_http_uri amanagerxmluri
Definition: manager.c:6603
static int manager_enabled
Definition: manager.c:904
#define ast_calloc(a, b)
Definition: astmm.h:82
#define ROW_FMT
list of hooks registered
Definition: manager.c:1061
manager_hook_t helper
Definition: manager.h:101
static int action_updateconfig(struct mansession *s, const struct message *m)
Definition: manager.c:2845
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
static int function_capable_string_allowed_with_auths(const char *evaluating, int writepermlist)
Checks to see if a string which can be used to evaluate functions should be rejected.
Definition: manager.c:1199
#define ao2_container_alloc(arg1, arg2, arg3)
Definition: astobj2.h:734
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
Uses hint and devicestate callback to get the state of an extension.
Definition: pbx.c:4914
static int ast_instring(const char *bigstr, const char *smallstr, const char delim)
Definition: manager.c:1259
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
static char * handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager reload.
Definition: manager.c:1774
static void mansession_lock(struct mansession *s)
Lock the &#39;mansession&#39; structure.
Definition: manager.c:2151
char * varname
Definition: manager.c:5748
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is &quot;false&quot;...
Definition: utils.c:1550
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
const int pos
Definition: cli.h:158
static int auth_http_callback(struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, struct sockaddr_in *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:6180
#define EVENT_FLAG_VERBOSE
Definition: manager.h:74
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1649
Definition of a URI handler.
Definition: http.h:91
int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Set the channel to next execute the specified dialplan location.
Definition: pbx.c:8731
ast_aoc_billing_id
Defines the billing id options for an aoc message.
Definition: aoc.h:49
static void * fast_originate(void *data)
Definition: manager.c:3840
static void free_channelvars(void)
Definition: manager.c:7252
char challenge[10]
Definition: manager.c:981
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static int action_hangup(struct mansession *s, const struct message *m)
Definition: manager.c:3167
const ast_string_field app
Definition: manager.c:3821
static void purge_events(void)
Definition: manager.c:1141
struct ast_variable * ast_http_get_post_vars(struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlenco...
Definition: http.c:624
static int whitefilter_cmp_fn(void *obj, void *arg, void *data, int flags)
Definition: manager.c:4365
int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value)
Used to parse conf files containing tls/ssl options.
Definition: tcptls.c:1072
const ast_string_field accountcode
Definition: channel.h:787
Data structure associated with a single frame of data.
Definition: frame.h:142
int hangupcause
Definition: channel.h:849
#define ast_manager_event_multichan(category, event, nchans, chans, contents,...)
Definition: manager.h:226
int init_manager(void)
Called by Asterisk initialization.
Definition: manager.c:7262
const char * headers[AST_MAX_MANHEADERS]
Definition: manager.h:135
static void session_destroy(struct mansession_session *s)
Definition: manager.c:1411
int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic)
Parse digest authorization header.
Definition: utils.c:2216
const ast_string_field idtext
Definition: manager.c:3821
Definition: aoc.h:66
static char global_realm[MAXHOSTNAMELEN]
Definition: manager.c:912
#define AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION
Event descriptor version.
struct mansession_session * session
Definition: manager.c:1013
#define AST_RWLIST_REMOVE
Definition: linkedlists.h:870
void ast_tcptls_stream_set_timeout_sequence(struct ast_tcptls_stream *stream, struct timeval start, int timeout)
Set the TCP/TLS stream I/O sequence timeout timer.
Definition: tcptls.c:99
static void handle_parse_error(struct mansession *s, struct message *m, char *error)
Definition: manager.c:4968
struct ast_ha * ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error)
Add a new rule to a list of HAs.
Definition: acl.c:399
Handy terminal functions for vt* terms.
static int action_extensionstate(struct mansession *s, const struct message *m)
Definition: manager.c:4306
int ast_aoc_set_association_id(struct ast_aoc_decoded *decoded, const int id)
set the charging association id for an AST_AOC_E message
Definition: aoc.c:909
#define ast_sockaddr_to_sin(addr, sin)
Converts a struct ast_sockaddr to a struct sockaddr_in.
Definition: netsock2.h:629
int ast_wait_for_input(int fd, int ms)
Definition: utils.c:1255
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
#define AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION
Event descriptor version.
struct ast_variable * next
Definition: config.h:82
void ast_tcptls_server_stop(struct ast_tcptls_session_args *desc)
Shutdown a running server if there is one.
Definition: tcptls.c:1058
struct ast_tls_config * tls_cfg
Definition: tcptls.h:128
static int manager_state_cb(char *context, char *exten, int state, void *data)
Definition: manager.c:5404
Invalid formatting of request.
static struct mansession_session * build_mansession(struct sockaddr_in sin)
Allocate manager session structure and add it to the list of sessions.
Definition: manager.c:1375
static int generic_http_callback(struct ast_tcptls_session_instance *ser, enum ast_http_method method, enum output_format format, struct sockaddr_in *remote_address, const char *uri, struct ast_variable *get_params, struct ast_variable *headers)
Definition: manager.c:5969
#define ast_mutex_init(pmutex)
Definition: lock.h:152
static int allowmultiplelogin
Definition: manager.c:900
#define AST_CLI_YESNO(x)
return Yes or No depending on the argument. This is used in many places in CLI command, having a function to generate this helps maintaining a consistent output (and possibly emitting the output in other languages, at some point).
Definition: cli.h:65
int check_cdr_enabled(void)
Return TRUE if CDR subsystem is enabled.
Definition: cdr.c:120
static const int DEFAULT_AUTHLIMIT
Definition: manager.c:896
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
const char * uri
Definition: http.h:94
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:229
struct ast_sockaddr local_address
Definition: tcptls.h:124
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
void ast_category_append(struct ast_config *config, struct ast_category *cat)
Definition: config.c:719
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
static int action_corestatus(struct mansession *s, const struct message *m)
Show PBX core status information.
Definition: manager.c:4510
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
ast_http_method
HTTP Request methods known by Asterisk.
Definition: http.h:56
#define AST_RWLIST_FIRST
Definition: linkedlists.h:422
#define ast_mutex_destroy(a)
Definition: lock.h:154
Definition: aoc.h:178
static int webmanager_enabled
Definition: manager.c:905
int ast_pbx_outgoing_app(const char *type, format_t format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
Definition: pbx.c:9544
void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
Definition: config.c:496
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1701
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Registers a state change callback.
Definition: pbx.c:5135
const char * ast_file_version_find(const char *file)
Find version for given module name.
Definition: asterisk.c:376
time_t sessionstart
Definition: manager.c:977
struct ast_channel * ast_dummy_channel_alloc(void)
Create a fake channel structure.
Definition: channel.c:1391
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()&#39;s, .&#39;s, and -&#39;s...
Definition: callerid.c:948
struct manager_custom_hook * hook
Definition: manager.c:1019
void ast_category_rename(struct ast_category *cat, const char *name)
Definition: config.c:867
void ast_md5_hash(char *output, const char *input)
Produces MD5 hash based on input string.
Definition: utils.c:245
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:219
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1803
void ast_tcptls_stream_set_timeout_disable(struct ast_tcptls_stream *stream)
Disable the TCP/TLS stream timeout timer.
Definition: tcptls.c:84
#define ast_malloc(a)
Definition: astmm.h:91
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:2130
Asterisk module definitions.
output_format
Definition: manager.c:5541
const char * label
Definition: manager.c:1175
char * strcasestr(const char *, const char *)
static int manager_displayconnects(struct mansession_session *session)
Get displayconnects config option.
Definition: manager.c:1452
unsigned int hdrcount
Definition: manager.h:134
MD5 digest functions.
static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
Definition: manager.c:5690
#define FORMAT2
struct manager_channel_variable * next
Definition: manager.c:1026
#define AST_RWLIST_LAST
Definition: linkedlists.h:430
static void manager_set_defaults(void)
Definition: manager.c:6810
static snd_pcm_format_t format
Definition: chan_alsa.c:93
union ast_frame::@172 data
int option_maxcalls
Definition: asterisk.c:184
static struct @286 command_blacklist[]
int ast_active_channels(void)
returns number of active/allocated channels
Definition: channel.c:848
static char * handle_mandebug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: manager.c:1548
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2069
unsigned int amount
Definition: aoc.h:180
static int mansession_cmp_fn(void *obj, void *arg, int flags)
Definition: manager.c:1404
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:253
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:247
static int action_redirect(struct mansession *s, const struct message *m)
action_redirect: The redirect manager command
Definition: manager.c:3494
#define ao2_unlink(arg1, arg2)
Definition: astobj2.h:817
unsigned long oldnonce
Definition: manager.c:996
#define AST_MAX_CMD_LEN
Definition: cli.h:47
char * cipher
Definition: tcptls.h:89
static struct sockaddr_in * mansession_encode_sin_local(const struct mansession *s, struct sockaddr_in *sin_local)
Definition: manager.c:2185
int inet_aton(const char *cp, struct in_addr *pin)
void * data
Definition: http.h:102
static int action_listcategories(struct mansession *s, const struct message *m)
Definition: manager.c:2581
static const int DEFAULT_HTTPTIMEOUT
Definition: manager.c:893
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:602
#define AST_SECURITY_EVENT_SESSION_LIMIT_VERSION
Event descriptor version.
int ast_category_empty(struct ast_config *cfg, const char *category)
Removes and destroys all variables within a category.
Definition: config.c:1021
static struct ast_http_uri rawmanuri
Definition: manager.c:6526
char exten[AST_MAX_EXTENSION]
Definition: channel.h:869
Request denied because it&#39;s not allowed.
struct ast_call_feature * ast_find_call_feature(const char *name)
look for a call feature entry by its sname
Definition: features.c:3160
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
Definition: config.c:278
const char * request_type
Request type that was made.
Structure for mutex and tracking information.
Definition: lock.h:121
static char * handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command manager list connected.
Definition: manager.c:1709
static void report_req_bad_format(const struct mansession *s, const char *action)
Definition: manager.c:2328
static int variable_count_hash_fn(const void *vvc, const int flags)
Definition: manager.c:5752
static char mailbox[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:197
int ast_parse_allow_disallow(struct ast_codec_pref *pref, format_t *mask, const char *list, int allowing)
Parse an &quot;allow&quot; or &quot;deny&quot; line in a channel or device configuration and update the capabilities mask...
Definition: frame.c:1272
static void purge_sessions(int n_max)
remove at most n_max stale session from the list.
Definition: manager.c:5181
int ast_manager_unregister(char *action)
Unregister a registered manager command.
Definition: manager.c:5355
jack_status_t status
Definition: app_jack.c:143
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
#define COLOR_MAGENTA
Definition: term.h:57
Definition: aoc.h:65
struct ast_variable * ast_http_get_cookies(struct ast_variable *headers)
Get cookie from Request headers.
Definition: http.c:862
#define AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION
Event descriptor version.
#define CONFIG_STATUS_FILEUNCHANGED
Definition: config.h:51
#define ast_mutex_unlock(a)
Definition: lock.h:156
static char * manager_channelvars
Definition: manager.c:909
struct ast_pbx * pbx
Definition: channel.h:761
static int action_setvar(struct mansession *s, const struct message *m)
Definition: manager.c:3210
int ast_sendtext(struct ast_channel *chan, const char *text)
Sends text to a channel.
Definition: channel.c:4687
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:949
struct ast_sockaddr remote_address
Definition: tcptls.h:207
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
Definition: callerid.c:1009
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
int ast_aoc_set_currency_info(struct ast_aoc_decoded *decoded, const unsigned int amount, const enum ast_aoc_currency_multiplier multiplier, const char *name)
Sets the currency values for a AOC-D or AOC-E message.
Definition: aoc.c:788
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager list transaction.
Definition: manager.c:2145
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292
int enabled
Definition: tcptls.h:86