#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "asterisk/lock.h"
Go to the source code of this file.
Data Structures | |
struct | manager_action |
struct | message |
Defines | |
#define | AMI_VERSION "1.0" |
#define | ast_manager_register(a, b, c, d) ast_manager_register2(a, b, c, d, NULL) |
#define | AST_MAX_MANHEADERS 128 |
#define | DEFAULT_MANAGER_PORT 5038 |
#define | EVENT_FLAG_AGENT (1 << 5) |
#define | EVENT_FLAG_CALL (1 << 1) |
#define | EVENT_FLAG_COMMAND (1 << 4) |
#define | EVENT_FLAG_CONFIG (1 << 7) |
#define | EVENT_FLAG_LOG (1 << 2) |
#define | EVENT_FLAG_SYSTEM (1 << 0) |
#define | EVENT_FLAG_USER (1 << 6) |
#define | EVENT_FLAG_VERBOSE (1 << 3) |
Functions | |
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 new command with manager, including online help. This is the preferred way to register a manager command | |
int | ast_manager_unregister (char *action) |
void | astman_append (struct mansession *s, const char *fmt,...) |
const char * | astman_get_header (const struct message *m, char *var) |
ast_variable * | astman_get_variables (const struct message *m) |
void | astman_send_ack (struct mansession *s, const struct message *m, char *msg) |
void | astman_send_error (struct mansession *s, const struct message *m, char *error) |
void | astman_send_response (struct mansession *s, const struct message *m, char *resp, char *msg) |
int | astman_verify_session_readpermissions (uint32_t ident, int perm) |
Verify a session's read permissions against a permission mask. | |
int | astman_verify_session_writepermissions (uint32_t ident, int perm) |
Verify a session's write permissions against a permission mask. | |
int | check_manager_enabled (void) |
Check if AMI is enabled. | |
int | check_webmanager_enabled (void) |
Check if AMI/HTTP is enabled. | |
int | init_manager (void) |
int | manager_event (int category, const char *event, const char *contents,...) |
manager_event: Send AMI event to client | |
int | reload_manager (void) |
Manager protocol packages are text fields of the form a: b. There is always exactly one space after the colon.
The first header type is the "Event" header. Other headers vary from event to event. Headers end with standard
termination. The last line of the manager response or event is an empty line. (
)
Please try to re-use existing headers to simplify manager message parsing in clients. Don't re-use an existing header with a new meaning, please. You can find a reference of standard headers in doc/manager.txt
Definition in file manager.h.
#define AMI_VERSION "1.0" |
#define ast_manager_register | ( | a, | |||
b, | |||||
c, | |||||
d | ) | ast_manager_register2(a, b, c, d, NULL) |
Definition at line 92 of file manager.h.
Referenced by astdb_init(), init_manager(), and load_module().
#define AST_MAX_MANHEADERS 128 |
#define DEFAULT_MANAGER_PORT 5038 |
#define EVENT_FLAG_AGENT (1 << 5) |
Definition at line 56 of file manager.h.
Referenced by __login_exec(), action_agent_callback_login(), add_to_queue(), agent_logoff_maintenance(), load_module(), record_abandoned(), remove_from_queue(), ring_entry(), set_member_paused(), try_calling(), and update_status().
#define EVENT_FLAG_CALL (1 << 1) |
Definition at line 52 of file manager.h.
Referenced by change_hold_state(), conf_run(), fast_originate(), init_manager(), join_queue(), leave_queue(), load_module(), manager_log(), manager_state_cb(), notify_new_message(), park_call_full(), park_exec(), pbx_extension_helper(), post_manager_event(), realtime_exec(), senddialevent(), socket_process(), and vm_execmain().
#define EVENT_FLAG_COMMAND (1 << 4) |
#define EVENT_FLAG_CONFIG (1 << 7) |
#define EVENT_FLAG_SYSTEM (1 << 0) |
Definition at line 51 of file manager.h.
Referenced by __expire_registry(), __iax2_poke_noanswer(), ast_log(), astdb_init(), dahdi_handle_event(), expire_register(), handle_alarms(), handle_init_event(), handle_response_peerpoke(), handle_response_register(), iax2_ack_registry(), init_manager(), load_module(), parse_register_contact(), quit_handler(), register_verify(), reload_logger(), reload_manager(), sip_poke_noanswer(), sip_reg_timeout(), socket_process(), ss_thread(), and update_registry().
#define EVENT_FLAG_USER (1 << 6) |
int astman_verify_session_readpermissions | ( | uint32_t | ident, | |
int | perm | |||
) |
Verify a session's read permissions against a permission mask.
ident | session identity | |
perm | permission mask to verify |
Definition at line 2815 of file manager.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), and s.
02816 { 02817 int result = 0; 02818 struct mansession *s; 02819 02820 AST_LIST_LOCK(&sessions); 02821 AST_LIST_TRAVERSE(&sessions, s, list) { 02822 ast_mutex_lock(&s->__lock); 02823 if ((s->managerid == ident) && (s->readperm & perm)) { 02824 result = 1; 02825 ast_mutex_unlock(&s->__lock); 02826 break; 02827 } 02828 ast_mutex_unlock(&s->__lock); 02829 } 02830 AST_LIST_UNLOCK(&sessions); 02831 return result; 02832 }
int astman_verify_session_writepermissions | ( | uint32_t | ident, | |
int | perm | |||
) |
Verify a session's write permissions against a permission mask.
ident | session identity | |
perm | permission mask to verify |
Definition at line 2834 of file manager.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), and s.
02835 { 02836 int result = 0; 02837 struct mansession *s; 02838 02839 AST_LIST_LOCK(&sessions); 02840 AST_LIST_TRAVERSE(&sessions, s, list) { 02841 ast_mutex_lock(&s->__lock); 02842 if ((s->managerid == ident) && (s->writeperm & perm)) { 02843 result = 1; 02844 ast_mutex_unlock(&s->__lock); 02845 break; 02846 } 02847 ast_mutex_unlock(&s->__lock); 02848 } 02849 AST_LIST_UNLOCK(&sessions); 02850 return result; 02851 }
int init_manager | ( | void | ) |
Called by Asterisk initialization
Definition at line 3053 of file manager.c.
References action_atxfer(), action_command(), action_coresettings(), action_corestatus(), action_events(), action_extensionstate(), action_getconfig(), action_getvar(), action_hangup(), action_listcommands(), action_logoff(), action_mailboxcount(), action_mailboxstatus(), action_originate(), action_ping(), action_redirect(), action_setvar(), action_status(), action_timeout(), action_updateconfig(), action_userevent(), action_waitevent(), append_event(), asock, ast_calloc, ast_category_browse(), ast_cli_register_multiple(), ast_config_load(), ast_copy_string(), ast_extension_state_add(), ast_get_manager_by_name_locked(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, ast_log(), ast_manager_register, ast_manager_register2(), ast_strdup, ast_true(), ast_variable_browse(), ast_variable_retrieve(), block_sockets, cli_manager, DEFAULT_MANAGER_PORT, ast_manager_user::deny, ast_manager_user::displayconnects, displayconnects, EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, EVENT_FLAG_CONFIG, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, ast_channel::flags, free, ast_manager_user::keep, LOG_DEBUG, LOG_WARNING, manager_enabled, manager_state_cb(), mandescr_atxfer, mandescr_command, mandescr_events, mandescr_extensionstate, mandescr_getconfig, mandescr_getvar, mandescr_hangup, mandescr_listcommands, mandescr_logoff, mandescr_mailboxcount, mandescr_mailboxstatus, mandescr_originate, mandescr_ping, mandescr_redirect, mandescr_setvar, mandescr_timeout, mandescr_updateconfig, mandescr_userevent, mandescr_waitevent, ast_manager_user::permit, portno, ast_manager_user::read, ast_manager_user::secret, timestampevents, var, webmanager_enabled, and ast_manager_user::write.
Referenced by main(), and reload_manager().
03054 { 03055 struct ast_config *cfg = NULL, *ucfg = NULL; 03056 const char *val; 03057 char *cat = NULL; 03058 int oldportno = portno; 03059 static struct sockaddr_in ba; 03060 int x = 1; 03061 int flags; 03062 int newhttptimeout = 60; 03063 struct ast_manager_user *user = NULL; 03064 03065 if (!registered) { 03066 /* Register default actions */ 03067 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping); 03068 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events); 03069 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff); 03070 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup); 03071 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" ); 03072 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar ); 03073 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar ); 03074 ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig); 03075 ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig); 03076 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect ); 03077 ast_manager_register2("Atxfer", EVENT_FLAG_CALL, action_atxfer, "Attended transfer", mandescr_atxfer ); 03078 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate); 03079 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command ); 03080 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate ); 03081 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout ); 03082 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus ); 03083 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount ); 03084 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands); 03085 ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent); 03086 ast_manager_register2("CoreSettings", EVENT_FLAG_SYSTEM, action_coresettings, "Show PBX core settings (version etc)", mandescr_coresettings); 03087 ast_manager_register2("CoreStatus", EVENT_FLAG_SYSTEM, action_corestatus, "Show PBX core status variables", mandescr_corestatus); 03088 ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent); 03089 03090 ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry)); 03091 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL); 03092 registered = 1; 03093 /* Append placeholder event so master_eventq never runs dry */ 03094 append_event("Event: Placeholder\r\n\r\n", 0); 03095 } 03096 portno = DEFAULT_MANAGER_PORT; 03097 displayconnects = 1; 03098 cfg = ast_config_load("manager.conf"); 03099 if (!cfg) { 03100 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n"); 03101 return 0; 03102 } 03103 if ((val = ast_variable_retrieve(cfg, "general", "enabled"))) { 03104 manager_enabled = ast_true(val); 03105 } 03106 if ((val = ast_variable_retrieve(cfg, "general", "block-sockets"))) { 03107 block_sockets = ast_true(val); 03108 } 03109 if((val = ast_variable_retrieve(cfg, "general", "webenabled"))) { 03110 webmanager_enabled = ast_true(val); 03111 } 03112 if ((val = ast_variable_retrieve(cfg, "general", "port"))) { 03113 if (sscanf(val, "%d", &portno) != 1) { 03114 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val); 03115 portno = DEFAULT_MANAGER_PORT; 03116 } 03117 } 03118 if ((val = ast_variable_retrieve(cfg, "general", "displayconnects"))) { 03119 displayconnects = ast_true(val); 03120 } 03121 if ((val = ast_variable_retrieve(cfg, "general", "timestampevents"))) { 03122 timestampevents = ast_true(val); 03123 } 03124 if ((val = ast_variable_retrieve(cfg, "general", "httptimeout"))) { 03125 newhttptimeout = atoi(val); 03126 } 03127 03128 memset(&ba, 0, sizeof(ba)); 03129 ba.sin_family = AF_INET; 03130 ba.sin_port = htons(portno); 03131 03132 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) { 03133 if (!inet_aton(val, &ba.sin_addr)) { 03134 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val); 03135 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr)); 03136 } 03137 } 03138 03139 03140 if ((asock > -1) && ((portno != oldportno) || !manager_enabled)) { 03141 #if 0 03142 /* Can't be done yet */ 03143 close(asock); 03144 asock = -1; 03145 #else 03146 ast_log(LOG_WARNING, "Unable to change management port / enabled\n"); 03147 #endif 03148 } 03149 03150 AST_LIST_LOCK(&users); 03151 03152 if ((ucfg = ast_config_load("users.conf"))) { 03153 while ((cat = ast_category_browse(ucfg, cat))) { 03154 int hasmanager = 0; 03155 struct ast_variable *var = NULL; 03156 03157 if (!strcasecmp(cat, "general")) { 03158 continue; 03159 } 03160 03161 if (!(hasmanager = ast_true(ast_variable_retrieve(ucfg, cat, "hasmanager")))) { 03162 continue; 03163 } 03164 03165 /* Look for an existing entry, if none found - create one and add it to the list */ 03166 if (!(user = ast_get_manager_by_name_locked(cat))) { 03167 if (!(user = ast_calloc(1, sizeof(*user)))) { 03168 break; 03169 } 03170 /* Copy name over */ 03171 ast_copy_string(user->username, cat, sizeof(user->username)); 03172 /* Insert into list */ 03173 AST_LIST_INSERT_TAIL(&users, user, list); 03174 } 03175 03176 /* Make sure we keep this user and don't destroy it during cleanup */ 03177 user->keep = 1; 03178 03179 for (var = ast_variable_browse(ucfg, cat); var; var = var->next) { 03180 if (!strcasecmp(var->name, "secret")) { 03181 if (user->secret) { 03182 free(user->secret); 03183 } 03184 user->secret = ast_strdup(var->value); 03185 } else if (!strcasecmp(var->name, "deny") ) { 03186 if (user->deny) { 03187 free(user->deny); 03188 } 03189 user->deny = ast_strdup(var->value); 03190 } else if (!strcasecmp(var->name, "permit") ) { 03191 if (user->permit) { 03192 free(user->permit); 03193 } 03194 user->permit = ast_strdup(var->value); 03195 } else if (!strcasecmp(var->name, "read") ) { 03196 if (user->read) { 03197 free(user->read); 03198 } 03199 user->read = ast_strdup(var->value); 03200 } else if (!strcasecmp(var->name, "write") ) { 03201 if (user->write) { 03202 free(user->write); 03203 } 03204 user->write = ast_strdup(var->value); 03205 } else if (!strcasecmp(var->name, "displayconnects") ) { 03206 user->displayconnects = ast_true(var->value); 03207 } else if (!strcasecmp(var->name, "hasmanager")) { 03208 /* already handled */ 03209 } else { 03210 ast_log(LOG_DEBUG, "%s is an unknown option (to the manager module).\n", var->name); 03211 } 03212 } 03213 } 03214 ast_config_destroy(ucfg); 03215 } 03216 03217 while ((cat = ast_category_browse(cfg, cat))) { 03218 struct ast_variable *var = NULL; 03219 03220 if (!strcasecmp(cat, "general")) 03221 continue; 03222 03223 /* Look for an existing entry, if none found - create one and add it to the list */ 03224 if (!(user = ast_get_manager_by_name_locked(cat))) { 03225 if (!(user = ast_calloc(1, sizeof(*user)))) 03226 break; 03227 /* Copy name over */ 03228 ast_copy_string(user->username, cat, sizeof(user->username)); 03229 /* Insert into list */ 03230 AST_LIST_INSERT_TAIL(&users, user, list); 03231 } 03232 03233 /* Make sure we keep this user and don't destroy it during cleanup */ 03234 user->keep = 1; 03235 03236 var = ast_variable_browse(cfg, cat); 03237 while (var) { 03238 if (!strcasecmp(var->name, "secret")) { 03239 if (user->secret) 03240 free(user->secret); 03241 user->secret = ast_strdup(var->value); 03242 } else if (!strcasecmp(var->name, "deny") ) { 03243 if (user->deny) 03244 free(user->deny); 03245 user->deny = ast_strdup(var->value); 03246 } else if (!strcasecmp(var->name, "permit") ) { 03247 if (user->permit) 03248 free(user->permit); 03249 user->permit = ast_strdup(var->value); 03250 } else if (!strcasecmp(var->name, "read") ) { 03251 if (user->read) 03252 free(user->read); 03253 user->read = ast_strdup(var->value); 03254 } else if (!strcasecmp(var->name, "write") ) { 03255 if (user->write) 03256 free(user->write); 03257 user->write = ast_strdup(var->value); 03258 } else if (!strcasecmp(var->name, "displayconnects") ) 03259 user->displayconnects = ast_true(var->value); 03260 else 03261 ast_log(LOG_DEBUG, "%s is an unknown option.\n", var->name); 03262 var = var->next; 03263 } 03264 } 03265 03266 /* Perform cleanup - essentially prune out old users that no longer exist */ 03267 AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, list) { 03268 if (user->keep) { 03269 user->keep = 0; 03270 continue; 03271 } 03272 /* We do not need to keep this user so take them out of the list */ 03273 AST_LIST_REMOVE_CURRENT(&users, list); 03274 /* Free their memory now */ 03275 if (user->secret) 03276 free(user->secret); 03277 if (user->deny) 03278 free(user->deny); 03279 if (user->permit) 03280 free(user->permit); 03281 if (user->read) 03282 free(user->read); 03283 if (user->write) 03284 free(user->write); 03285 free(user); 03286 } 03287 AST_LIST_TRAVERSE_SAFE_END 03288 03289 AST_LIST_UNLOCK(&users); 03290 03291 ast_config_destroy(cfg); 03292 03293 if (webmanager_enabled && manager_enabled) { 03294 if (!webregged) { 03295 ast_http_uri_link(&rawmanuri); 03296 ast_http_uri_link(&manageruri); 03297 ast_http_uri_link(&managerxmluri); 03298 webregged = 1; 03299 } 03300 } else { 03301 if (webregged) { 03302 ast_http_uri_unlink(&rawmanuri); 03303 ast_http_uri_unlink(&manageruri); 03304 ast_http_uri_unlink(&managerxmluri); 03305 webregged = 0; 03306 } 03307 } 03308 03309 if (newhttptimeout > 0) 03310 httptimeout = newhttptimeout; 03311 03312 /* If not enabled, do nothing */ 03313 if (!manager_enabled) 03314 return 0; 03315 03316 if (asock < 0) { 03317 asock = socket(AF_INET, SOCK_STREAM, 0); 03318 if (asock < 0) { 03319 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno)); 03320 return -1; 03321 } 03322 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 03323 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) { 03324 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno)); 03325 close(asock); 03326 asock = -1; 03327 return -1; 03328 } 03329 if (listen(asock, 2)) { 03330 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno)); 03331 close(asock); 03332 asock = -1; 03333 return -1; 03334 } 03335 flags = fcntl(asock, F_GETFL); 03336 fcntl(asock, F_SETFL, flags | O_NONBLOCK); 03337 if (option_verbose) 03338 ast_verbose("Asterisk Management interface listening on port %d\n", portno); 03339 ast_pthread_create_background(&t, NULL, accept_thread, NULL); 03340 } 03341 return 0; 03342 }
int reload_manager | ( | void | ) |
Definition at line 3344 of file manager.c.
References EVENT_FLAG_SYSTEM, init_manager(), and manager_event().
03345 { 03346 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n"); 03347 return init_manager(); 03348 }