#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(), main(), parse_register_contact(), process_message(), 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 2938 of file manager.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), and s.
02939 { 02940 int result = 0; 02941 struct mansession_session *s; 02942 02943 AST_LIST_LOCK(&sessions); 02944 AST_LIST_TRAVERSE(&sessions, s, list) { 02945 ast_mutex_lock(&s->__lock); 02946 if ((s->managerid == ident) && (s->readperm & perm)) { 02947 result = 1; 02948 ast_mutex_unlock(&s->__lock); 02949 break; 02950 } 02951 ast_mutex_unlock(&s->__lock); 02952 } 02953 AST_LIST_UNLOCK(&sessions); 02954 return result; 02955 }
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 2957 of file manager.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), and s.
02958 { 02959 int result = 0; 02960 struct mansession_session *s; 02961 02962 AST_LIST_LOCK(&sessions); 02963 AST_LIST_TRAVERSE(&sessions, s, list) { 02964 ast_mutex_lock(&s->__lock); 02965 if ((s->managerid == ident) && (s->writeperm & perm)) { 02966 result = 1; 02967 ast_mutex_unlock(&s->__lock); 02968 break; 02969 } 02970 ast_mutex_unlock(&s->__lock); 02971 } 02972 AST_LIST_UNLOCK(&sessions); 02973 return result; 02974 }
int init_manager | ( | void | ) |
Called by Asterisk initialization
Definition at line 3226 of file manager.c.
References 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(), authlimit, authtimeout, block_sockets, broken_events_action, cli_manager, DEFAULT_AUTHLIMIT, DEFAULT_AUTHTIMEOUT, DEFAULT_BLOCKSOCKETS, DEFAULT_BROKENEVENTSACTION, DEFAULT_DISPLAYCONNECTS, DEFAULT_HTTPTIMEOUT, DEFAULT_MANAGER_PORT, DEFAULT_TIMESTAMPEVENTS, DEFAULT_WEBENABLED, 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, httptimeout, ast_manager_user::keep, LOG_DEBUG, LOG_WARNING, manager_enabled, manager_state_cb(), 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().
03227 { 03228 struct ast_config *cfg = NULL, *ucfg = NULL; 03229 const char *val; 03230 char *cat = NULL; 03231 int oldportno = portno; 03232 static struct sockaddr_in ba; 03233 int x = 1; 03234 int flags; 03235 int webenabled = DEFAULT_WEBENABLED; 03236 int newhttptimeout = DEFAULT_HTTPTIMEOUT; 03237 struct ast_manager_user *user = NULL; 03238 03239 if (!registered) { 03240 /* Register default actions */ 03241 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping); 03242 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events); 03243 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff); 03244 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup); 03245 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" ); 03246 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar ); 03247 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar ); 03248 ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig); 03249 ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig); 03250 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect ); 03251 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate); 03252 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command ); 03253 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate ); 03254 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout ); 03255 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus ); 03256 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount ); 03257 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands); 03258 ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent); 03259 ast_manager_register2("CoreSettings", EVENT_FLAG_SYSTEM, action_coresettings, "Show PBX core settings (version etc)", mandescr_coresettings); 03260 ast_manager_register2("CoreStatus", EVENT_FLAG_SYSTEM, action_corestatus, "Show PBX core status variables", mandescr_corestatus); 03261 ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent); 03262 03263 ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry)); 03264 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL); 03265 registered = 1; 03266 /* Append placeholder event so master_eventq never runs dry */ 03267 append_event("Event: Placeholder\r\n\r\n", 0); 03268 } 03269 03270 portno = DEFAULT_MANAGER_PORT; 03271 displayconnects = DEFAULT_DISPLAYCONNECTS; 03272 broken_events_action = DEFAULT_BROKENEVENTSACTION; 03273 block_sockets = DEFAULT_BLOCKSOCKETS; 03274 timestampevents = DEFAULT_TIMESTAMPEVENTS; 03275 httptimeout = DEFAULT_HTTPTIMEOUT; 03276 authtimeout = DEFAULT_AUTHTIMEOUT; 03277 authlimit = DEFAULT_AUTHLIMIT; 03278 03279 cfg = ast_config_load("manager.conf"); 03280 if (!cfg) { 03281 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n"); 03282 return 0; 03283 } 03284 if ((val = ast_variable_retrieve(cfg, "general", "enabled"))) { 03285 manager_enabled = ast_true(val); 03286 } 03287 if ((val = ast_variable_retrieve(cfg, "general", "block-sockets"))) { 03288 block_sockets = ast_true(val); 03289 } 03290 if((val = ast_variable_retrieve(cfg, "general", "webenabled"))) { 03291 webmanager_enabled = ast_true(val); 03292 } 03293 if ((val = ast_variable_retrieve(cfg, "general", "port"))) { 03294 if (sscanf(val, "%5d", &portno) != 1) { 03295 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val); 03296 portno = DEFAULT_MANAGER_PORT; 03297 } 03298 } 03299 03300 if ((val = ast_variable_retrieve(cfg, "general", "displayconnects"))) 03301 displayconnects = ast_true(val); 03302 03303 if ((val = ast_variable_retrieve(cfg, "general", "brokeneventsaction"))) 03304 broken_events_action = ast_true(val); 03305 03306 if ((val = ast_variable_retrieve(cfg, "general", "timestampevents"))) 03307 timestampevents = ast_true(val); 03308 03309 if ((val = ast_variable_retrieve(cfg, "general", "httptimeout"))) 03310 newhttptimeout = atoi(val); 03311 03312 if ((val = ast_variable_retrieve(cfg, "general", "authtimeout"))) { 03313 int timeout = atoi(val); 03314 03315 if (timeout < 1) { 03316 ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", val); 03317 } else { 03318 authtimeout = timeout; 03319 } 03320 } 03321 03322 if ((val = ast_variable_retrieve(cfg, "general", "authlimit"))) { 03323 int limit = atoi(val); 03324 03325 if (limit < 1) { 03326 ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", val); 03327 } else { 03328 authlimit = limit; 03329 } 03330 } 03331 03332 memset(&ba, 0, sizeof(ba)); 03333 ba.sin_family = AF_INET; 03334 ba.sin_port = htons(portno); 03335 03336 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) { 03337 if (!inet_aton(val, &ba.sin_addr)) { 03338 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val); 03339 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr)); 03340 } 03341 } 03342 03343 03344 if ((asock > -1) && ((portno != oldportno) || !manager_enabled)) { 03345 #if 0 03346 /* Can't be done yet */ 03347 close(asock); 03348 asock = -1; 03349 #else 03350 ast_log(LOG_WARNING, "Unable to change management port / enabled\n"); 03351 #endif 03352 } 03353 03354 AST_LIST_LOCK(&users); 03355 03356 if ((ucfg = ast_config_load("users.conf"))) { 03357 while ((cat = ast_category_browse(ucfg, cat))) { 03358 int hasmanager = 0; 03359 struct ast_variable *var = NULL; 03360 03361 if (!strcasecmp(cat, "general")) { 03362 continue; 03363 } 03364 03365 if (!(hasmanager = ast_true(ast_variable_retrieve(ucfg, cat, "hasmanager")))) { 03366 continue; 03367 } 03368 03369 /* Look for an existing entry, if none found - create one and add it to the list */ 03370 if (!(user = ast_get_manager_by_name_locked(cat))) { 03371 if (!(user = ast_calloc(1, sizeof(*user)))) { 03372 break; 03373 } 03374 /* Copy name over */ 03375 ast_copy_string(user->username, cat, sizeof(user->username)); 03376 /* Insert into list */ 03377 AST_LIST_INSERT_TAIL(&users, user, list); 03378 } 03379 03380 /* Make sure we keep this user and don't destroy it during cleanup */ 03381 user->keep = 1; 03382 03383 for (var = ast_variable_browse(ucfg, cat); var; var = var->next) { 03384 if (!strcasecmp(var->name, "secret")) { 03385 if (user->secret) { 03386 free(user->secret); 03387 } 03388 user->secret = ast_strdup(var->value); 03389 } else if (!strcasecmp(var->name, "deny") ) { 03390 if (user->deny) { 03391 free(user->deny); 03392 } 03393 user->deny = ast_strdup(var->value); 03394 } else if (!strcasecmp(var->name, "permit") ) { 03395 if (user->permit) { 03396 free(user->permit); 03397 } 03398 user->permit = ast_strdup(var->value); 03399 } else if (!strcasecmp(var->name, "read") ) { 03400 if (user->read) { 03401 free(user->read); 03402 } 03403 user->read = ast_strdup(var->value); 03404 } else if (!strcasecmp(var->name, "write") ) { 03405 if (user->write) { 03406 free(user->write); 03407 } 03408 user->write = ast_strdup(var->value); 03409 } else if (!strcasecmp(var->name, "displayconnects") ) { 03410 user->displayconnects = ast_true(var->value); 03411 } else if (!strcasecmp(var->name, "hasmanager")) { 03412 /* already handled */ 03413 } else { 03414 ast_log(LOG_DEBUG, "%s is an unknown option (to the manager module).\n", var->name); 03415 } 03416 } 03417 } 03418 ast_config_destroy(ucfg); 03419 } 03420 03421 while ((cat = ast_category_browse(cfg, cat))) { 03422 struct ast_variable *var = NULL; 03423 03424 if (!strcasecmp(cat, "general")) 03425 continue; 03426 03427 /* Look for an existing entry, if none found - create one and add it to the list */ 03428 if (!(user = ast_get_manager_by_name_locked(cat))) { 03429 if (!(user = ast_calloc(1, sizeof(*user)))) 03430 break; 03431 /* Copy name over */ 03432 ast_copy_string(user->username, cat, sizeof(user->username)); 03433 /* Insert into list */ 03434 AST_LIST_INSERT_TAIL(&users, user, list); 03435 } 03436 03437 /* Make sure we keep this user and don't destroy it during cleanup */ 03438 user->keep = 1; 03439 03440 var = ast_variable_browse(cfg, cat); 03441 while (var) { 03442 if (!strcasecmp(var->name, "secret")) { 03443 if (user->secret) 03444 free(user->secret); 03445 user->secret = ast_strdup(var->value); 03446 } else if (!strcasecmp(var->name, "deny") ) { 03447 if (user->deny) 03448 free(user->deny); 03449 user->deny = ast_strdup(var->value); 03450 } else if (!strcasecmp(var->name, "permit") ) { 03451 if (user->permit) 03452 free(user->permit); 03453 user->permit = ast_strdup(var->value); 03454 } else if (!strcasecmp(var->name, "read") ) { 03455 if (user->read) 03456 free(user->read); 03457 user->read = ast_strdup(var->value); 03458 } else if (!strcasecmp(var->name, "write") ) { 03459 if (user->write) 03460 free(user->write); 03461 user->write = ast_strdup(var->value); 03462 } else if (!strcasecmp(var->name, "displayconnects") ) 03463 user->displayconnects = ast_true(var->value); 03464 else 03465 ast_log(LOG_DEBUG, "%s is an unknown option.\n", var->name); 03466 var = var->next; 03467 } 03468 } 03469 03470 /* Perform cleanup - essentially prune out old users that no longer exist */ 03471 AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, list) { 03472 if (user->keep) { 03473 user->keep = 0; 03474 continue; 03475 } 03476 /* We do not need to keep this user so take them out of the list */ 03477 AST_LIST_REMOVE_CURRENT(&users, list); 03478 /* Free their memory now */ 03479 if (user->secret) 03480 free(user->secret); 03481 if (user->deny) 03482 free(user->deny); 03483 if (user->permit) 03484 free(user->permit); 03485 if (user->read) 03486 free(user->read); 03487 if (user->write) 03488 free(user->write); 03489 free(user); 03490 } 03491 AST_LIST_TRAVERSE_SAFE_END 03492 03493 AST_LIST_UNLOCK(&users); 03494 03495 ast_config_destroy(cfg); 03496 03497 if (webmanager_enabled && manager_enabled) { 03498 if (!webregged) { 03499 ast_http_uri_link(&rawmanuri); 03500 ast_http_uri_link(&manageruri); 03501 ast_http_uri_link(&managerxmluri); 03502 webregged = 1; 03503 } 03504 } else { 03505 if (webregged) { 03506 ast_http_uri_unlink(&rawmanuri); 03507 ast_http_uri_unlink(&manageruri); 03508 ast_http_uri_unlink(&managerxmluri); 03509 webregged = 0; 03510 } 03511 } 03512 03513 if (newhttptimeout > 0) 03514 httptimeout = newhttptimeout; 03515 03516 /* If not enabled, do nothing */ 03517 if (!manager_enabled) 03518 return 0; 03519 03520 if (asock < 0) { 03521 asock = socket(AF_INET, SOCK_STREAM, 0); 03522 if (asock < 0) { 03523 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno)); 03524 return -1; 03525 } 03526 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 03527 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) { 03528 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno)); 03529 close(asock); 03530 asock = -1; 03531 return -1; 03532 } 03533 if (listen(asock, 2)) { 03534 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno)); 03535 close(asock); 03536 asock = -1; 03537 return -1; 03538 } 03539 flags = fcntl(asock, F_GETFL); 03540 fcntl(asock, F_SETFL, flags | O_NONBLOCK); 03541 if (option_verbose) 03542 ast_verbose("Asterisk Management interface listening on port %d\n", portno); 03543 ast_pthread_create_background(&t, NULL, accept_thread, NULL); 03544 } 03545 return 0; 03546 }
int reload_manager | ( | void | ) |
Definition at line 3548 of file manager.c.
References EVENT_FLAG_SYSTEM, init_manager(), and manager_event().
03549 { 03550 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n"); 03551 return init_manager(); 03552 }