#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) |
Definition at line 57 of file manager.h.
Referenced by action_userevent(), aji_log_hook(), init_manager(), and userevent_exec().
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 2800 of file manager.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), and s.
02801 { 02802 int result = 0; 02803 struct mansession *s; 02804 02805 AST_LIST_LOCK(&sessions); 02806 AST_LIST_TRAVERSE(&sessions, s, list) { 02807 ast_mutex_lock(&s->__lock); 02808 if ((s->managerid == ident) && (s->readperm & perm)) { 02809 result = 1; 02810 ast_mutex_unlock(&s->__lock); 02811 break; 02812 } 02813 ast_mutex_unlock(&s->__lock); 02814 } 02815 AST_LIST_UNLOCK(&sessions); 02816 return result; 02817 }
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 2819 of file manager.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), and s.
02820 { 02821 int result = 0; 02822 struct mansession *s; 02823 02824 AST_LIST_LOCK(&sessions); 02825 AST_LIST_TRAVERSE(&sessions, s, list) { 02826 ast_mutex_lock(&s->__lock); 02827 if ((s->managerid == ident) && (s->writeperm & perm)) { 02828 result = 1; 02829 ast_mutex_unlock(&s->__lock); 02830 break; 02831 } 02832 ast_mutex_unlock(&s->__lock); 02833 } 02834 AST_LIST_UNLOCK(&sessions); 02835 return result; 02836 }
int init_manager | ( | void | ) |
Called by Asterisk initialization
Definition at line 3038 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(), 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().
03039 { 03040 struct ast_config *cfg = NULL, *ucfg = NULL; 03041 const char *val; 03042 char *cat = NULL; 03043 int oldportno = portno; 03044 static struct sockaddr_in ba; 03045 int x = 1; 03046 int flags; 03047 int newhttptimeout = 60; 03048 struct ast_manager_user *user = NULL; 03049 03050 if (!registered) { 03051 /* Register default actions */ 03052 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping); 03053 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events); 03054 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff); 03055 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup); 03056 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" ); 03057 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar ); 03058 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar ); 03059 ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig); 03060 ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig); 03061 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect ); 03062 ast_manager_register2("Atxfer", EVENT_FLAG_CALL, action_atxfer, "Attended transfer", mandescr_atxfer ); 03063 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate); 03064 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command ); 03065 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate ); 03066 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout ); 03067 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus ); 03068 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount ); 03069 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands); 03070 ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent); 03071 ast_manager_register2("CoreSettings", EVENT_FLAG_SYSTEM, action_coresettings, "Show PBX core settings (version etc)", mandescr_coresettings); 03072 ast_manager_register2("CoreStatus", EVENT_FLAG_SYSTEM, action_corestatus, "Show PBX core status variables", mandescr_corestatus); 03073 ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent); 03074 03075 ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry)); 03076 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL); 03077 registered = 1; 03078 /* Append placeholder event so master_eventq never runs dry */ 03079 append_event("Event: Placeholder\r\n\r\n", 0); 03080 } 03081 portno = DEFAULT_MANAGER_PORT; 03082 displayconnects = 1; 03083 cfg = ast_config_load("manager.conf"); 03084 if (!cfg) { 03085 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n"); 03086 return 0; 03087 } 03088 if ((val = ast_variable_retrieve(cfg, "general", "enabled"))) { 03089 manager_enabled = ast_true(val); 03090 } 03091 if ((val = ast_variable_retrieve(cfg, "general", "block-sockets"))) { 03092 block_sockets = ast_true(val); 03093 } 03094 if((val = ast_variable_retrieve(cfg, "general", "webenabled"))) { 03095 webmanager_enabled = ast_true(val); 03096 } 03097 if ((val = ast_variable_retrieve(cfg, "general", "port"))) { 03098 if (sscanf(val, "%d", &portno) != 1) { 03099 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val); 03100 portno = DEFAULT_MANAGER_PORT; 03101 } 03102 } 03103 if ((val = ast_variable_retrieve(cfg, "general", "displayconnects"))) { 03104 displayconnects = ast_true(val); 03105 } 03106 if ((val = ast_variable_retrieve(cfg, "general", "timestampevents"))) { 03107 timestampevents = ast_true(val); 03108 } 03109 if ((val = ast_variable_retrieve(cfg, "general", "httptimeout"))) { 03110 newhttptimeout = atoi(val); 03111 } 03112 03113 memset(&ba, 0, sizeof(ba)); 03114 ba.sin_family = AF_INET; 03115 ba.sin_port = htons(portno); 03116 03117 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) { 03118 if (!inet_aton(val, &ba.sin_addr)) { 03119 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val); 03120 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr)); 03121 } 03122 } 03123 03124 03125 if ((asock > -1) && ((portno != oldportno) || !manager_enabled)) { 03126 #if 0 03127 /* Can't be done yet */ 03128 close(asock); 03129 asock = -1; 03130 #else 03131 ast_log(LOG_WARNING, "Unable to change management port / enabled\n"); 03132 #endif 03133 } 03134 03135 AST_LIST_LOCK(&users); 03136 03137 if ((ucfg = ast_config_load("users.conf"))) { 03138 while ((cat = ast_category_browse(ucfg, cat))) { 03139 int hasmanager = 0; 03140 struct ast_variable *var = NULL; 03141 03142 if (!strcasecmp(cat, "general")) { 03143 continue; 03144 } 03145 03146 if (!(hasmanager = ast_true(ast_variable_retrieve(ucfg, cat, "hasmanager")))) { 03147 continue; 03148 } 03149 03150 /* Look for an existing entry, if none found - create one and add it to the list */ 03151 if (!(user = ast_get_manager_by_name_locked(cat))) { 03152 if (!(user = ast_calloc(1, sizeof(*user)))) { 03153 break; 03154 } 03155 /* Copy name over */ 03156 ast_copy_string(user->username, cat, sizeof(user->username)); 03157 /* Insert into list */ 03158 AST_LIST_INSERT_TAIL(&users, user, list); 03159 } 03160 03161 /* Make sure we keep this user and don't destroy it during cleanup */ 03162 user->keep = 1; 03163 03164 for (var = ast_variable_browse(ucfg, cat); var; var = var->next) { 03165 if (!strcasecmp(var->name, "secret")) { 03166 if (user->secret) { 03167 free(user->secret); 03168 } 03169 user->secret = ast_strdup(var->value); 03170 } else if (!strcasecmp(var->name, "deny") ) { 03171 if (user->deny) { 03172 free(user->deny); 03173 } 03174 user->deny = ast_strdup(var->value); 03175 } else if (!strcasecmp(var->name, "permit") ) { 03176 if (user->permit) { 03177 free(user->permit); 03178 } 03179 user->permit = ast_strdup(var->value); 03180 } else if (!strcasecmp(var->name, "read") ) { 03181 if (user->read) { 03182 free(user->read); 03183 } 03184 user->read = ast_strdup(var->value); 03185 } else if (!strcasecmp(var->name, "write") ) { 03186 if (user->write) { 03187 free(user->write); 03188 } 03189 user->write = ast_strdup(var->value); 03190 } else if (!strcasecmp(var->name, "displayconnects") ) { 03191 user->displayconnects = ast_true(var->value); 03192 } else if (!strcasecmp(var->name, "hasmanager")) { 03193 /* already handled */ 03194 } else { 03195 ast_log(LOG_DEBUG, "%s is an unknown option (to the manager module).\n", var->name); 03196 } 03197 } 03198 } 03199 ast_config_destroy(ucfg); 03200 } 03201 03202 while ((cat = ast_category_browse(cfg, cat))) { 03203 struct ast_variable *var = NULL; 03204 03205 if (!strcasecmp(cat, "general")) 03206 continue; 03207 03208 /* Look for an existing entry, if none found - create one and add it to the list */ 03209 if (!(user = ast_get_manager_by_name_locked(cat))) { 03210 if (!(user = ast_calloc(1, sizeof(*user)))) 03211 break; 03212 /* Copy name over */ 03213 ast_copy_string(user->username, cat, sizeof(user->username)); 03214 /* Insert into list */ 03215 AST_LIST_INSERT_TAIL(&users, user, list); 03216 } 03217 03218 /* Make sure we keep this user and don't destroy it during cleanup */ 03219 user->keep = 1; 03220 03221 var = ast_variable_browse(cfg, cat); 03222 while (var) { 03223 if (!strcasecmp(var->name, "secret")) { 03224 if (user->secret) 03225 free(user->secret); 03226 user->secret = ast_strdup(var->value); 03227 } else if (!strcasecmp(var->name, "deny") ) { 03228 if (user->deny) 03229 free(user->deny); 03230 user->deny = ast_strdup(var->value); 03231 } else if (!strcasecmp(var->name, "permit") ) { 03232 if (user->permit) 03233 free(user->permit); 03234 user->permit = ast_strdup(var->value); 03235 } else if (!strcasecmp(var->name, "read") ) { 03236 if (user->read) 03237 free(user->read); 03238 user->read = ast_strdup(var->value); 03239 } else if (!strcasecmp(var->name, "write") ) { 03240 if (user->write) 03241 free(user->write); 03242 user->write = ast_strdup(var->value); 03243 } else if (!strcasecmp(var->name, "displayconnects") ) 03244 user->displayconnects = ast_true(var->value); 03245 else 03246 ast_log(LOG_DEBUG, "%s is an unknown option.\n", var->name); 03247 var = var->next; 03248 } 03249 } 03250 03251 /* Perform cleanup - essentially prune out old users that no longer exist */ 03252 AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, list) { 03253 if (user->keep) { 03254 user->keep = 0; 03255 continue; 03256 } 03257 /* We do not need to keep this user so take them out of the list */ 03258 AST_LIST_REMOVE_CURRENT(&users, list); 03259 /* Free their memory now */ 03260 if (user->secret) 03261 free(user->secret); 03262 if (user->deny) 03263 free(user->deny); 03264 if (user->permit) 03265 free(user->permit); 03266 if (user->read) 03267 free(user->read); 03268 if (user->write) 03269 free(user->write); 03270 free(user); 03271 } 03272 AST_LIST_TRAVERSE_SAFE_END 03273 03274 AST_LIST_UNLOCK(&users); 03275 03276 ast_config_destroy(cfg); 03277 03278 if (webmanager_enabled && manager_enabled) { 03279 if (!webregged) { 03280 ast_http_uri_link(&rawmanuri); 03281 ast_http_uri_link(&manageruri); 03282 ast_http_uri_link(&managerxmluri); 03283 webregged = 1; 03284 } 03285 } else { 03286 if (webregged) { 03287 ast_http_uri_unlink(&rawmanuri); 03288 ast_http_uri_unlink(&manageruri); 03289 ast_http_uri_unlink(&managerxmluri); 03290 webregged = 0; 03291 } 03292 } 03293 03294 if (newhttptimeout > 0) 03295 httptimeout = newhttptimeout; 03296 03297 /* If not enabled, do nothing */ 03298 if (!manager_enabled) 03299 return 0; 03300 03301 if (asock < 0) { 03302 asock = socket(AF_INET, SOCK_STREAM, 0); 03303 if (asock < 0) { 03304 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno)); 03305 return -1; 03306 } 03307 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 03308 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) { 03309 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno)); 03310 close(asock); 03311 asock = -1; 03312 return -1; 03313 } 03314 if (listen(asock, 2)) { 03315 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno)); 03316 close(asock); 03317 asock = -1; 03318 return -1; 03319 } 03320 flags = fcntl(asock, F_GETFL); 03321 fcntl(asock, F_SETFL, flags | O_NONBLOCK); 03322 if (option_verbose) 03323 ast_verbose("Asterisk Management interface listening on port %d\n", portno); 03324 ast_pthread_create_background(&t, NULL, accept_thread, NULL); 03325 } 03326 return 0; 03327 }
int reload_manager | ( | void | ) |
Definition at line 3329 of file manager.c.
References EVENT_FLAG_SYSTEM, init_manager(), and manager_event().
03330 { 03331 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n"); 03332 return init_manager(); 03333 }