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