manager.c 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * The Asterisk Management Interface - AMI
  5. *
  6. * Channel Management and more
  7. *
  8. * Copyright (C) 1999-2004, Digium, Inc.
  9. *
  10. * Mark Spencer <markster@digium.com>
  11. *
  12. * This program is free software, distributed under the terms of
  13. * the GNU General Public License
  14. */
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <sys/time.h>
  19. #include <sys/types.h>
  20. #include <netdb.h>
  21. #include <sys/socket.h>
  22. #include <netinet/in.h>
  23. #include <netinet/tcp.h>
  24. #include <arpa/inet.h>
  25. #include <signal.h>
  26. #include <errno.h>
  27. #include <unistd.h>
  28. #include <sys/poll.h>
  29. #include <asterisk/channel.h>
  30. #include <asterisk/file.h>
  31. #include <asterisk/manager.h>
  32. #include <asterisk/config.h>
  33. #include <asterisk/lock.h>
  34. #include <asterisk/logger.h>
  35. #include <asterisk/options.h>
  36. #include <asterisk/cli.h>
  37. #include <asterisk/app.h>
  38. #include <asterisk/pbx.h>
  39. #include <asterisk/md5.h>
  40. #include <asterisk/acl.h>
  41. #include <asterisk/utils.h>
  42. struct fast_originate_helper
  43. {
  44. char tech[256];
  45. char data[256];
  46. int timeout;
  47. char app[256];
  48. char appdata[256];
  49. char callerid[256];
  50. char variable[256];
  51. char account[256];
  52. char context[256];
  53. char exten[256];
  54. char idtext[256];
  55. int priority;
  56. };
  57. static int enabled = 0;
  58. static int portno = DEFAULT_MANAGER_PORT;
  59. static int asock = -1;
  60. static pthread_t t;
  61. AST_MUTEX_DEFINE_STATIC(sessionlock);
  62. static int block_sockets = 0;
  63. static struct permalias {
  64. int num;
  65. char *label;
  66. } perms[] = {
  67. { EVENT_FLAG_SYSTEM, "system" },
  68. { EVENT_FLAG_CALL, "call" },
  69. { EVENT_FLAG_LOG, "log" },
  70. { EVENT_FLAG_VERBOSE, "verbose" },
  71. { EVENT_FLAG_COMMAND, "command" },
  72. { EVENT_FLAG_AGENT, "agent" },
  73. { EVENT_FLAG_USER, "user" },
  74. { -1, "all" },
  75. };
  76. static struct mansession *sessions = NULL;
  77. static struct manager_action *first_action = NULL;
  78. AST_MUTEX_DEFINE_STATIC(actionlock);
  79. int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
  80. {
  81. /* Try to write string, but wait no more than ms milliseconds
  82. before timing out */
  83. int res=0;
  84. struct pollfd fds[1];
  85. while(len) {
  86. res = write(fd, s, len);
  87. if ((res < 0) && (errno != EAGAIN)) {
  88. return -1;
  89. }
  90. if (res < 0) res = 0;
  91. len -= res;
  92. s += res;
  93. fds[0].fd = fd;
  94. fds[0].events = POLLOUT;
  95. /* Wait until writable again */
  96. res = poll(fds, 1, timeoutms);
  97. if (res < 1)
  98. return -1;
  99. }
  100. return res;
  101. }
  102. static char *authority_to_str(int authority, char *res, int reslen)
  103. {
  104. int running_total = 0, i;
  105. memset(res, 0, reslen);
  106. for (i=0; i<sizeof(perms) / sizeof(perms[0]) - 1; i++) {
  107. if (authority & perms[i].num) {
  108. if (*res) {
  109. strncat(res, ",", (reslen > running_total) ? reslen - running_total : 0);
  110. running_total++;
  111. }
  112. strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total : 0);
  113. running_total += strlen(perms[i].label);
  114. }
  115. }
  116. if (ast_strlen_zero(res)) {
  117. strncpy(res, "<none>", reslen);
  118. }
  119. return res;
  120. }
  121. static char *complete_show_mancmd(char *line, char *word, int pos, int state)
  122. {
  123. struct manager_action *cur = first_action;
  124. int which = 0;
  125. ast_mutex_lock(&actionlock);
  126. while (cur) { /* Walk the list of actions */
  127. if (!strncasecmp(word, cur->action, strlen(word))) {
  128. if (++which > state) {
  129. char *ret = strdup(cur->action);
  130. ast_mutex_unlock(&actionlock);
  131. return ret;
  132. }
  133. }
  134. cur = cur->next;
  135. }
  136. ast_mutex_unlock(&actionlock);
  137. return NULL;
  138. }
  139. static int handle_showmancmd(int fd, int argc, char *argv[])
  140. {
  141. struct manager_action *cur = first_action;
  142. char authority[80];
  143. int num;
  144. if (argc != 4)
  145. return RESULT_SHOWUSAGE;
  146. ast_mutex_lock(&actionlock);
  147. while (cur) { /* Walk the list of actions */
  148. for (num = 3; num < argc; num++) {
  149. if (!strcasecmp(cur->action, argv[num])) {
  150. ast_cli(fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n", cur->action, cur->synopsis, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->description ? cur->description : "");
  151. }
  152. }
  153. cur = cur->next;
  154. }
  155. ast_mutex_unlock(&actionlock);
  156. return RESULT_SUCCESS;
  157. }
  158. static int handle_showmancmds(int fd, int argc, char *argv[])
  159. {
  160. struct manager_action *cur = first_action;
  161. char authority[80];
  162. char *format = " %-15.15s %-10.10s %-45.45s\n";
  163. ast_mutex_lock(&actionlock);
  164. ast_cli(fd, format, "Action", "Privilege", "Synopsis");
  165. while (cur) { /* Walk the list of actions */
  166. ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
  167. cur = cur->next;
  168. }
  169. ast_mutex_unlock(&actionlock);
  170. return RESULT_SUCCESS;
  171. }
  172. static int handle_showmanconn(int fd, int argc, char *argv[])
  173. {
  174. struct mansession *s;
  175. char iabuf[INET_ADDRSTRLEN];
  176. char *format = " %-15.15s %-15.15s\n";
  177. ast_mutex_lock(&sessionlock);
  178. s = sessions;
  179. ast_cli(fd, format, "Username", "IP Address");
  180. while (s) {
  181. ast_cli(fd, format,s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  182. s = s->next;
  183. }
  184. ast_mutex_unlock(&sessionlock);
  185. return RESULT_SUCCESS;
  186. }
  187. static char showmancmd_help[] =
  188. "Usage: show manager command <actionname>\n"
  189. " Shows the detailed description for a specific manager command.\n";
  190. static char showmancmds_help[] =
  191. "Usage: show manager commands\n"
  192. " Prints a listing of all the available manager commands.\n";
  193. static char showmanconn_help[] =
  194. "Usage: show manager connected\n"
  195. " Prints a listing of the users that are connected to the\n"
  196. "manager interface.\n";
  197. static struct ast_cli_entry show_mancmd_cli =
  198. { { "show", "manager", "command", NULL },
  199. handle_showmancmd, "Show manager command", showmancmd_help, complete_show_mancmd };
  200. static struct ast_cli_entry show_mancmds_cli =
  201. { { "show", "manager", "commands", NULL },
  202. handle_showmancmds, "Show manager commands", showmancmds_help };
  203. static struct ast_cli_entry show_manconn_cli =
  204. { { "show", "manager", "connected", NULL },
  205. handle_showmanconn, "Show connected manager users", showmanconn_help };
  206. static void destroy_session(struct mansession *s)
  207. {
  208. struct mansession *cur, *prev = NULL;
  209. ast_mutex_lock(&sessionlock);
  210. cur = sessions;
  211. while(cur) {
  212. if (cur == s)
  213. break;
  214. prev = cur;
  215. cur = cur->next;
  216. }
  217. if (cur) {
  218. if (prev)
  219. prev->next = cur->next;
  220. else
  221. sessions = cur->next;
  222. if (s->fd > -1)
  223. close(s->fd);
  224. ast_mutex_destroy(&s->lock);
  225. free(s);
  226. } else
  227. ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
  228. ast_mutex_unlock(&sessionlock);
  229. }
  230. char *astman_get_header(struct message *m, char *var)
  231. {
  232. char cmp[80];
  233. int x;
  234. snprintf(cmp, sizeof(cmp), "%s: ", var);
  235. for (x=0;x<m->hdrcount;x++)
  236. if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
  237. return m->headers[x] + strlen(cmp);
  238. return "";
  239. }
  240. void astman_send_error(struct mansession *s, struct message *m, char *error)
  241. {
  242. char *id = astman_get_header(m,"ActionID");
  243. ast_mutex_lock(&s->lock);
  244. ast_cli(s->fd, "Response: Error\r\n");
  245. if (id && !ast_strlen_zero(id))
  246. ast_cli(s->fd, "ActionID: %s\r\n",id);
  247. ast_cli(s->fd, "Message: %s\r\n\r\n", error);
  248. ast_mutex_unlock(&s->lock);
  249. }
  250. void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
  251. {
  252. char *id = astman_get_header(m,"ActionID");
  253. ast_mutex_lock(&s->lock);
  254. ast_cli(s->fd, "Response: %s\r\n", resp);
  255. if (id && !ast_strlen_zero(id))
  256. ast_cli(s->fd, "ActionID: %s\r\n",id);
  257. if (msg)
  258. ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
  259. else
  260. ast_cli(s->fd, "\r\n");
  261. ast_mutex_unlock(&s->lock);
  262. }
  263. void astman_send_ack(struct mansession *s, struct message *m, char *msg)
  264. {
  265. astman_send_response(s, m, "Success", msg);
  266. }
  267. /* Tells you if smallstr exists inside bigstr
  268. which is delim by delim and uses no buf or stringsep
  269. ast_instring("this|that|more","this",',') == 1;
  270. feel free to move this to app.c -anthm */
  271. static int ast_instring(char *bigstr, char *smallstr, char delim)
  272. {
  273. char *val = bigstr, *next;
  274. do {
  275. if ((next = strchr(val, delim))) {
  276. if (!strncmp(val, smallstr, (next - val)))
  277. return 1;
  278. else
  279. continue;
  280. } else
  281. return !strcmp(smallstr, val);
  282. } while (*(val = (next + 1)));
  283. return 0;
  284. }
  285. static int get_perm(char *instr)
  286. {
  287. int x = 0, ret = 0;
  288. if (!instr)
  289. return 0;
  290. for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
  291. if (ast_instring(instr, perms[x].label, ','))
  292. ret |= perms[x].num;
  293. return ret;
  294. }
  295. static int ast_is_number(char *string)
  296. {
  297. int ret = 1, x = 0;
  298. if (!string)
  299. return 0;
  300. for (x=0; x < strlen(string); x++) {
  301. if (!(string[x] >= 48 && string[x] <= 57)) {
  302. ret = 0;
  303. break;
  304. }
  305. }
  306. return ret ? atoi(string) : 0;
  307. }
  308. static int ast_strings_to_mask(char *string)
  309. {
  310. int x = 0, ret = -1;
  311. x = ast_is_number(string);
  312. if (x)
  313. ret = x;
  314. else if (!string || ast_strlen_zero(string))
  315. ret = -1;
  316. else if (!strcasecmp(string, "off") || ast_false(string))
  317. ret = 0;
  318. else if (!strcasecmp(string, "on") || ast_true(string))
  319. ret = -1;
  320. else {
  321. ret = 0;
  322. for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
  323. if (ast_instring(string, perms[x].label, ','))
  324. ret |= perms[x].num;
  325. }
  326. }
  327. return ret;
  328. }
  329. /*
  330. Rather than braindead on,off this now can also accept a specific int mask value
  331. or a ',' delim list of mask strings (the same as manager.conf) -anthm
  332. */
  333. static int set_eventmask(struct mansession *s, char *eventmask)
  334. {
  335. int maskint = ast_strings_to_mask(eventmask);
  336. ast_mutex_lock(&s->lock);
  337. s->send_events = maskint;
  338. ast_mutex_unlock(&s->lock);
  339. return s->send_events;
  340. }
  341. static int authenticate(struct mansession *s, struct message *m)
  342. {
  343. struct ast_config *cfg;
  344. char iabuf[INET_ADDRSTRLEN];
  345. char *cat;
  346. char *user = astman_get_header(m, "Username");
  347. char *pass = astman_get_header(m, "Secret");
  348. char *authtype = astman_get_header(m, "AuthType");
  349. char *key = astman_get_header(m, "Key");
  350. char *events = astman_get_header(m, "Events");
  351. cfg = ast_load("manager.conf");
  352. if (!cfg)
  353. return -1;
  354. cat = ast_category_browse(cfg, NULL);
  355. while(cat) {
  356. if (strcasecmp(cat, "general")) {
  357. /* This is a user */
  358. if (!strcasecmp(cat, user)) {
  359. struct ast_variable *v;
  360. struct ast_ha *ha = NULL;
  361. char *password = NULL;
  362. v = ast_variable_browse(cfg, cat);
  363. while (v) {
  364. if (!strcasecmp(v->name, "secret")) {
  365. password = v->value;
  366. } else if (!strcasecmp(v->name, "permit") ||
  367. !strcasecmp(v->name, "deny")) {
  368. ha = ast_append_ha(v->name, v->value, ha);
  369. }
  370. v = v->next;
  371. }
  372. if (ha && !ast_apply_ha(ha, &(s->sin))) {
  373. ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
  374. ast_free_ha(ha);
  375. ast_destroy(cfg);
  376. return -1;
  377. } else if (ha)
  378. ast_free_ha(ha);
  379. if (!strcasecmp(authtype, "MD5")) {
  380. if (key && !ast_strlen_zero(key) && s->challenge) {
  381. int x;
  382. int len=0;
  383. char md5key[256] = "";
  384. struct MD5Context md5;
  385. unsigned char digest[16];
  386. MD5Init(&md5);
  387. MD5Update(&md5, s->challenge, strlen(s->challenge));
  388. MD5Update(&md5, password, strlen(password));
  389. MD5Final(digest, &md5);
  390. for (x=0;x<16;x++)
  391. len += sprintf(md5key + len, "%2.2x", digest[x]);
  392. if (!strcmp(md5key, key))
  393. break;
  394. else {
  395. ast_destroy(cfg);
  396. return -1;
  397. }
  398. }
  399. } else if (password && !strcasecmp(password, pass)) {
  400. break;
  401. } else {
  402. ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
  403. ast_destroy(cfg);
  404. return -1;
  405. }
  406. }
  407. }
  408. cat = ast_category_browse(cfg, cat);
  409. }
  410. if (cat) {
  411. strncpy(s->username, cat, sizeof(s->username) - 1);
  412. s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
  413. s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
  414. ast_destroy(cfg);
  415. if (events)
  416. set_eventmask(s, events);
  417. return 0;
  418. }
  419. ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
  420. ast_destroy(cfg);
  421. return -1;
  422. }
  423. static char mandescr_ping[] =
  424. "Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the "
  425. " manager connection open.\n"
  426. "Variables: NONE\n";
  427. static int action_ping(struct mansession *s, struct message *m)
  428. {
  429. astman_send_response(s, m, "Pong", NULL);
  430. return 0;
  431. }
  432. static char mandescr_listcommands[] =
  433. "Description: Returns the action name and synopsis for every\n"
  434. " action that is available to the user\n"
  435. "Variables: NONE\n";
  436. static int action_listcommands(struct mansession *s, struct message *m)
  437. {
  438. struct manager_action *cur = first_action;
  439. char idText[256] = "";
  440. char *id = astman_get_header(m,"ActionID");
  441. if (id && !ast_strlen_zero(id))
  442. snprintf(idText,256,"ActionID: %s\r\n",id);
  443. ast_cli(s->fd, "Response: Success\r\n%s", idText);
  444. ast_mutex_lock(&s->lock);
  445. ast_mutex_lock(&actionlock);
  446. while (cur) { /* Walk the list of actions */
  447. if ((s->writeperm & cur->authority) == cur->authority)
  448. ast_cli(s->fd, "%s: %s\r\n", cur->action, cur->synopsis);
  449. cur = cur->next;
  450. }
  451. ast_mutex_unlock(&actionlock);
  452. ast_cli(s->fd, "\r\n");
  453. ast_mutex_unlock(&s->lock);
  454. return 0;
  455. }
  456. static char mandescr_events[] =
  457. "Description: Enable/Disable sending of events to this manager\n"
  458. " client.\n"
  459. "Variables:\n"
  460. " EventMask: 'on' if all events should be sent,\n"
  461. " 'off' if no events should be sent,\n"
  462. " 'system,call,log' to select which flags events should have to be sent.\n";
  463. static int action_events(struct mansession *s, struct message *m)
  464. {
  465. char *mask = astman_get_header(m, "EventMask");
  466. int res;
  467. res = set_eventmask(s, mask);
  468. if (res > 0)
  469. astman_send_response(s, m, "Events On", NULL);
  470. else if (res == 0)
  471. astman_send_response(s, m, "Events Off", NULL);
  472. return 0;
  473. }
  474. static char mandescr_logoff[] =
  475. "Description: Logoff this manager session\n"
  476. "Variables: NONE\n";
  477. static int action_logoff(struct mansession *s, struct message *m)
  478. {
  479. astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
  480. return -1;
  481. }
  482. static char mandescr_hangup[] =
  483. "Description: Hangup a channel\n"
  484. "Variables: \n"
  485. " Channel: The channel name to be hungup\n";
  486. static int action_hangup(struct mansession *s, struct message *m)
  487. {
  488. struct ast_channel *c = NULL;
  489. char *name = astman_get_header(m, "Channel");
  490. if (ast_strlen_zero(name)) {
  491. astman_send_error(s, m, "No channel specified");
  492. return 0;
  493. }
  494. c = ast_channel_walk_locked(NULL);
  495. while(c) {
  496. if (!strcasecmp(c->name, name)) {
  497. break;
  498. }
  499. ast_mutex_unlock(&c->lock);
  500. c = ast_channel_walk_locked(c);
  501. }
  502. if (!c) {
  503. astman_send_error(s, m, "No such channel");
  504. return 0;
  505. }
  506. ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
  507. ast_mutex_unlock(&c->lock);
  508. astman_send_ack(s, m, "Channel Hungup");
  509. return 0;
  510. }
  511. static char mandescr_setvar[] =
  512. "Description: Set a local channel variable.\n"
  513. "Variables: (Names marked with * are required)\n"
  514. " *Channel: Channel to set variable for\n"
  515. " *Variable: Variable name\n"
  516. " *Value: Value\n";
  517. static int action_setvar(struct mansession *s, struct message *m)
  518. {
  519. struct ast_channel *c = NULL;
  520. char *name = astman_get_header(m, "Channel");
  521. char *varname = astman_get_header(m, "Variable");
  522. char *varval = astman_get_header(m, "Value");
  523. if (!strlen(name)) {
  524. astman_send_error(s, m, "No channel specified");
  525. return 0;
  526. }
  527. if (!strlen(varname)) {
  528. astman_send_error(s, m, "No variable specified");
  529. return 0;
  530. }
  531. c = ast_channel_walk_locked(NULL);
  532. while(c) {
  533. if (!strcasecmp(c->name, name)) {
  534. break;
  535. }
  536. ast_mutex_unlock(&c->lock);
  537. c = ast_channel_walk_locked(c);
  538. }
  539. if (!c) {
  540. astman_send_error(s, m, "No such channel");
  541. return 0;
  542. }
  543. pbx_builtin_setvar_helper(c,varname,varval);
  544. ast_mutex_unlock(&c->lock);
  545. astman_send_ack(s, m, "Variable Set");
  546. return 0;
  547. }
  548. static char mandescr_getvar[] =
  549. "Description: Get the value of a local channel variable.\n"
  550. "Variables: (Names marked with * are required)\n"
  551. " *Channel: Channel to read variable from\n"
  552. " *Variable: Variable name\n"
  553. " ActionID: Optional Action id for message matching.\n";
  554. static int action_getvar(struct mansession *s, struct message *m)
  555. {
  556. struct ast_channel *c = NULL;
  557. char *name = astman_get_header(m, "Channel");
  558. char *varname = astman_get_header(m, "Variable");
  559. char *id = astman_get_header(m,"ActionID");
  560. char *varval;
  561. if (!strlen(name)) {
  562. astman_send_error(s, m, "No channel specified");
  563. return 0;
  564. }
  565. if (!strlen(varname)) {
  566. astman_send_error(s, m, "No variable specified");
  567. return 0;
  568. }
  569. c = ast_channel_walk_locked(NULL);
  570. while(c) {
  571. if (!strcasecmp(c->name, name)) {
  572. break;
  573. }
  574. ast_mutex_unlock(&c->lock);
  575. c = ast_channel_walk_locked(c);
  576. }
  577. if (!c) {
  578. astman_send_error(s, m, "No such channel");
  579. return 0;
  580. }
  581. varval=pbx_builtin_getvar_helper(c,varname);
  582. ast_mutex_unlock(&c->lock);
  583. ast_mutex_lock(&s->lock);
  584. ast_cli(s->fd, "Response: Success\r\n"
  585. "%s: %s\r\n" ,varname,varval);
  586. if (id && !ast_strlen_zero(id))
  587. ast_cli(s->fd, "ActionID: %s\r\n",id);
  588. ast_cli(s->fd, "\r\n");
  589. ast_mutex_unlock(&s->lock);
  590. return 0;
  591. }
  592. static int action_status(struct mansession *s, struct message *m)
  593. {
  594. char *id = astman_get_header(m,"ActionID");
  595. char *name = astman_get_header(m,"Channel");
  596. char idText[256] = "";
  597. struct ast_channel *c;
  598. char bridge[256];
  599. struct timeval now;
  600. long elapsed_seconds=0;
  601. gettimeofday(&now, NULL);
  602. astman_send_ack(s, m, "Channel status will follow");
  603. c = ast_channel_walk_locked(NULL);
  604. if (id && !ast_strlen_zero(id))
  605. snprintf(idText,256,"ActionID: %s\r\n",id);
  606. if (name && !ast_strlen_zero(name)) {
  607. while (c) {
  608. if (!strcasecmp(c->name, name)) {
  609. break;
  610. }
  611. ast_mutex_unlock(&c->lock);
  612. c = ast_channel_walk_locked(c);
  613. }
  614. if (!c) {
  615. astman_send_error(s, m, "No such channel");
  616. return 0;
  617. }
  618. }
  619. while(c) {
  620. if (c->bridge)
  621. snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->bridge->name);
  622. else
  623. bridge[0] = '\0';
  624. ast_mutex_lock(&s->lock);
  625. if (c->pbx) {
  626. if (c->cdr) {
  627. elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
  628. }
  629. ast_cli(s->fd,
  630. "Event: Status\r\n"
  631. "Channel: %s\r\n"
  632. "CallerID: %s\r\n"
  633. "Account: %s\r\n"
  634. "State: %s\r\n"
  635. "Context: %s\r\n"
  636. "Extension: %s\r\n"
  637. "Priority: %d\r\n"
  638. "Seconds: %ld\r\n"
  639. "%s"
  640. "Uniqueid: %s\r\n"
  641. "%s"
  642. "\r\n",
  643. c->name, c->callerid ? c->callerid : "<unknown>",
  644. c->accountcode,
  645. ast_state2str(c->_state), c->context,
  646. c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
  647. } else {
  648. ast_cli(s->fd,
  649. "Event: Status\r\n"
  650. "Channel: %s\r\n"
  651. "CallerID: %s\r\n"
  652. "Account: %s\r\n"
  653. "State: %s\r\n"
  654. "%s"
  655. "Uniqueid: %s\r\n"
  656. "%s"
  657. "\r\n",
  658. c->name, c->callerid ? c->callerid : "<unknown>",
  659. c->accountcode,
  660. ast_state2str(c->_state), bridge, c->uniqueid, idText);
  661. }
  662. ast_mutex_unlock(&s->lock);
  663. ast_mutex_unlock(&c->lock);
  664. if (name && !ast_strlen_zero(name)) {
  665. break;
  666. }
  667. c = ast_channel_walk_locked(c);
  668. }
  669. ast_mutex_lock(&s->lock);
  670. ast_cli(s->fd,
  671. "Event: StatusComplete\r\n"
  672. "%s"
  673. "\r\n",idText);
  674. ast_mutex_unlock(&s->lock);
  675. return 0;
  676. }
  677. static int action_redirect(struct mansession *s, struct message *m)
  678. {
  679. char *name = astman_get_header(m, "Channel");
  680. char *name2 = astman_get_header(m, "ExtraChannel");
  681. char *exten = astman_get_header(m, "Exten");
  682. char *context = astman_get_header(m, "Context");
  683. char *priority = astman_get_header(m, "Priority");
  684. struct ast_channel *chan, *chan2 = NULL;
  685. int pi = 0;
  686. int res;
  687. if (!name || ast_strlen_zero(name)) {
  688. astman_send_error(s, m, "Channel not specified");
  689. return 0;
  690. }
  691. if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
  692. astman_send_error(s, m, "Invalid priority\n");
  693. return 0;
  694. }
  695. chan = ast_get_channel_by_name_locked(name);
  696. if (!chan) {
  697. astman_send_error(s, m, "Channel not existent");
  698. return 0;
  699. }
  700. if (!ast_strlen_zero(name2))
  701. chan2 = ast_get_channel_by_name_locked(name2);
  702. res = ast_async_goto(chan, context, exten, pi);
  703. if (!res) {
  704. if (!ast_strlen_zero(name2)) {
  705. if (chan2)
  706. res = ast_async_goto(chan2, context, exten, pi);
  707. else
  708. res = -1;
  709. if (!res)
  710. astman_send_ack(s, m, "Dual Redirect successful");
  711. else
  712. astman_send_error(s, m, "Secondary redirect failed");
  713. } else
  714. astman_send_ack(s, m, "Redirect successful");
  715. } else
  716. astman_send_error(s, m, "Redirect failed");
  717. if (chan)
  718. ast_mutex_unlock(&chan->lock);
  719. if (chan2)
  720. ast_mutex_unlock(&chan2->lock);
  721. return 0;
  722. }
  723. static char mandescr_command[] =
  724. "Description: Run a CLI command.\n"
  725. "Variables: (Names marked with * are required)\n"
  726. " *Command: Asterisk CLI command to run\n"
  727. " ActionID: Optional Action id for message matching.\n";
  728. static int action_command(struct mansession *s, struct message *m)
  729. {
  730. char *cmd = astman_get_header(m, "Command");
  731. char *id = astman_get_header(m, "ActionID");
  732. ast_mutex_lock(&s->lock);
  733. s->blocking = 1;
  734. ast_mutex_unlock(&s->lock);
  735. ast_cli(s->fd, "Response: Follows\r\n");
  736. if (id && !ast_strlen_zero(id))
  737. ast_cli(s->fd, "ActionID: %s\r\n", id);
  738. /* FIXME: Wedge a ActionID response in here, waiting for later changes */
  739. ast_cli_command(s->fd, cmd);
  740. ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
  741. ast_mutex_lock(&s->lock);
  742. s->blocking = 0;
  743. ast_mutex_unlock(&s->lock);
  744. return 0;
  745. }
  746. static void *fast_originate(void *data)
  747. {
  748. struct fast_originate_helper *in = data;
  749. int res;
  750. int reason = 0;
  751. if (!ast_strlen_zero(in->app)) {
  752. res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, !ast_strlen_zero(in->callerid) ? in->callerid : NULL, in->variable, in->account);
  753. } else {
  754. res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, !ast_strlen_zero(in->callerid) ? in->callerid : NULL, in->variable, in->account);
  755. }
  756. if (!res)
  757. manager_event(EVENT_FLAG_CALL,
  758. "OriginateSuccess",
  759. "%s"
  760. "Channel: %s/%s\r\n"
  761. "Context: %s\r\n"
  762. "Exten: %s\r\n",
  763. in->idtext, in->tech, in->data, in->context, in->exten);
  764. else
  765. manager_event(EVENT_FLAG_CALL,
  766. "OriginateFailure",
  767. "%s"
  768. "Channel: %s/%s\r\n"
  769. "Context: %s\r\n"
  770. "Exten: %s\r\n",
  771. in->idtext, in->tech, in->data, in->context, in->exten);
  772. free(in);
  773. return NULL;
  774. }
  775. static char mandescr_originate[] =
  776. "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
  777. " Application/Data\n"
  778. "Variables: (Names marked with * are required)\n"
  779. " *Channel: Channel name to call\n"
  780. " Exten: Extension to use (requires 'Context' and 'Priority')\n"
  781. " Context: Context to use (requires 'Exten' and 'Priority')\n"
  782. " Priority: Priority to use (requires 'Exten' and 'Context')\n"
  783. " Application: Application to use\n"
  784. " Data: Data to use (requires 'Application')\n"
  785. " Timeout: How long to wait for call to be answered (in ms)\n"
  786. " CallerID: Caller ID to be set on the outgoing channel\n"
  787. " Variable: Channel variable to set (VAR1=value1|VAR2=value2)\n"
  788. " Account: Account code\n"
  789. " Async: Set to 'true' for fast origination\n";
  790. static int action_originate(struct mansession *s, struct message *m)
  791. {
  792. char *name = astman_get_header(m, "Channel");
  793. char *exten = astman_get_header(m, "Exten");
  794. char *context = astman_get_header(m, "Context");
  795. char *priority = astman_get_header(m, "Priority");
  796. char *timeout = astman_get_header(m, "Timeout");
  797. char *callerid = astman_get_header(m, "CallerID");
  798. char *variable = astman_get_header(m, "Variable");
  799. char *account = astman_get_header(m, "Account");
  800. char *app = astman_get_header(m, "Application");
  801. char *appdata = astman_get_header(m, "Data");
  802. char *async = astman_get_header(m, "Async");
  803. char *id = astman_get_header(m, "ActionID");
  804. char *tech, *data;
  805. int pi = 0;
  806. int res;
  807. int to = 30000;
  808. int reason = 0;
  809. char tmp[256];
  810. pthread_t th;
  811. pthread_attr_t attr;
  812. if (!name) {
  813. astman_send_error(s, m, "Channel not specified");
  814. return 0;
  815. }
  816. if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
  817. astman_send_error(s, m, "Invalid priority\n");
  818. return 0;
  819. }
  820. if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
  821. astman_send_error(s, m, "Invalid timeout\n");
  822. return 0;
  823. }
  824. strncpy(tmp, name, sizeof(tmp) - 1);
  825. tech = tmp;
  826. data = strchr(tmp, '/');
  827. if (!data) {
  828. astman_send_error(s, m, "Invalid channel\n");
  829. return 0;
  830. }
  831. *data = '\0';
  832. data++;
  833. if (ast_true(async)) {
  834. struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
  835. if (!fast) {
  836. res = -1;
  837. } else {
  838. memset(fast, 0, sizeof(struct fast_originate_helper));
  839. if (id && !ast_strlen_zero(id))
  840. snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
  841. strncpy(fast->tech, tech, sizeof(fast->tech) - 1);
  842. strncpy(fast->data, data, sizeof(fast->data) - 1);
  843. strncpy(fast->app, app, sizeof(fast->app) - 1);
  844. strncpy(fast->appdata, appdata, sizeof(fast->appdata) - 1);
  845. strncpy(fast->callerid, callerid, sizeof(fast->callerid) - 1);
  846. strncpy(fast->variable, variable, sizeof(fast->variable) - 1);
  847. strncpy(fast->account, account, sizeof(fast->account) - 1);
  848. strncpy(fast->context, context, sizeof(fast->context) - 1);
  849. strncpy(fast->exten, exten, sizeof(fast->exten) - 1);
  850. fast->timeout = to;
  851. fast->priority = pi;
  852. pthread_attr_init(&attr);
  853. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  854. if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
  855. res = -1;
  856. } else {
  857. res = 0;
  858. }
  859. }
  860. } else if (!ast_strlen_zero(app)) {
  861. res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account);
  862. } else {
  863. if (exten && context && pi)
  864. res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account);
  865. else {
  866. astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
  867. return 0;
  868. }
  869. }
  870. if (!res)
  871. astman_send_ack(s, m, "Originate successfully queued");
  872. else
  873. astman_send_error(s, m, "Originate failed");
  874. return 0;
  875. }
  876. static char mandescr_mailboxstatus[] =
  877. "Description: Checks a voicemail account for status.\n"
  878. "Variables: (Names marked with * are required)\n"
  879. " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
  880. " ActionID: Optional ActionID for message matching.\n"
  881. "Returns number of messages.\n"
  882. " Message: Mailbox Status\n"
  883. " Mailbox: <mailboxid>\n"
  884. " Waiting: <count>\n"
  885. "\n";
  886. static int action_mailboxstatus(struct mansession *s, struct message *m)
  887. {
  888. char *mailbox = astman_get_header(m, "Mailbox");
  889. char *id = astman_get_header(m,"ActionID");
  890. char idText[256] = "";
  891. int ret;
  892. if (!mailbox || ast_strlen_zero(mailbox)) {
  893. astman_send_error(s, m, "Mailbox not specified");
  894. return 0;
  895. }
  896. if (id && !ast_strlen_zero(id))
  897. snprintf(idText,256,"ActionID: %s\r\n",id);
  898. ret = ast_app_has_voicemail(mailbox);
  899. ast_mutex_lock(&s->lock);
  900. ast_cli(s->fd, "Response: Success\r\n"
  901. "%s"
  902. "Message: Mailbox Status\r\n"
  903. "Mailbox: %s\r\n"
  904. "Waiting: %d\r\n\r\n", idText, mailbox, ret);
  905. ast_mutex_unlock(&s->lock);
  906. return 0;
  907. }
  908. static char mandescr_mailboxcount[] =
  909. "Description: Checks a voicemail account for new messages.\n"
  910. "Variables: (Names marked with * are required)\n"
  911. " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
  912. " ActionID: Optional ActionID for message matching.\n"
  913. "Returns number of new and old messages.\n"
  914. " Message: Mailbox Message Count\n"
  915. " Mailbox: <mailboxid>\n"
  916. " NewMessages: <count>\n"
  917. " OldMessages: <count>\n"
  918. "\n";
  919. static int action_mailboxcount(struct mansession *s, struct message *m)
  920. {
  921. char *mailbox = astman_get_header(m, "Mailbox");
  922. char *id = astman_get_header(m,"ActionID");
  923. char idText[256] = "";
  924. int newmsgs = 0, oldmsgs = 0;
  925. if (!mailbox || ast_strlen_zero(mailbox)) {
  926. astman_send_error(s, m, "Mailbox not specified");
  927. return 0;
  928. }
  929. ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
  930. if (id && !ast_strlen_zero(id)) {
  931. snprintf(idText,256,"ActionID: %s\r\n",id);
  932. }
  933. ast_mutex_lock(&s->lock);
  934. ast_cli(s->fd, "Response: Success\r\n"
  935. "%s"
  936. "Message: Mailbox Message Count\r\n"
  937. "Mailbox: %s\r\n"
  938. "NewMessages: %d\r\n"
  939. "OldMessages: %d\r\n"
  940. "\r\n",
  941. idText,mailbox, newmsgs, oldmsgs);
  942. ast_mutex_unlock(&s->lock);
  943. return 0;
  944. }
  945. static char mandescr_extensionstate[] =
  946. "Description: Report the extension state for given extension.\n"
  947. " If the extension has a hint, will use devicestate to check\n"
  948. " the status of the device connected to the extension.\n"
  949. "Variables: (Names marked with * are required)\n"
  950. " *Exten: Extension to check state on\n"
  951. " *Context: Context for extension\n"
  952. " ActionId: Optional ID for this transaction\n"
  953. "Will return an \"Extension Status\" message.\n"
  954. "The response will include the hint for the extension and the status.\n";
  955. static int action_extensionstate(struct mansession *s, struct message *m)
  956. {
  957. char *exten = astman_get_header(m, "Exten");
  958. char *context = astman_get_header(m, "Context");
  959. char *id = astman_get_header(m,"ActionID");
  960. char idText[256] = "";
  961. char hint[256] = "";
  962. int status;
  963. if (!exten || ast_strlen_zero(exten)) {
  964. astman_send_error(s, m, "Extension not specified");
  965. return 0;
  966. }
  967. if (!context || ast_strlen_zero(context))
  968. context = "default";
  969. status = ast_extension_state(NULL, context, exten);
  970. ast_get_hint(hint, sizeof(hint) - 1, NULL, context, exten);
  971. if (id && !ast_strlen_zero(id)) {
  972. snprintf(idText,256,"ActionID: %s\r\n",id);
  973. }
  974. ast_mutex_lock(&s->lock);
  975. ast_cli(s->fd, "Response: Success\r\n"
  976. "%s"
  977. "Message: Extension Status\r\n"
  978. "Exten: %s\r\n"
  979. "Context: %s\r\n"
  980. "Hint: %s\r\n"
  981. "Status: %d\r\n\r\n",
  982. idText,exten, context, hint, status);
  983. ast_mutex_unlock(&s->lock);
  984. return 0;
  985. }
  986. static char mandescr_timeout[] =
  987. "Description: Hangup a channel after a certain time.\n"
  988. "Variables: (Names marked with * are required)\n"
  989. " *Channel: Channel name to hangup\n"
  990. " *Timeout: Maximum duration of the call (sec)\n"
  991. "Acknowledges set time with 'Timeout Set' message\n";
  992. static int action_timeout(struct mansession *s, struct message *m)
  993. {
  994. struct ast_channel *c = NULL;
  995. char *name = astman_get_header(m, "Channel");
  996. int timeout = atoi(astman_get_header(m, "Timeout"));
  997. if (ast_strlen_zero(name)) {
  998. astman_send_error(s, m, "No channel specified");
  999. return 0;
  1000. }
  1001. if (!timeout) {
  1002. astman_send_error(s, m, "No timeout specified");
  1003. return 0;
  1004. }
  1005. c = ast_channel_walk_locked(NULL);
  1006. while(c) {
  1007. if (!strcasecmp(c->name, name)) {
  1008. break;
  1009. }
  1010. ast_mutex_unlock(&c->lock);
  1011. c = ast_channel_walk_locked(c);
  1012. }
  1013. if (!c) {
  1014. astman_send_error(s, m, "No such channel");
  1015. return 0;
  1016. }
  1017. ast_channel_setwhentohangup(c, timeout);
  1018. ast_mutex_unlock(&c->lock);
  1019. astman_send_ack(s, m, "Timeout Set");
  1020. return 0;
  1021. }
  1022. static int process_message(struct mansession *s, struct message *m)
  1023. {
  1024. char action[80] = "";
  1025. struct manager_action *tmp = first_action;
  1026. char *id = astman_get_header(m,"ActionID");
  1027. char idText[256] = "";
  1028. char iabuf[INET_ADDRSTRLEN];
  1029. strncpy(action, astman_get_header(m, "Action"), sizeof(action) - 1);
  1030. ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
  1031. if (ast_strlen_zero(action)) {
  1032. astman_send_error(s, m, "Missing action in request");
  1033. return 0;
  1034. }
  1035. if (id && !ast_strlen_zero(id)) {
  1036. snprintf(idText,256,"ActionID: %s\r\n",id);
  1037. }
  1038. if (!s->authenticated) {
  1039. if (!strcasecmp(action, "Challenge")) {
  1040. char *authtype;
  1041. authtype = astman_get_header(m, "AuthType");
  1042. if (!strcasecmp(authtype, "MD5")) {
  1043. if (!s->challenge || ast_strlen_zero(s->challenge)) {
  1044. ast_mutex_lock(&s->lock);
  1045. snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
  1046. ast_mutex_unlock(&s->lock);
  1047. }
  1048. ast_mutex_lock(&s->lock);
  1049. ast_cli(s->fd, "Response: Success\r\n"
  1050. "%s"
  1051. "Challenge: %s\r\n\r\n",
  1052. idText,s->challenge);
  1053. ast_mutex_unlock(&s->lock);
  1054. return 0;
  1055. } else {
  1056. astman_send_error(s, m, "Must specify AuthType");
  1057. return 0;
  1058. }
  1059. } else if (!strcasecmp(action, "Login")) {
  1060. if (authenticate(s, m)) {
  1061. sleep(1);
  1062. astman_send_error(s, m, "Authentication failed");
  1063. return -1;
  1064. } else {
  1065. s->authenticated = 1;
  1066. if (option_verbose > 1)
  1067. ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1068. ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1069. astman_send_ack(s, m, "Authentication accepted");
  1070. }
  1071. } else if (!strcasecmp(action, "Logoff")) {
  1072. astman_send_ack(s, m, "See ya");
  1073. return -1;
  1074. } else
  1075. astman_send_error(s, m, "Authentication Required");
  1076. } else {
  1077. while( tmp ) {
  1078. if (!strcasecmp(action, tmp->action)) {
  1079. if ((s->writeperm & tmp->authority) == tmp->authority) {
  1080. if (tmp->func(s, m))
  1081. return -1;
  1082. } else {
  1083. astman_send_error(s, m, "Permission denied");
  1084. }
  1085. return 0;
  1086. }
  1087. tmp = tmp->next;
  1088. }
  1089. astman_send_error(s, m, "Invalid/unknown command");
  1090. }
  1091. return 0;
  1092. }
  1093. static int get_input(struct mansession *s, char *output)
  1094. {
  1095. /* output must have at least sizeof(s->inbuf) space */
  1096. int res;
  1097. int x;
  1098. struct pollfd fds[1];
  1099. char iabuf[INET_ADDRSTRLEN];
  1100. for (x=1;x<s->inlen;x++) {
  1101. if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
  1102. /* Copy output data up to and including \r\n */
  1103. memcpy(output, s->inbuf, x + 1);
  1104. /* Add trailing \0 */
  1105. output[x+1] = '\0';
  1106. /* Move remaining data back to the front */
  1107. memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
  1108. s->inlen -= (x + 1);
  1109. return 1;
  1110. }
  1111. }
  1112. if (s->inlen >= sizeof(s->inbuf) - 1) {
  1113. ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->inbuf);
  1114. s->inlen = 0;
  1115. }
  1116. fds[0].fd = s->fd;
  1117. fds[0].events = POLLIN;
  1118. res = poll(fds, 1, -1);
  1119. if (res < 0) {
  1120. ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
  1121. return -1;
  1122. } else if (res > 0) {
  1123. ast_mutex_lock(&s->lock);
  1124. res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
  1125. ast_mutex_unlock(&s->lock);
  1126. if (res < 1)
  1127. return -1;
  1128. }
  1129. s->inlen += res;
  1130. s->inbuf[s->inlen] = '\0';
  1131. return 0;
  1132. }
  1133. static void *session_do(void *data)
  1134. {
  1135. struct mansession *s = data;
  1136. struct message m;
  1137. char iabuf[INET_ADDRSTRLEN];
  1138. int res;
  1139. ast_mutex_lock(&s->lock);
  1140. ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
  1141. ast_mutex_unlock(&s->lock);
  1142. memset(&m, 0, sizeof(&m));
  1143. for (;;) {
  1144. res = get_input(s, m.headers[m.hdrcount]);
  1145. if (res > 0) {
  1146. /* Strip trailing \r\n */
  1147. if (strlen(m.headers[m.hdrcount]) < 2)
  1148. continue;
  1149. m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
  1150. if (ast_strlen_zero(m.headers[m.hdrcount])) {
  1151. if (process_message(s, &m))
  1152. break;
  1153. memset(&m, 0, sizeof(&m));
  1154. } else if (m.hdrcount < MAX_HEADERS - 1)
  1155. m.hdrcount++;
  1156. } else if (res < 0)
  1157. break;
  1158. }
  1159. if (s->authenticated) {
  1160. if (option_verbose > 1)
  1161. ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1162. ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1163. } else {
  1164. if (option_verbose > 1)
  1165. ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1166. ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1167. }
  1168. destroy_session(s);
  1169. return NULL;
  1170. }
  1171. static void *accept_thread(void *ignore)
  1172. {
  1173. int as;
  1174. struct sockaddr_in sin;
  1175. int sinlen;
  1176. struct mansession *s;
  1177. struct protoent *p;
  1178. int arg = 1;
  1179. int flags;
  1180. pthread_attr_t attr;
  1181. pthread_attr_init(&attr);
  1182. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  1183. for (;;) {
  1184. sinlen = sizeof(sin);
  1185. as = accept(asock, (struct sockaddr *)&sin, &sinlen);
  1186. if (as < 0) {
  1187. ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
  1188. continue;
  1189. }
  1190. p = getprotobyname("tcp");
  1191. if( p ) {
  1192. if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
  1193. ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
  1194. }
  1195. }
  1196. s = malloc(sizeof(struct mansession));
  1197. if (!s) {
  1198. ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
  1199. continue;
  1200. }
  1201. memset(s, 0, sizeof(struct mansession));
  1202. memcpy(&s->sin, &sin, sizeof(sin));
  1203. if(! block_sockets) {
  1204. /* For safety, make sure socket is non-blocking */
  1205. flags = fcntl(as, F_GETFL);
  1206. fcntl(as, F_SETFL, flags | O_NONBLOCK);
  1207. }
  1208. ast_mutex_init(&s->lock);
  1209. s->fd = as;
  1210. s->send_events = -1;
  1211. ast_mutex_lock(&sessionlock);
  1212. s->next = sessions;
  1213. sessions = s;
  1214. ast_mutex_unlock(&sessionlock);
  1215. if (ast_pthread_create(&t, &attr, session_do, s))
  1216. destroy_session(s);
  1217. }
  1218. pthread_attr_destroy(&attr);
  1219. return NULL;
  1220. }
  1221. int manager_event(int category, char *event, char *fmt, ...)
  1222. {
  1223. struct mansession *s;
  1224. char tmp[4096];
  1225. va_list ap;
  1226. ast_mutex_lock(&sessionlock);
  1227. s = sessions;
  1228. while(s) {
  1229. if (((s->readperm & category) == category) && ((s->send_events & category) == category) ) {
  1230. ast_mutex_lock(&s->lock);
  1231. if (!s->blocking) {
  1232. ast_cli(s->fd, "Event: %s\r\n", event);
  1233. va_start(ap, fmt);
  1234. vsnprintf(tmp, sizeof(tmp), fmt, ap);
  1235. va_end(ap);
  1236. ast_carefulwrite(s->fd,tmp,strlen(tmp),100);
  1237. ast_cli(s->fd, "\r\n");
  1238. }
  1239. ast_mutex_unlock(&s->lock);
  1240. }
  1241. s = s->next;
  1242. }
  1243. ast_mutex_unlock(&sessionlock);
  1244. return 0;
  1245. }
  1246. int ast_manager_unregister( char *action ) {
  1247. struct manager_action *cur = first_action, *prev = first_action;
  1248. ast_mutex_lock(&actionlock);
  1249. while( cur ) {
  1250. if (!strcasecmp(action, cur->action)) {
  1251. prev->next = cur->next;
  1252. free(cur);
  1253. if (option_verbose > 1)
  1254. ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
  1255. ast_mutex_unlock(&actionlock);
  1256. return 0;
  1257. }
  1258. prev = cur;
  1259. cur = cur->next;
  1260. }
  1261. ast_mutex_unlock(&actionlock);
  1262. return 0;
  1263. }
  1264. static int manager_state_cb(char *context, char *exten, int state, void *data)
  1265. {
  1266. /* Notify managers of change */
  1267. manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
  1268. return 0;
  1269. }
  1270. static int ast_manager_register_struct(struct manager_action *act)
  1271. {
  1272. struct manager_action *cur = first_action, *prev = NULL;
  1273. int ret;
  1274. ast_mutex_lock(&actionlock);
  1275. while(cur) { /* Walk the list of actions */
  1276. ret = strcasecmp(cur->action, act->action);
  1277. if (ret == 0) {
  1278. ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
  1279. ast_mutex_unlock(&actionlock);
  1280. return -1;
  1281. } else if (ret > 0) {
  1282. /* Insert these alphabetically */
  1283. if (prev) {
  1284. act->next = prev->next;
  1285. prev->next = act;
  1286. } else {
  1287. act->next = first_action;
  1288. first_action = act;
  1289. }
  1290. break;
  1291. }
  1292. prev = cur;
  1293. cur = cur->next;
  1294. }
  1295. if (!cur) {
  1296. if (prev)
  1297. prev->next = act;
  1298. else
  1299. first_action = act;
  1300. act->next = NULL;
  1301. }
  1302. if (option_verbose > 1)
  1303. ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
  1304. ast_mutex_unlock(&actionlock);
  1305. return 0;
  1306. }
  1307. int ast_manager_register2(char *action, int auth, int (*func)(struct mansession *s, struct message *m), char *synopsis, char *description)
  1308. {
  1309. struct manager_action *cur;
  1310. cur = malloc(sizeof(struct manager_action));
  1311. if (!cur) {
  1312. ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
  1313. ast_mutex_unlock(&actionlock);
  1314. return -1;
  1315. }
  1316. cur->action = action;
  1317. cur->authority = auth;
  1318. cur->func = func;
  1319. cur->synopsis = synopsis;
  1320. cur->description = description;
  1321. cur->next = NULL;
  1322. ast_manager_register_struct(cur);
  1323. return 0;
  1324. }
  1325. static int registered = 0;
  1326. int init_manager(void)
  1327. {
  1328. struct ast_config *cfg;
  1329. char *val;
  1330. int oldportno = portno;
  1331. static struct sockaddr_in ba;
  1332. int x = 1;
  1333. if (!registered) {
  1334. /* Register default actions */
  1335. ast_manager_register2("Ping", 0, action_ping, "Ping", mandescr_ping);
  1336. ast_manager_register2("Events", 0, action_events, "Contol Event Flow", mandescr_events);
  1337. ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
  1338. ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
  1339. ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" );
  1340. ast_manager_register2( "Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
  1341. ast_manager_register2( "Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
  1342. ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect" );
  1343. ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
  1344. ast_manager_register2( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command", mandescr_command );
  1345. ast_manager_register2( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
  1346. ast_manager_register2( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
  1347. ast_manager_register2( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
  1348. ast_manager_register2( "MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
  1349. ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
  1350. ast_cli_register(&show_mancmd_cli);
  1351. ast_cli_register(&show_mancmds_cli);
  1352. ast_cli_register(&show_manconn_cli);
  1353. ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
  1354. registered = 1;
  1355. }
  1356. portno = DEFAULT_MANAGER_PORT;
  1357. cfg = ast_load("manager.conf");
  1358. if (!cfg) {
  1359. ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
  1360. return 0;
  1361. }
  1362. memset(&ba, 0, sizeof(ba));
  1363. val = ast_variable_retrieve(cfg, "general", "enabled");
  1364. if (val)
  1365. enabled = ast_true(val);
  1366. val = ast_variable_retrieve(cfg, "general", "block-sockets");
  1367. if(val)
  1368. block_sockets = ast_true(val);
  1369. if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
  1370. if (sscanf(val, "%d", &portno) != 1) {
  1371. ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
  1372. portno = DEFAULT_MANAGER_PORT;
  1373. }
  1374. } else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
  1375. if (sscanf(val, "%d", &portno) != 1) {
  1376. ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
  1377. portno = DEFAULT_MANAGER_PORT;
  1378. }
  1379. ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated. Please use 'port=%s' instead.\n", val);
  1380. }
  1381. ba.sin_family = AF_INET;
  1382. ba.sin_port = htons(portno);
  1383. memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
  1384. if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
  1385. if (!inet_aton(val, &ba.sin_addr)) {
  1386. ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
  1387. memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
  1388. }
  1389. }
  1390. if ((asock > -1) && ((portno != oldportno) || !enabled)) {
  1391. #if 0
  1392. /* Can't be done yet */
  1393. close(asock);
  1394. asock = -1;
  1395. #else
  1396. ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
  1397. #endif
  1398. }
  1399. ast_destroy(cfg);
  1400. /* If not enabled, do nothing */
  1401. if (!enabled) {
  1402. return 0;
  1403. }
  1404. if (asock < 0) {
  1405. asock = socket(AF_INET, SOCK_STREAM, 0);
  1406. if (asock < 0) {
  1407. ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
  1408. return -1;
  1409. }
  1410. setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
  1411. if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
  1412. ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
  1413. close(asock);
  1414. asock = -1;
  1415. return -1;
  1416. }
  1417. if (listen(asock, 2)) {
  1418. ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
  1419. close(asock);
  1420. asock = -1;
  1421. return -1;
  1422. }
  1423. if (option_verbose)
  1424. ast_verbose("Asterisk Management interface listening on port %d\n", portno);
  1425. ast_pthread_create(&t, NULL, accept_thread, NULL);
  1426. }
  1427. return 0;
  1428. }
  1429. int reload_manager(void)
  1430. {
  1431. manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
  1432. return init_manager();
  1433. }