00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <pthread.h>
00017 #include <string.h>
00018 #include <sys/time.h>
00019 #include <sys/types.h>
00020 #include <netdb.h>
00021 #include <sys/socket.h>
00022 #include <netinet/in.h>
00023 #include <netinet/tcp.h>
00024 #include <arpa/inet.h>
00025 #include <signal.h>
00026 #include <errno.h>
00027 #include <unistd.h>
00028 #include <asterisk/channel.h>
00029 #include <asterisk/file.h>
00030 #include <asterisk/manager.h>
00031 #include <asterisk/config.h>
00032 #include <asterisk/lock.h>
00033 #include <asterisk/logger.h>
00034 #include <asterisk/options.h>
00035 #include <asterisk/cli.h>
00036 #include <asterisk/app.h>
00037 #include <asterisk/pbx.h>
00038 #include <asterisk/md5.h>
00039 #include <asterisk/acl.h>
00040
00041 static int enabled = 0;
00042 static int portno = DEFAULT_MANAGER_PORT;
00043 static int asock = -1;
00044 static pthread_t t;
00045 static ast_mutex_t sessionlock = AST_MUTEX_INITIALIZER;
00046
00047 static struct permalias {
00048 int num;
00049 char *label;
00050 } perms[] = {
00051 { EVENT_FLAG_SYSTEM, "system" },
00052 { EVENT_FLAG_CALL, "call" },
00053 { EVENT_FLAG_LOG, "log" },
00054 { EVENT_FLAG_VERBOSE, "verbose" },
00055 { EVENT_FLAG_COMMAND, "command" },
00056 { EVENT_FLAG_AGENT, "agent" },
00057 { EVENT_FLAG_USER, "user" },
00058 { -1, "all" },
00059 };
00060
00061 static struct mansession *sessions = NULL;
00062 static struct manager_action *first_action = NULL;
00063 static ast_mutex_t actionlock = AST_MUTEX_INITIALIZER;
00064
00065 static int handle_showmancmds(int fd, int argc, char *argv[])
00066 {
00067 struct manager_action *cur = first_action;
00068 char *format = " %-15.15s %-45.45s\n";
00069
00070 ast_mutex_lock(&actionlock);
00071 ast_cli(fd, format, "Action", "Synopsis");
00072 while(cur) {
00073 ast_cli(fd, format, cur->action, cur->synopsis);
00074 cur = cur->next;
00075 }
00076
00077 ast_mutex_unlock(&actionlock);
00078 return RESULT_SUCCESS;
00079 }
00080
00081 static int handle_showmanconn(int fd, int argc, char *argv[])
00082 {
00083 struct mansession *s;
00084 char *format = " %-15.15s %-15.15s\n";
00085 ast_mutex_lock(&sessionlock);
00086 s = sessions;
00087 ast_cli(fd, format, "Username", "IP Address");
00088 while(s) {
00089 ast_cli(fd, format,s->username, inet_ntoa(s->sin.sin_addr));
00090 s = s->next;
00091 }
00092
00093 ast_mutex_unlock(&sessionlock);
00094 return RESULT_SUCCESS;
00095 }
00096
00097 static char showmancmds_help[] =
00098 "Usage: show manager commands\n"
00099 " Prints a listing of all the available manager commands.\n";
00100
00101 static char showmanconn_help[] =
00102 "Usage: show manager connected\n"
00103 " Prints a listing of the users that are connected to the\n"
00104 "manager interface.\n";
00105
00106 static struct ast_cli_entry show_mancmds_cli =
00107 { { "show", "manager", "commands", NULL },
00108 handle_showmancmds, "Show manager commands", showmancmds_help };
00109
00110 static struct ast_cli_entry show_manconn_cli =
00111 { { "show", "manager", "connected", NULL },
00112 handle_showmanconn, "Show connected manager users", showmanconn_help };
00113
00114 static void destroy_session(struct mansession *s)
00115 {
00116 struct mansession *cur, *prev = NULL;
00117 ast_mutex_lock(&sessionlock);
00118 cur = sessions;
00119 while(cur) {
00120 if (cur == s)
00121 break;
00122 prev = cur;
00123 cur = cur->next;
00124 }
00125 if (cur) {
00126 if (prev)
00127 prev->next = cur->next;
00128 else
00129 sessions = cur->next;
00130 if (s->fd > -1)
00131 close(s->fd);
00132 free(s);
00133 } else
00134 ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s);
00135 ast_mutex_unlock(&sessionlock);
00136
00137 }
00138
00139 char *astman_get_header(struct message *m, char *var)
00140 {
00141 char cmp[80];
00142 int x;
00143 snprintf(cmp, sizeof(cmp), "%s: ", var);
00144 for (x=0;x<m->hdrcount;x++)
00145 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
00146 return m->headers[x] + strlen(cmp);
00147 return "";
00148 }
00149
00150 void astman_send_error(struct mansession *s, struct message *m, char *error)
00151 {
00152 char *id = astman_get_header(m,"ActionID");
00153 ast_mutex_lock(&s->lock);
00154 ast_cli(s->fd, "Response: Error\r\n");
00155 if (id && strlen(id))
00156 ast_cli(s->fd, "ActionID: %s\r\n",id);
00157 ast_cli(s->fd, "Message: %s\r\n\r\n", error);
00158 ast_mutex_unlock(&s->lock);
00159 }
00160
00161 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
00162 {
00163 char *id = astman_get_header(m,"ActionID");
00164 ast_mutex_lock(&s->lock);
00165 ast_cli(s->fd, "Response: %s\r\n", resp);
00166 if (id && strlen(id))
00167 ast_cli(s->fd, "ActionID: %s\r\n",id);
00168 if (msg)
00169 ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
00170 else
00171 ast_cli(s->fd, "\r\n");
00172 ast_mutex_unlock(&s->lock);
00173 }
00174
00175 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
00176 {
00177 astman_send_response(s, m, "Success", msg);
00178 }
00179
00180 static int get_perm(char *instr)
00181 {
00182 char tmp[256];
00183 char *c;
00184 int x;
00185 int ret = 0;
00186 char *stringp=NULL;
00187 if (!instr)
00188 return 0;
00189 strncpy(tmp, instr, sizeof(tmp) - 1);
00190 stringp=tmp;
00191 c = strsep(&stringp, ",");
00192 while(c) {
00193 for (x=0;x<sizeof(perms) / sizeof(perms[0]);x++) {
00194 if (!strcasecmp(perms[x].label, c))
00195 ret |= perms[x].num;
00196 }
00197 c = strsep(&stringp, ",");
00198 }
00199 return ret;
00200 }
00201
00202 static int authenticate(struct mansession *s, struct message *m)
00203 {
00204 struct ast_config *cfg;
00205 char *cat;
00206 char *user = astman_get_header(m, "Username");
00207 char *pass = astman_get_header(m, "Secret");
00208 char *authtype = astman_get_header(m, "AuthType");
00209 char *key = astman_get_header(m, "Key");
00210
00211 cfg = ast_load("manager.conf");
00212 if (!cfg)
00213 return -1;
00214 cat = ast_category_browse(cfg, NULL);
00215 while(cat) {
00216 if (strcasecmp(cat, "general")) {
00217
00218 if (!strcasecmp(cat, user)) {
00219 struct ast_variable *v;
00220 struct ast_ha *ha = NULL;
00221 char *password = NULL;
00222 v = ast_variable_browse(cfg, cat);
00223 while (v) {
00224 if (!strcasecmp(v->name, "secret")) {
00225 password = v->value;
00226 } else if (!strcasecmp(v->name, "permit") ||
00227 !strcasecmp(v->name, "deny")) {
00228 ha = ast_append_ha(v->name, v->value, ha);
00229 }
00230 v = v->next;
00231 }
00232 if (ha && !ast_apply_ha(ha, &(s->sin))) {
00233 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", inet_ntoa(s->sin.sin_addr), user);
00234 ast_free_ha(ha);
00235 ast_destroy(cfg);
00236 return -1;
00237 } else if (ha)
00238 ast_free_ha(ha);
00239 if (!strcasecmp(authtype, "MD5")) {
00240 if (key && strlen(key) && s->challenge) {
00241 int x;
00242 int len=0;
00243 char md5key[256] = "";
00244 struct MD5Context md5;
00245 unsigned char digest[16];
00246 MD5Init(&md5);
00247 MD5Update(&md5, s->challenge, strlen(s->challenge));
00248 MD5Update(&md5, password, strlen(password));
00249 MD5Final(digest, &md5);
00250 for (x=0;x<16;x++)
00251 len += sprintf(md5key + len, "%2.2x", digest[x]);
00252 if (!strcmp(md5key, key))
00253 break;
00254 else {
00255 ast_destroy(cfg);
00256 return -1;
00257 }
00258 }
00259 } else if (password && !strcasecmp(password, pass)) {
00260 break;
00261 } else {
00262 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", inet_ntoa(s->sin.sin_addr), user);
00263 ast_destroy(cfg);
00264 return -1;
00265 }
00266 }
00267 }
00268 cat = ast_category_browse(cfg, cat);
00269 }
00270 if (cat) {
00271 strncpy(s->username, cat, sizeof(s->username) - 1);
00272 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
00273 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
00274 ast_destroy(cfg);
00275 return 0;
00276 }
00277 ast_log(LOG_NOTICE, "%s tried to authenticate with non-existant user '%s'\n", inet_ntoa(s->sin.sin_addr), user);
00278 ast_destroy(cfg);
00279 return -1;
00280 }
00281
00282 static int action_ping(struct mansession *s, struct message *m)
00283 {
00284 astman_send_response(s, m, "Pong", NULL);
00285 return 0;
00286 }
00287
00288 static int action_logoff(struct mansession *s, struct message *m)
00289 {
00290 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
00291 return -1;
00292 }
00293
00294 static int action_hangup(struct mansession *s, struct message *m)
00295 {
00296 struct ast_channel *c = NULL;
00297 char *name = astman_get_header(m, "Channel");
00298 if (!strlen(name)) {
00299 astman_send_error(s, m, "No channel specified");
00300 return 0;
00301 }
00302 c = ast_channel_walk(NULL);
00303 while(c) {
00304 if (!strcasecmp(c->name, name)) {
00305 break;
00306 }
00307 c = ast_channel_walk(c);
00308 }
00309 if (!c) {
00310 astman_send_error(s, m, "No such channel");
00311 return 0;
00312 }
00313 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
00314 astman_send_ack(s, m, "Channel Hungup");
00315 return 0;
00316 }
00317
00318 static int action_status(struct mansession *s, struct message *m)
00319 {
00320 char *id = astman_get_header(m,"ActionID");
00321 char idText[256] = "";
00322 struct ast_channel *c;
00323 char bridge[256];
00324 astman_send_ack(s, m, "Channel status will follow");
00325 c = ast_channel_walk(NULL);
00326 if (id && strlen(id))
00327 snprintf(idText,256,"ActionID: %s\r\n",id);
00328 while(c) {
00329 if (c->bridge)
00330 snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->bridge->name);
00331 else
00332 strcpy(bridge, "");
00333 if (c->pbx) {
00334 ast_cli(s->fd,
00335 "Event: Status\r\n"
00336 "Channel: %s\r\n"
00337 "CallerID: %s\r\n"
00338 "State: %s\r\n"
00339 "Context: %s\r\n"
00340 "Extension: %s\r\n"
00341 "Priority: %d\r\n"
00342 "%s"
00343 "Uniqueid: %s\r\n"
00344 "%s"
00345 "\r\n",
00346 c->name, c->callerid ? c->callerid : "<unknown>",
00347 ast_state2str(c->_state), c->context,
00348 c->exten, c->priority, bridge, c->uniqueid, idText);
00349 } else {
00350 ast_cli(s->fd,
00351 "Event: Status\r\n"
00352 "Channel: %s\r\n"
00353 "CallerID: %s\r\n"
00354 "State: %s\r\n"
00355 "%s"
00356 "Uniqueid: %s\r\n"
00357 "%s"
00358 "\r\n",
00359 c->name, c->callerid ? c->callerid : "<unknown>",
00360 ast_state2str(c->_state), bridge, c->uniqueid, idText);
00361 }
00362 c = ast_channel_walk(c);
00363 }
00364 ast_cli(s->fd,
00365 "Event: StatusComplete\r\n"
00366 "%s"
00367 "\r\n",idText);
00368 return 0;
00369 }
00370
00371 static int action_redirect(struct mansession *s, struct message *m)
00372 {
00373 char *name = astman_get_header(m, "Channel");
00374 char *name2 = astman_get_header(m, "ExtraChannel");
00375 char *exten = astman_get_header(m, "Exten");
00376 char *context = astman_get_header(m, "Context");
00377 char *priority = astman_get_header(m, "Priority");
00378 int pi = 0;
00379 int res;
00380 if (!name || !strlen(name)) {
00381 astman_send_error(s, m, "Channel not specified");
00382 return 0;
00383 }
00384 if (strlen(priority) && (sscanf(priority, "%d", &pi) != 1)) {
00385 astman_send_error(s, m, "Invalid priority\n");
00386 return 0;
00387 }
00388 res = ast_async_goto_by_name(name, context, exten, pi);
00389 if (!res) {
00390 if (strlen(name2)) {
00391 res = ast_async_goto_by_name(name2, context, exten, pi);
00392 if (!res)
00393 astman_send_ack(s, m, "Dual Redirect successful");
00394 else
00395 astman_send_error(s, m, "Secondary redirect failed");
00396 } else
00397 astman_send_ack(s, m, "Redirect successful");
00398 } else
00399 astman_send_error(s, m, "Redirect failed");
00400 return 0;
00401 }
00402
00403 static int action_command(struct mansession *s, struct message *m)
00404 {
00405 char *cmd = astman_get_header(m, "Command");
00406 ast_mutex_lock(&s->lock);
00407 s->blocking = 1;
00408 ast_mutex_unlock(&s->lock);
00409 ast_cli(s->fd, "Response: Follows\r\n");
00410
00411 ast_cli_command(s->fd, cmd);
00412 ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
00413 ast_mutex_lock(&s->lock);
00414 s->blocking = 0;
00415 ast_mutex_unlock(&s->lock);
00416 return 0;
00417 }
00418
00419 static int action_originate(struct mansession *s, struct message *m)
00420 {
00421 char *name = astman_get_header(m, "Channel");
00422 char *exten = astman_get_header(m, "Exten");
00423 char *context = astman_get_header(m, "Context");
00424 char *priority = astman_get_header(m, "Priority");
00425 char *timeout = astman_get_header(m, "Timeout");
00426 char *callerid = astman_get_header(m, "CallerID");
00427 char *variable = astman_get_header(m, "Variable");
00428 char *account = astman_get_header(m, "Account");
00429 char *app = astman_get_header(m, "Application");
00430 char *appdata = astman_get_header(m, "Data");
00431 char *tech, *data;
00432 int pi = 0;
00433 int res;
00434 int to = 30000;
00435 int reason = 0;
00436 char tmp[256];
00437 if (!name) {
00438 astman_send_error(s, m, "Channel not specified");
00439 return 0;
00440 }
00441 if (strlen(priority) && (sscanf(priority, "%d", &pi) != 1)) {
00442 astman_send_error(s, m, "Invalid priority\n");
00443 return 0;
00444 }
00445 if (strlen(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
00446 astman_send_error(s, m, "Invalid timeout\n");
00447 return 0;
00448 }
00449 strncpy(tmp, name, sizeof(tmp) - 1);
00450 tech = tmp;
00451 data = strchr(tmp, '/');
00452 if (!data) {
00453 astman_send_error(s, m, "Invalid channel\n");
00454 return 0;
00455 }
00456 *data = '\0';
00457 data++;
00458 if (strlen(app)) {
00459 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 0, strlen(callerid) ? callerid : NULL, variable, account);
00460 } else {
00461 res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 0, strlen(callerid) ? callerid : NULL, variable, account);
00462 }
00463 if (!res)
00464 astman_send_ack(s, m, "Originate successfully queued");
00465 else
00466 astman_send_error(s, m, "Originate failed");
00467 return 0;
00468 }
00469
00470 static int action_mailboxstatus(struct mansession *s, struct message *m)
00471 {
00472 char *mailbox = astman_get_header(m, "Mailbox");
00473 char *id = astman_get_header(m,"ActionID");
00474 char idText[256] = "";
00475 if (!mailbox || !strlen(mailbox)) {
00476 astman_send_error(s, m, "Mailbox not specified");
00477 return 0;
00478 }
00479 if (id && strlen(id))
00480 snprintf(idText,256,"ActionID: %s\r\n",id);
00481 ast_cli(s->fd, "Response: Success\r\n"
00482 "%s"
00483 "Message: Mailbox Status\r\n"
00484 "Mailbox: %s\r\n"
00485 "Waiting: %d\r\n\r\n", idText, mailbox, ast_app_has_voicemail(mailbox));
00486 return 0;
00487 }
00488
00489 static int action_mailboxcount(struct mansession *s, struct message *m)
00490 {
00491 char *mailbox = astman_get_header(m, "Mailbox");
00492 char *id = astman_get_header(m,"ActionID");
00493 char idText[256] = "";
00494 int newmsgs = 0, oldmsgs = 0;
00495 if (!mailbox || !strlen(mailbox)) {
00496 astman_send_error(s, m, "Mailbox not specified");
00497 return 0;
00498 }
00499 ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
00500 if (id && strlen(id)) {
00501 snprintf(idText,256,"ActionID: %s\r\n",id);
00502 }
00503 ast_cli(s->fd, "Response: Success\r\n"
00504 "%s"
00505 "Message: Mailbox Message Count\r\n"
00506 "Mailbox: %s\r\n"
00507 "NewMessages: %d\r\n"
00508 "OldMessages: %d\r\n"
00509 "\r\n",
00510 idText,mailbox, newmsgs, oldmsgs);
00511 return 0;
00512 }
00513
00514 static int action_extensionstate(struct mansession *s, struct message *m)
00515 {
00516 char *exten = astman_get_header(m, "Exten");
00517 char *context = astman_get_header(m, "Context");
00518 char *id = astman_get_header(m,"ActionID");
00519 char idText[256] = "";
00520 char hint[256] = "";
00521 int status;
00522 if (!exten || !strlen(exten)) {
00523 astman_send_error(s, m, "Extension not specified");
00524 return 0;
00525 }
00526 if (!context || !strlen(context))
00527 context = "default";
00528 status = ast_extension_state(NULL, context, exten);
00529 ast_get_hint(hint, sizeof(hint) - 1, NULL, context, exten);
00530 if (id && strlen(id)) {
00531 snprintf(idText,256,"ActionID: %s\r\n",id);
00532 }
00533 ast_cli(s->fd, "Response: Success\r\n"
00534 "%s"
00535 "Message: Extension Status\r\n"
00536 "Exten: %s\r\n"
00537 "Context: %s\r\n"
00538 "Hint: %s\r\n"
00539 "Status: %d\r\n\r\n",
00540 idText,exten, context, hint, status);
00541 return 0;
00542 }
00543
00544 static int action_timeout(struct mansession *s, struct message *m)
00545 {
00546 struct ast_channel *c = NULL;
00547 char *name = astman_get_header(m, "Channel");
00548 int timeout = atoi(astman_get_header(m, "Timeout"));
00549 if (!strlen(name)) {
00550 astman_send_error(s, m, "No channel specified");
00551 return 0;
00552 }
00553 if (!timeout) {
00554 astman_send_error(s, m, "No timeout specified");
00555 return 0;
00556 }
00557 c = ast_channel_walk(NULL);
00558 while(c) {
00559 if (!strcasecmp(c->name, name)) {
00560 break;
00561 }
00562 c = ast_channel_walk(c);
00563 }
00564 if (!c) {
00565 astman_send_error(s, m, "No such channel");
00566 return 0;
00567 }
00568 ast_channel_setwhentohangup(c, timeout);
00569 astman_send_ack(s, m, "Timeout Set");
00570 return 0;
00571 }
00572
00573 static int process_message(struct mansession *s, struct message *m)
00574 {
00575 char action[80];
00576 struct manager_action *tmp = first_action;
00577 char *id = astman_get_header(m,"ActionID");
00578 char idText[256] = "";
00579
00580 strncpy(action, astman_get_header(m, "Action"), sizeof(action));
00581 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
00582
00583 if (!strlen(action)) {
00584 astman_send_error(s, m, "Missing action in request");
00585 return 0;
00586 }
00587 if (id && strlen(id)) {
00588 snprintf(idText,256,"ActionID: %s\r\n",id);
00589 }
00590 if (!s->authenticated) {
00591 if (!strcasecmp(action, "Challenge")) {
00592 char *authtype;
00593 authtype = astman_get_header(m, "AuthType");
00594 if (!strcasecmp(authtype, "MD5")) {
00595 if (!s->challenge || !strlen(s->challenge)) {
00596 ast_mutex_lock(&s->lock);
00597 snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
00598 ast_mutex_unlock(&s->lock);
00599 }
00600 ast_cli(s->fd, "Response: Success\r\n"
00601 "%s"
00602 "Challenge: %s\r\n\r\n",
00603 idText,s->challenge);
00604 return 0;
00605 } else {
00606 astman_send_error(s, m, "Must specify AuthType");
00607 return 0;
00608 }
00609 } else if (!strcasecmp(action, "Login")) {
00610 if (authenticate(s, m)) {
00611 sleep(1);
00612 astman_send_error(s, m, "Authentication failed");
00613 return -1;
00614 } else {
00615 s->authenticated = 1;
00616 if (option_verbose > 1)
00617 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
00618 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
00619 astman_send_ack(s, m, "Authentication accepted");
00620 }
00621 } else if (!strcasecmp(action, "Logoff")) {
00622 astman_send_ack(s, m, "See ya");
00623 return -1;
00624 } else
00625 astman_send_error(s, m, "Authentication Required");
00626 } else {
00627 while( tmp ) {
00628 if (!strcasecmp(action, tmp->action)) {
00629 if ((s->writeperm & tmp->authority) == tmp->authority) {
00630 if (tmp->func(s, m))
00631 return -1;
00632 } else {
00633 astman_send_error(s, m, "Permission denied");
00634 }
00635 return 0;
00636 }
00637 tmp = tmp->next;
00638 }
00639 astman_send_error(s, m, "Invalid/unknown command");
00640 }
00641 return 0;
00642 }
00643
00644 static int get_input(struct mansession *s, char *output)
00645 {
00646
00647 int res;
00648 int x;
00649 fd_set fds;
00650 for (x=1;x<s->inlen;x++) {
00651 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
00652
00653 memcpy(output, s->inbuf, x + 1);
00654
00655 output[x+1] = '\0';
00656
00657 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
00658 s->inlen -= (x + 1);
00659 return 1;
00660 }
00661 }
00662 if (s->inlen >= sizeof(s->inbuf) - 1) {
00663 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
00664 s->inlen = 0;
00665 }
00666 FD_ZERO(&fds);
00667 FD_SET(s->fd, &fds);
00668 res = ast_select(s->fd + 1, &fds, NULL, NULL, NULL);
00669 if (res < 0) {
00670 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
00671 } else if (res > 0) {
00672 ast_mutex_lock(&s->lock);
00673 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
00674 ast_mutex_unlock(&s->lock);
00675 if (res < 1)
00676 return -1;
00677 }
00678 s->inlen += res;
00679 s->inbuf[s->inlen] = '\0';
00680 return 0;
00681 }
00682
00683 static void *session_do(void *data)
00684 {
00685 struct mansession *s = data;
00686 struct message m;
00687 int res;
00688
00689 ast_mutex_lock(&s->lock);
00690 ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
00691 ast_mutex_unlock(&s->lock);
00692 memset(&m, 0, sizeof(&m));
00693 for (;;) {
00694 res = get_input(s, m.headers[m.hdrcount]);
00695 if (res > 0) {
00696
00697 if (strlen(m.headers[m.hdrcount]) < 2)
00698 continue;
00699 m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
00700 if (!strlen(m.headers[m.hdrcount])) {
00701 if (process_message(s, &m))
00702 break;
00703 memset(&m, 0, sizeof(&m));
00704 } else if (m.hdrcount < MAX_HEADERS - 1)
00705 m.hdrcount++;
00706 } else if (res < 0)
00707 break;
00708 }
00709 if (s->authenticated) {
00710 if (option_verbose > 1)
00711 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
00712 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
00713 } else {
00714 if (option_verbose > 1)
00715 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", inet_ntoa(s->sin.sin_addr));
00716 ast_log(LOG_EVENT, "Failed attempt from %s\n", inet_ntoa(s->sin.sin_addr));
00717 }
00718 destroy_session(s);
00719 return NULL;
00720 }
00721
00722 static void *accept_thread(void *ignore)
00723 {
00724 int as;
00725 struct sockaddr_in sin;
00726 int sinlen;
00727 struct mansession *s;
00728 struct protoent *p;
00729 int arg = 1;
00730 pthread_attr_t attr;
00731
00732 pthread_attr_init(&attr);
00733 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00734
00735 for (;;) {
00736 sinlen = sizeof(sin);
00737 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
00738 if (as < 0) {
00739 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
00740 continue;
00741 }
00742 p = getprotobyname("tcp");
00743 if( p ) {
00744 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
00745 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
00746 }
00747 }
00748 s = malloc(sizeof(struct mansession));
00749 if (!s) {
00750 ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
00751 continue;
00752 }
00753 memset(s, 0, sizeof(struct mansession));
00754 memcpy(&s->sin, &sin, sizeof(sin));
00755 ast_mutex_init(&s->lock);
00756 s->fd = as;
00757 ast_mutex_lock(&sessionlock);
00758 s->next = sessions;
00759 sessions = s;
00760 ast_mutex_unlock(&sessionlock);
00761 if (pthread_create(&t, &attr, session_do, s))
00762 destroy_session(s);
00763 }
00764 pthread_attr_destroy(&attr);
00765 return NULL;
00766 }
00767
00768 int manager_event(int category, char *event, char *fmt, ...)
00769 {
00770 struct mansession *s;
00771 char tmp[4096];
00772 va_list ap;
00773
00774 ast_mutex_lock(&sessionlock);
00775 s = sessions;
00776 while(s) {
00777 if ((s->readperm & category) == category) {
00778 ast_mutex_lock(&s->lock);
00779 if (!s->blocking) {
00780 ast_cli(s->fd, "Event: %s\r\n", event);
00781 va_start(ap, fmt);
00782 vsnprintf(tmp, sizeof(tmp), fmt, ap);
00783 va_end(ap);
00784 write(s->fd, tmp, strlen(tmp));
00785 ast_cli(s->fd, "\r\n");
00786 }
00787 ast_mutex_unlock(&s->lock);
00788 }
00789 s = s->next;
00790 }
00791 ast_mutex_unlock(&sessionlock);
00792 return 0;
00793 }
00794
00795 int ast_manager_unregister( char *action ) {
00796 struct manager_action *cur = first_action, *prev = first_action;
00797
00798 ast_mutex_lock(&actionlock);
00799 while( cur ) {
00800 if (!strcasecmp(action, cur->action)) {
00801 prev->next = cur->next;
00802 free(cur);
00803 if (option_verbose > 1)
00804 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
00805 ast_mutex_unlock(&actionlock);
00806 return 0;
00807 }
00808 prev = cur;
00809 cur = cur->next;
00810 }
00811 ast_mutex_unlock(&actionlock);
00812 return 0;
00813 }
00814
00815 static int manager_state_cb(char *context, char *exten, int state, void *data)
00816 {
00817
00818 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
00819 return 0;
00820 }
00821
00822 int ast_manager_register( char *action, int auth,
00823 int (*func)(struct mansession *s, struct message *m), char *synopsis)
00824 {
00825 struct manager_action *cur = first_action, *prev = NULL;
00826
00827 ast_mutex_lock(&actionlock);
00828 while(cur) {
00829 if (!strcasecmp(cur->action, action)) {
00830 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", action);
00831 ast_mutex_unlock(&actionlock);
00832 return -1;
00833 }
00834 prev = cur;
00835 cur = cur->next;
00836 }
00837 cur = malloc( sizeof(struct manager_action) );
00838 if( !cur ) {
00839 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
00840 ast_mutex_unlock(&actionlock);
00841 return -1;
00842 }
00843 strncpy( cur->action, action, 255 );
00844 cur->authority = auth;
00845 cur->func = func;
00846 cur->synopsis = synopsis;
00847 cur->next = NULL;
00848
00849 if( prev ) prev->next = cur;
00850 else first_action = cur;
00851
00852 if (option_verbose > 1)
00853 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", action);
00854 ast_mutex_unlock(&actionlock);
00855 return 0;
00856 }
00857
00858 static int registered = 0;
00859
00860 int init_manager(void)
00861 {
00862 struct ast_config *cfg;
00863 char *val;
00864 int oldportno = portno;
00865 static struct sockaddr_in ba;
00866 int x = 1;
00867 if (!registered) {
00868
00869 ast_manager_register( "Ping", 0, action_ping, "Ping" );
00870 ast_manager_register( "Logoff", 0, action_logoff, "Logoff Manager" );
00871 ast_manager_register( "Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel" );
00872 ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" );
00873 ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect" );
00874 ast_manager_register( "Originate", EVENT_FLAG_CALL, action_originate, "Originate Call" );
00875 ast_manager_register( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox" );
00876 ast_manager_register( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command" );
00877 ast_manager_register( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status" );
00878 ast_manager_register( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout" );
00879 ast_manager_register( "MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count" );
00880
00881 ast_cli_register(&show_mancmds_cli);
00882 ast_cli_register(&show_manconn_cli);
00883 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
00884 registered = 1;
00885 }
00886 portno = DEFAULT_MANAGER_PORT;
00887 cfg = ast_load("manager.conf");
00888 if (!cfg) {
00889 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
00890 return 0;
00891 }
00892 memset(&ba, 0, sizeof(ba));
00893 val = ast_variable_retrieve(cfg, "general", "enabled");
00894 if (val)
00895 enabled = ast_true(val);
00896
00897 if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
00898 if (sscanf(val, "%d", &portno) != 1) {
00899 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
00900 portno = DEFAULT_MANAGER_PORT;
00901 }
00902 }
00903
00904 ba.sin_family = AF_INET;
00905 ba.sin_port = htons(portno);
00906 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
00907
00908 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
00909 if (!inet_aton(val, &ba.sin_addr)) {
00910 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
00911 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
00912 }
00913 }
00914
00915 if ((asock > -1) && ((portno != oldportno) || !enabled)) {
00916 #if 0
00917
00918 close(asock);
00919 asock = -1;
00920 #else
00921 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
00922 #endif
00923 }
00924 ast_destroy(cfg);
00925
00926
00927 if (!enabled) {
00928 return 0;
00929 }
00930 if (asock < 0) {
00931 asock = socket(AF_INET, SOCK_STREAM, 0);
00932 if (asock < 0) {
00933 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
00934 return -1;
00935 }
00936 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
00937 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
00938 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
00939 close(asock);
00940 asock = -1;
00941 return -1;
00942 }
00943 if (listen(asock, 2)) {
00944 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
00945 close(asock);
00946 asock = -1;
00947 return -1;
00948 }
00949 if (option_verbose)
00950 ast_verbose("Asterisk Management interface listening on port %d\n", portno);
00951 pthread_create(&t, NULL, accept_thread, NULL);
00952 }
00953 return 0;
00954 }
00955
00956 int reload_manager(void)
00957 {
00958 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
00959 return init_manager();
00960 }