enabled=yes
in the [general]
section in
manager.conf
.iptables
, ipfw
, an external
firewall, or an SSH tunnel!admin
at the
end of the file:[admin] secret = secret5 deny = 0.0.0.0/0.0.0.0 permit = 127.0.0.1/255.255.255.255 read = all,system,call,log,verbose,command,agent,user,config write = all,system,call,log,verbose,command,agent,user,configThe options following
read
and write
define the
allowed command types for this user.[40]command
rights level means the user can stop Asterisk. As
of Asterisk 1.4, it is even possible to make dialplan changes through
the AMI - which also means it is possible to run shell commands with
root privileges using System()
!telnet
[41]:$
telnet 127.0.0.1 5038
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Asterisk Call Manager/1.0
Now you can enter commands, usually
consisting of multiple lines, by hand. For example:Action: Login ActionID: 1 Username: admin Secret: secret5
Response: Success ActionID: 1 Message: Authentication accepted
Action
packets, the server answers with
Response
or can send Event
packets. Otherwise
the order of the lines in a packet is irrelevant. Lines are terminated
with a CR LF[43]combination. The entire packet is terminated with an
additional CR LF combination. An AMI client normally sends a randomized
but unique ActionID
with every Action
,[44] which the server uses in its response for the purpose of
managing overlapping packet streams.Event
packets, which can
refer to any events; ther are also events that occur as the result of a
client-initiated Action
. In this case, the server sends
Response: Follows
followed by the events (which will contain
the ActionID
of the initiating action) and a closing event
(usually actionname
Complete).Events: off
in the authentication
packet. Once set, the AMI sends only responses to actions initiated by the
client.manager show commands
(or show manager
commands
), while information about a specific command can be
obtained with manager show command
command
(or show manager
command command
):mos-eisley*CLI> show manager commands Action Privilege Synopsis ------ --------- -------- AbsoluteTimeout call,all Set Absolute Timeout AgentCallbackLo agent,all Sets an agent as logged in by callback AgentLogoff agent,all Sets an agent as no longer logged in Agents agent,all Lists agents and their status ChangeMonitor call,all Change monitoring filename of a channel Command command,all Execute Asterisk CLI Command DBGet system,all Get DB Entry DBPut system,all Put DB Entry Events <none> Control Event Flow ExtensionState call,all Check Extension Status GetConfig config,all Retrieve configuration Getvar call,all Gets a Channel Variable Hangup call,all Hangup Channel IAXnetstats <none> Show IAX Netstats IAXpeers <none> List IAX Peers ListCommands <none> List available manager commands Logoff <none> Logoff Manager MailboxCount call,all Check Mailbox Message Count MailboxStatus call,all Check Mailbox Monitor call,all Monitor a channel Originate call,all Originate Call Park call,all Park a channel ParkedCalls <none> List parked calls PauseMonitor call,all Pause monitoring of a channel Ping <none> Keepalive command PlayDTMF call,all Play DTMF signal on a specific channel. QueueAdd agent,all Add interface to queue. QueuePause agent,all Makes a queue member temporarily unavailable QueueRemove agent,all Remove interface from queue. Queues <none> Queues QueueStatus <none> Queue Status Redirect call,all Redirect (transfer) a call SetCDRUserField call,all Set the CDR UserField Setvar call,all Set Channel Variable SIPpeers system,all List SIP peers (text format) SIPshowpeer system,all Show SIP peer (text format) Status call,all Lists channel status StopMonitor call,all Stop monitoring a channel UnpauseMonitor call,all Unpause monitoring of a channel UpdateConfig config,all Update basic configuration UserEvent user,all Send an arbitrary event WaitEvent <none> Wait for an event to occurThese commands are almost always a direct translation of dialplan applications, except in the case of
Originate
, used to initiate an outgoing
call, and Command
, which executes a command directly on the
CLI. Because our test user admin
has all the rights levels
(see above), he can execute all commands. The following example shows how
we learn how a command is used:mos-eisley*CLI> manager show command Command Action: Command Synopsis: Execute Asterisk CLI Command Privilege: command,a Description: Run a CLI command. Variables: (Names marked with * are required) *Command: Asterisk CLI command to run ActionID: Optional Action id for message matching.
expect
script.#!/usr/bin/expect # # Usage: ./vmcount.exp 1234@default # The user account from manager.conf: set username "admin" set secret "secret5" set host "127.0.0.1" set port "5038" if {[llength $argv] != 1} { send_user "Error: You must specify a mailbox!\n" exit 1 } # First argument is the mailbox: set mailbox [lindex $argv 0] send_user "Mailbox: $mailbox\n" # Mute output to stdout: log_user 0 # Open connection to AMI: spawn telnet $host $port # Just in case telnet aborts because it cannot connect: expect_before eof { send_user "Failed to connect.\n" exit 1 } # Wait for the text "Manager"; once received, send a login packet: # expect "Manager" { send_user "Connected.\n" send "Action: Login\nUsername: $username\nSecret: $secret\n\n" # Please note that telnet automatically converts line feeds # (\n) to CR LF (\r\n) - so you must not write \r\n here. } # Login successful?: # expect { -re "Response:\\s*Error" { send_user "Login failed.\n" exit 1 } -re "Response:\\s*Success" { send_user "Logged in.\n" # Query the number of messages in the mailbox: send "Action: MailboxCount\nMailbox: $mailbox\n\n" } } expect { -re "Response:\\s*Error" { send_user "Query of mailbox failed.\n" exit 1 } -re "Response:\\s*Success" {} } expect { -re "NewMessages:\\s*(\[\\d]*)" { send_user "New messages: $expect_out(1,string)\n" } } expect { -re "OldMessages:\\s*(\[\\d]*)" { send_user "Old messages: $expect_out(1,string)\n" } } # Log out -- not strictly necessary, but cleaner: send "Action: Logoff\n\n"We save the script as
vmcount.exp
and
set it executable with chmod a+x vmcount.exp
.$ ./vmcount.exp 123@default Mailbox: 123@default Connected. Logged in. New messages: 0 Old messages: 0
--enable-sockets
.[50] Unfortunately, the StarAstAPI files still contain the
obsolete "short open tags" (<?
). If you encounter them,
replace them with the correct syntax (<?php
). Four demo
scripts are included with the API: sLogin.php
attempts a login[51], sCommand.php
executes
reload
on the CLI, sDial.php
tries a
connection to SIP/120 and sEvents.php
receives
events. If we connect to Asterisk using asterisk
-vvvr
and simultaneously run php -q
sLogin.php
to open a connection to the AMI[52], watching the CLI, we see:mos-eisley*CLI> == Parsing '/etc/asterisk/manager.conf': Found [Jan 26 20:08:09] NOTICE[10352]: manager.c:961 authenticate: 127.0.0.1 tried to authenticate with nonexistent user 'mark' == Connect attempt from '127.0.0.1' unable to authenticate mos-eisley*CLI>This failed because the user did not exist, yet the demo script still reports success:
$ php -q sLogin.php Login Sucessfulfollowed by the response packet:
Response: Error ActionID: 1 Message: Authentication failedThe StarAstAPI is, as you can see, not completely clean, but is simple enough that it can be improved easily. If we call
php -q
sEvents.php
- this time with the correct user - we
see:mos-eisley*CLI> == Parsing '/etc/asterisk/manager.conf': Found == Manager 'admin' logged on from 127.0.0.1 mos-eisley*CLI>As a test, we execute a
reload
in the
CLI, which is reflected in the PHP script output:Event: Reload Privilege: system,all Message: Reload Requested Event: ChannelReload Privilege: system,all Channel: SIP ReloadReason: RELOAD (Channel module reload) Registry_Count: 0 Peer_Count: 0 User_Count: 0Give your creativity free-reign! Write a small script that calls all your friends - in the middle of the night, of course!
#!/usr/bin/php -q <?php # option -q turns off the header output when executing CGI-PHP if ($argc != 2) { echo "Error: You must specify a mailbox!\n"; exit(1); } # The first argument after the program name is the mailbox: $mailbox = $argv[1]; echo "Mailbox: $mailbox\n\n"; # Include StarAstAPI: require_once './StarAstAPI/StarAstAPI.php'; # Connect and log in: # $ami = new AstClientConnection(); if ($ami->Login( 'admin', 'secret5', '127.0.0.1', 5038 )) { $rp = $ami->GetResponse('1'); //echo $rp->ToString(); } else { exit(1); } # Send the following packet: # Action: MailboxCount # Mailbox: $mailbox # ActionID: 2 # $data = new AstPacketData; $data->AddKVPair( 'Action' , 'MailboxCount' ); $data->AddKVPair( 'Mailbox' , $mailbox ); $data->AddKVPair( 'ActionID', '2' ); $packet = new AstPacket; $packet->SetAstPacketType( 'Action' ); $packet->SetAstPacketData( $data ); $ami->SendPacket( $packet ); # Read the response packet bearing ActionID 2: # $rPacket = $ami->GetResponse('2'); //echo $rp->ToString(); $rData = $rPacket->GetAstPacketData(); $r = $rData->GetAll(); echo "New messages: ", (int)trim($r['NewMessages:']), "\n"; echo "Old messages: ", (int)trim($r['OldMessages:']), "\n"; echo "\n"; # Log out -- not strictly necessary, but cleaner: # $ami->Logoff(); # Unfortunately, StarAstAPI isn't totally discreet. # It does this: #echo "Logoff Called from somewhere ..."; #socket_close($this->mSocket); echo "\n"; ?>We save this script as
vmcount.php
and make it executable with chmod a+x
vmcount.exp
.$ ./vmcount.php 123@default Mailbox: 123123123 New messages: 0 Old messages: 0 Logoff Called from somewhere ...
manager show commands
(or show manager
commands
in Asterisk 1.2) in the CLI.telnet
as an interface,
and not in the traditional, interactive fashion.testscript.php-1169405408-1.
[50] You can check this from the shell with php
-m
.