#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(), send_talking_event(), 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(), dahdi_r2_on_hardware_alarm(), 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) |
Definition at line 57 of file manager.h.
Referenced by aji_log_hook(), builtin_automonitor(), and init_manager().
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 2876 of file manager.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), and s.
02877 { 02878 int result = 0; 02879 struct mansession_session *s; 02880 02881 AST_LIST_LOCK(&sessions); 02882 AST_LIST_TRAVERSE(&sessions, s, list) { 02883 ast_mutex_lock(&s->__lock); 02884 if ((s->managerid == ident) && (s->readperm & perm)) { 02885 result = 1; 02886 ast_mutex_unlock(&s->__lock); 02887 break; 02888 } 02889 ast_mutex_unlock(&s->__lock); 02890 } 02891 AST_LIST_UNLOCK(&sessions); 02892 return result; 02893 }
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 2895 of file manager.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), and s.
02896 { 02897 int result = 0; 02898 struct mansession_session *s; 02899 02900 AST_LIST_LOCK(&sessions); 02901 AST_LIST_TRAVERSE(&sessions, s, list) { 02902 ast_mutex_lock(&s->__lock); 02903 if ((s->managerid == ident) && (s->writeperm & perm)) { 02904 result = 1; 02905 ast_mutex_unlock(&s->__lock); 02906 break; 02907 } 02908 ast_mutex_unlock(&s->__lock); 02909 } 02910 AST_LIST_UNLOCK(&sessions); 02911 return result; 02912 }
int init_manager | ( | void | ) |
Called by Asterisk initialization
Definition at line 3157 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().
03158 { 03159 struct ast_config *cfg = NULL, *ucfg = NULL; 03160 const char *val; 03161 char *cat = NULL; 03162 int oldportno = portno; 03163 static struct sockaddr_in ba; 03164 int x = 1; 03165 int flags; 03166 int newhttptimeout = 60; 03167 struct ast_manager_user *user = NULL; 03168 03169 if (!registered) { 03170 /* Register default actions */ 03171 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping); 03172 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events); 03173 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff); 03174 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup); 03175 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" ); 03176 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar ); 03177 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar ); 03178 ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig); 03179 ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig); 03180 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect ); 03181 ast_manager_register2("Atxfer", EVENT_FLAG_CALL, action_atxfer, "Attended transfer", mandescr_atxfer ); 03182 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate); 03183 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command ); 03184 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate ); 03185 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout ); 03186 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus ); 03187 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount ); 03188 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands); 03189 ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent); 03190 ast_manager_register2("CoreSettings", EVENT_FLAG_SYSTEM, action_coresettings, "Show PBX core settings (version etc)", mandescr_coresettings); 03191 ast_manager_register2("CoreStatus", EVENT_FLAG_SYSTEM, action_corestatus, "Show PBX core status variables", mandescr_corestatus); 03192 ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent); 03193 03194 ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry)); 03195 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL); 03196 registered = 1; 03197 /* Append placeholder event so master_eventq never runs dry */ 03198 append_event("Event: Placeholder\r\n\r\n", 0); 03199 } 03200 portno = DEFAULT_MANAGER_PORT; 03201 displayconnects = 1; 03202 cfg = ast_config_load("manager.conf"); 03203 if (!cfg) { 03204 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n"); 03205 return 0; 03206 } 03207 if ((val = ast_variable_retrieve(cfg, "general", "enabled"))) { 03208 manager_enabled = ast_true(val); 03209 } 03210 if ((val = ast_variable_retrieve(cfg, "general", "block-sockets"))) { 03211 block_sockets = ast_true(val); 03212 } 03213 if((val = ast_variable_retrieve(cfg, "general", "webenabled"))) { 03214 webmanager_enabled = ast_true(val); 03215 } 03216 if ((val = ast_variable_retrieve(cfg, "general", "port"))) { 03217 if (sscanf(val, "%5d", &portno) != 1) { 03218 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val); 03219 portno = DEFAULT_MANAGER_PORT; 03220 } 03221 } 03222 03223 if ((val = ast_variable_retrieve(cfg, "general", "displayconnects"))) { 03224 displayconnects = ast_true(val); 03225 } 03226 if ((val = ast_variable_retrieve(cfg, "general", "timestampevents"))) { 03227 timestampevents = ast_true(val); 03228 } 03229 if ((val = ast_variable_retrieve(cfg, "general", "httptimeout"))) { 03230 newhttptimeout = atoi(val); 03231 } 03232 03233 memset(&ba, 0, sizeof(ba)); 03234 ba.sin_family = AF_INET; 03235 ba.sin_port = htons(portno); 03236 03237 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) { 03238 if (!inet_aton(val, &ba.sin_addr)) { 03239 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val); 03240 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr)); 03241 } 03242 } 03243 03244 03245 if ((asock > -1) && ((portno != oldportno) || !manager_enabled)) { 03246 #if 0 03247 /* Can't be done yet */ 03248 close(asock); 03249 asock = -1; 03250 #else 03251 ast_log(LOG_WARNING, "Unable to change management port / enabled\n"); 03252 #endif 03253 } 03254 03255 AST_LIST_LOCK(&users); 03256 03257 if ((ucfg = ast_config_load("users.conf"))) { 03258 while ((cat = ast_category_browse(ucfg, cat))) { 03259 int hasmanager = 0; 03260 struct ast_variable *var = NULL; 03261 03262 if (!strcasecmp(cat, "general")) { 03263 continue; 03264 } 03265 03266 if (!(hasmanager = ast_true(ast_variable_retrieve(ucfg, cat, "hasmanager")))) { 03267 continue; 03268 } 03269 03270 /* Look for an existing entry, if none found - create one and add it to the list */ 03271 if (!(user = ast_get_manager_by_name_locked(cat))) { 03272 if (!(user = ast_calloc(1, sizeof(*user)))) { 03273 break; 03274 } 03275 /* Copy name over */ 03276 ast_copy_string(user->username, cat, sizeof(user->username)); 03277 /* Insert into list */ 03278 AST_LIST_INSERT_TAIL(&users, user, list); 03279 } 03280 03281 /* Make sure we keep this user and don't destroy it during cleanup */ 03282 user->keep = 1; 03283 03284 for (var = ast_variable_browse(ucfg, cat); var; var = var->next) { 03285 if (!strcasecmp(var->name, "secret")) { 03286 if (user->secret) { 03287 free(user->secret); 03288 } 03289 user->secret = ast_strdup(var->value); 03290 } else if (!strcasecmp(var->name, "deny") ) { 03291 if (user->deny) { 03292 free(user->deny); 03293 } 03294 user->deny = ast_strdup(var->value); 03295 } else if (!strcasecmp(var->name, "permit") ) { 03296 if (user->permit) { 03297 free(user->permit); 03298 } 03299 user->permit = ast_strdup(var->value); 03300 } else if (!strcasecmp(var->name, "read") ) { 03301 if (user->read) { 03302 free(user->read); 03303 } 03304 user->read = ast_strdup(var->value); 03305 } else if (!strcasecmp(var->name, "write") ) { 03306 if (user->write) { 03307 free(user->write); 03308 } 03309 user->write = ast_strdup(var->value); 03310 } else if (!strcasecmp(var->name, "displayconnects") ) { 03311 user->displayconnects = ast_true(var->value); 03312 } else if (!strcasecmp(var->name, "hasmanager")) { 03313 /* already handled */ 03314 } else { 03315 ast_log(LOG_DEBUG, "%s is an unknown option (to the manager module).\n", var->name); 03316 } 03317 } 03318 } 03319 ast_config_destroy(ucfg); 03320 } 03321 03322 while ((cat = ast_category_browse(cfg, cat))) { 03323 struct ast_variable *var = NULL; 03324 03325 if (!strcasecmp(cat, "general")) 03326 continue; 03327 03328 /* Look for an existing entry, if none found - create one and add it to the list */ 03329 if (!(user = ast_get_manager_by_name_locked(cat))) { 03330 if (!(user = ast_calloc(1, sizeof(*user)))) 03331 break; 03332 /* Copy name over */ 03333 ast_copy_string(user->username, cat, sizeof(user->username)); 03334 /* Insert into list */ 03335 AST_LIST_INSERT_TAIL(&users, user, list); 03336 } 03337 03338 /* Make sure we keep this user and don't destroy it during cleanup */ 03339 user->keep = 1; 03340 03341 var = ast_variable_browse(cfg, cat); 03342 while (var) { 03343 if (!strcasecmp(var->name, "secret")) { 03344 if (user->secret) 03345 free(user->secret); 03346 user->secret = ast_strdup(var->value); 03347 } else if (!strcasecmp(var->name, "deny") ) { 03348 if (user->deny) 03349 free(user->deny); 03350 user->deny = ast_strdup(var->value); 03351 } else if (!strcasecmp(var->name, "permit") ) { 03352 if (user->permit) 03353 free(user->permit); 03354 user->permit = ast_strdup(var->value); 03355 } else if (!strcasecmp(var->name, "read") ) { 03356 if (user->read) 03357 free(user->read); 03358 user->read = ast_strdup(var->value); 03359 } else if (!strcasecmp(var->name, "write") ) { 03360 if (user->write) 03361 free(user->write); 03362 user->write = ast_strdup(var->value); 03363 } else if (!strcasecmp(var->name, "displayconnects") ) 03364 user->displayconnects = ast_true(var->value); 03365 else 03366 ast_log(LOG_DEBUG, "%s is an unknown option.\n", var->name); 03367 var = var->next; 03368 } 03369 } 03370 03371 /* Perform cleanup - essentially prune out old users that no longer exist */ 03372 AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, list) { 03373 if (user->keep) { 03374 user->keep = 0; 03375 continue; 03376 } 03377 /* We do not need to keep this user so take them out of the list */ 03378 AST_LIST_REMOVE_CURRENT(&users, list); 03379 /* Free their memory now */ 03380 if (user->secret) 03381 free(user->secret); 03382 if (user->deny) 03383 free(user->deny); 03384 if (user->permit) 03385 free(user->permit); 03386 if (user->read) 03387 free(user->read); 03388 if (user->write) 03389 free(user->write); 03390 free(user); 03391 } 03392 AST_LIST_TRAVERSE_SAFE_END 03393 03394 AST_LIST_UNLOCK(&users); 03395 03396 ast_config_destroy(cfg); 03397 03398 if (webmanager_enabled && manager_enabled) { 03399 if (!webregged) { 03400 ast_http_uri_link(&rawmanuri); 03401 ast_http_uri_link(&manageruri); 03402 ast_http_uri_link(&managerxmluri); 03403 webregged = 1; 03404 } 03405 } else { 03406 if (webregged) { 03407 ast_http_uri_unlink(&rawmanuri); 03408 ast_http_uri_unlink(&manageruri); 03409 ast_http_uri_unlink(&managerxmluri); 03410 webregged = 0; 03411 } 03412 } 03413 03414 if (newhttptimeout > 0) 03415 httptimeout = newhttptimeout; 03416 03417 /* If not enabled, do nothing */ 03418 if (!manager_enabled) 03419 return 0; 03420 03421 if (asock < 0) { 03422 asock = socket(AF_INET, SOCK_STREAM, 0); 03423 if (asock < 0) { 03424 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno)); 03425 return -1; 03426 } 03427 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 03428 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) { 03429 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno)); 03430 close(asock); 03431 asock = -1; 03432 return -1; 03433 } 03434 if (listen(asock, 2)) { 03435 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno)); 03436 close(asock); 03437 asock = -1; 03438 return -1; 03439 } 03440 flags = fcntl(asock, F_GETFL); 03441 fcntl(asock, F_SETFL, flags | O_NONBLOCK); 03442 if (option_verbose) 03443 ast_verbose("Asterisk Management interface listening on port %d\n", portno); 03444 ast_pthread_create_background(&t, NULL, accept_thread, NULL); 03445 } 03446 return 0; 03447 }
int reload_manager | ( | void | ) |
Definition at line 3449 of file manager.c.
References EVENT_FLAG_SYSTEM, init_manager(), and manager_event().
03450 { 03451 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n"); 03452 return init_manager(); 03453 }