pbx_functions.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2015, CFWare, LLC
  5. *
  6. * Corey Farrell <git@cfware.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief Custom function management routines.
  21. *
  22. * \author Corey Farrell <git@cfware.com>
  23. */
  24. /*** MODULEINFO
  25. <support_level>core</support_level>
  26. ***/
  27. #include "asterisk.h"
  28. ASTERISK_REGISTER_FILE()
  29. #include "asterisk/_private.h"
  30. #include "asterisk/cli.h"
  31. #include "asterisk/linkedlists.h"
  32. #include "asterisk/module.h"
  33. #include "asterisk/pbx.h"
  34. #include "asterisk/term.h"
  35. #include "asterisk/threadstorage.h"
  36. #include "asterisk/xmldoc.h"
  37. #include "pbx_private.h"
  38. /*!
  39. * \brief A thread local indicating whether the current thread can run
  40. * 'dangerous' dialplan functions.
  41. */
  42. AST_THREADSTORAGE(thread_inhibit_escalations_tl);
  43. /*!
  44. * \brief Set to true (non-zero) to globally allow all dangerous dialplan
  45. * functions to run.
  46. */
  47. static int live_dangerously;
  48. /*!
  49. * \brief Registered functions container.
  50. *
  51. * It is sorted by function name.
  52. */
  53. static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
  54. static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  55. {
  56. struct ast_custom_function *acf;
  57. int count_acf = 0;
  58. int like = 0;
  59. switch (cmd) {
  60. case CLI_INIT:
  61. e->command = "core show functions [like]";
  62. e->usage =
  63. "Usage: core show functions [like <text>]\n"
  64. " List builtin functions, optionally only those matching a given string\n";
  65. return NULL;
  66. case CLI_GENERATE:
  67. return NULL;
  68. }
  69. if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
  70. like = 1;
  71. } else if (a->argc != 3) {
  72. return CLI_SHOWUSAGE;
  73. }
  74. ast_cli(a->fd, "%s Custom Functions:\n"
  75. "--------------------------------------------------------------------------------\n",
  76. like ? "Matching" : "Installed");
  77. AST_RWLIST_RDLOCK(&acf_root);
  78. AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
  79. if (!like || strstr(acf->name, a->argv[4])) {
  80. count_acf++;
  81. ast_cli(a->fd, "%-20.20s %-35.35s %s\n",
  82. S_OR(acf->name, ""),
  83. S_OR(acf->syntax, ""),
  84. S_OR(acf->synopsis, ""));
  85. }
  86. }
  87. AST_RWLIST_UNLOCK(&acf_root);
  88. ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
  89. return CLI_SUCCESS;
  90. }
  91. static char *complete_functions(const char *word, int pos, int state)
  92. {
  93. struct ast_custom_function *cur;
  94. char *ret = NULL;
  95. int which = 0;
  96. int wordlen;
  97. int cmp;
  98. if (pos != 3) {
  99. return NULL;
  100. }
  101. wordlen = strlen(word);
  102. AST_RWLIST_RDLOCK(&acf_root);
  103. AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
  104. /*
  105. * Do a case-insensitive search for convenience in this
  106. * 'complete' function.
  107. *
  108. * We must search the entire container because the functions are
  109. * sorted and normally found case sensitively.
  110. */
  111. cmp = strncasecmp(word, cur->name, wordlen);
  112. if (!cmp) {
  113. /* Found match. */
  114. if (++which <= state) {
  115. /* Not enough matches. */
  116. continue;
  117. }
  118. ret = ast_strdup(cur->name);
  119. break;
  120. }
  121. }
  122. AST_RWLIST_UNLOCK(&acf_root);
  123. return ret;
  124. }
  125. static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  126. {
  127. struct ast_custom_function *acf;
  128. /* Maximum number of characters added by terminal coloring is 22 */
  129. char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], argtitle[40], seealsotitle[40];
  130. char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *seealso = NULL;
  131. char stxtitle[40], *syntax = NULL, *arguments = NULL;
  132. int syntax_size, description_size, synopsis_size, arguments_size, seealso_size;
  133. switch (cmd) {
  134. case CLI_INIT:
  135. e->command = "core show function";
  136. e->usage =
  137. "Usage: core show function <function>\n"
  138. " Describe a particular dialplan function.\n";
  139. return NULL;
  140. case CLI_GENERATE:
  141. return complete_functions(a->word, a->pos, a->n);
  142. }
  143. if (a->argc != 4) {
  144. return CLI_SHOWUSAGE;
  145. }
  146. if (!(acf = ast_custom_function_find(a->argv[3]))) {
  147. ast_cli(a->fd, "No function by that name registered.\n");
  148. return CLI_FAILURE;
  149. }
  150. syntax_size = strlen(S_OR(acf->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
  151. syntax = ast_malloc(syntax_size);
  152. if (!syntax) {
  153. ast_cli(a->fd, "Memory allocation failure!\n");
  154. return CLI_FAILURE;
  155. }
  156. snprintf(info, sizeof(info), "\n -= Info about function '%s' =- \n\n", acf->name);
  157. term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
  158. term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
  159. term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
  160. term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
  161. term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
  162. term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
  163. term_color(syntax, S_OR(acf->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
  164. #ifdef AST_XML_DOCS
  165. if (acf->docsrc == AST_XML_DOC) {
  166. arguments = ast_xmldoc_printable(S_OR(acf->arguments, "Not available"), 1);
  167. synopsis = ast_xmldoc_printable(S_OR(acf->synopsis, "Not available"), 1);
  168. description = ast_xmldoc_printable(S_OR(acf->desc, "Not available"), 1);
  169. seealso = ast_xmldoc_printable(S_OR(acf->seealso, "Not available"), 1);
  170. } else
  171. #endif
  172. {
  173. synopsis_size = strlen(S_OR(acf->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
  174. synopsis = ast_malloc(synopsis_size);
  175. description_size = strlen(S_OR(acf->desc, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
  176. description = ast_malloc(description_size);
  177. arguments_size = strlen(S_OR(acf->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
  178. arguments = ast_malloc(arguments_size);
  179. seealso_size = strlen(S_OR(acf->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
  180. seealso = ast_malloc(seealso_size);
  181. /* check allocated memory. */
  182. if (!synopsis || !description || !arguments || !seealso) {
  183. ast_free(synopsis);
  184. ast_free(description);
  185. ast_free(arguments);
  186. ast_free(seealso);
  187. ast_free(syntax);
  188. return CLI_FAILURE;
  189. }
  190. term_color(arguments, S_OR(acf->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
  191. term_color(synopsis, S_OR(acf->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
  192. term_color(description, S_OR(acf->desc, "Not available"), COLOR_CYAN, 0, description_size);
  193. term_color(seealso, S_OR(acf->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
  194. }
  195. ast_cli(a->fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
  196. infotitle, syntitle, synopsis, destitle, description,
  197. stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
  198. ast_free(arguments);
  199. ast_free(synopsis);
  200. ast_free(description);
  201. ast_free(seealso);
  202. ast_free(syntax);
  203. return CLI_SUCCESS;
  204. }
  205. static struct ast_custom_function *ast_custom_function_find_nolock(const char *name)
  206. {
  207. struct ast_custom_function *cur;
  208. int cmp;
  209. AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
  210. cmp = strcmp(name, cur->name);
  211. if (cmp > 0) {
  212. continue;
  213. }
  214. if (!cmp) {
  215. /* Found it. */
  216. break;
  217. }
  218. /* Not in container. */
  219. cur = NULL;
  220. break;
  221. }
  222. return cur;
  223. }
  224. struct ast_custom_function *ast_custom_function_find(const char *name)
  225. {
  226. struct ast_custom_function *acf;
  227. AST_RWLIST_RDLOCK(&acf_root);
  228. acf = ast_custom_function_find_nolock(name);
  229. AST_RWLIST_UNLOCK(&acf_root);
  230. return acf;
  231. }
  232. int ast_custom_function_unregister(struct ast_custom_function *acf)
  233. {
  234. struct ast_custom_function *cur;
  235. if (!acf) {
  236. return -1;
  237. }
  238. AST_RWLIST_WRLOCK(&acf_root);
  239. cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist);
  240. if (cur) {
  241. #ifdef AST_XML_DOCS
  242. if (cur->docsrc == AST_XML_DOC) {
  243. ast_string_field_free_memory(acf);
  244. }
  245. #endif
  246. ast_verb(2, "Unregistered custom function %s\n", cur->name);
  247. }
  248. AST_RWLIST_UNLOCK(&acf_root);
  249. return cur ? 0 : -1;
  250. }
  251. /*!
  252. * \brief Returns true if given custom function escalates privileges on read.
  253. *
  254. * \param acf Custom function to query.
  255. * \return True (non-zero) if reads escalate privileges.
  256. * \return False (zero) if reads just read.
  257. */
  258. static int read_escalates(const struct ast_custom_function *acf)
  259. {
  260. return acf->read_escalates;
  261. }
  262. /*!
  263. * \brief Returns true if given custom function escalates privileges on write.
  264. *
  265. * \param acf Custom function to query.
  266. * \return True (non-zero) if writes escalate privileges.
  267. * \return False (zero) if writes just write.
  268. */
  269. static int write_escalates(const struct ast_custom_function *acf)
  270. {
  271. return acf->write_escalates;
  272. }
  273. /*! \internal
  274. * \brief Retrieve the XML documentation of a specified ast_custom_function,
  275. * and populate ast_custom_function string fields.
  276. * \param acf ast_custom_function structure with empty 'desc' and 'synopsis'
  277. * but with a function 'name'.
  278. * \retval -1 On error.
  279. * \retval 0 On succes.
  280. */
  281. static int acf_retrieve_docs(struct ast_custom_function *acf)
  282. {
  283. #ifdef AST_XML_DOCS
  284. char *tmpxml;
  285. /* Let's try to find it in the Documentation XML */
  286. if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
  287. return 0;
  288. }
  289. if (ast_string_field_init(acf, 128)) {
  290. return -1;
  291. }
  292. /* load synopsis */
  293. tmpxml = ast_xmldoc_build_synopsis("function", acf->name, ast_module_name(acf->mod));
  294. ast_string_field_set(acf, synopsis, tmpxml);
  295. ast_free(tmpxml);
  296. /* load description */
  297. tmpxml = ast_xmldoc_build_description("function", acf->name, ast_module_name(acf->mod));
  298. ast_string_field_set(acf, desc, tmpxml);
  299. ast_free(tmpxml);
  300. /* load syntax */
  301. tmpxml = ast_xmldoc_build_syntax("function", acf->name, ast_module_name(acf->mod));
  302. ast_string_field_set(acf, syntax, tmpxml);
  303. ast_free(tmpxml);
  304. /* load arguments */
  305. tmpxml = ast_xmldoc_build_arguments("function", acf->name, ast_module_name(acf->mod));
  306. ast_string_field_set(acf, arguments, tmpxml);
  307. ast_free(tmpxml);
  308. /* load seealso */
  309. tmpxml = ast_xmldoc_build_seealso("function", acf->name, ast_module_name(acf->mod));
  310. ast_string_field_set(acf, seealso, tmpxml);
  311. ast_free(tmpxml);
  312. acf->docsrc = AST_XML_DOC;
  313. #endif
  314. return 0;
  315. }
  316. int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
  317. {
  318. struct ast_custom_function *cur;
  319. if (!acf) {
  320. return -1;
  321. }
  322. acf->mod = mod;
  323. #ifdef AST_XML_DOCS
  324. acf->docsrc = AST_STATIC_DOC;
  325. #endif
  326. if (acf_retrieve_docs(acf)) {
  327. return -1;
  328. }
  329. AST_RWLIST_WRLOCK(&acf_root);
  330. cur = ast_custom_function_find_nolock(acf->name);
  331. if (cur) {
  332. ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
  333. AST_RWLIST_UNLOCK(&acf_root);
  334. return -1;
  335. }
  336. /* Store in alphabetical order */
  337. AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
  338. if (strcmp(acf->name, cur->name) < 0) {
  339. AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
  340. break;
  341. }
  342. }
  343. AST_RWLIST_TRAVERSE_SAFE_END;
  344. if (!cur) {
  345. AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
  346. }
  347. AST_RWLIST_UNLOCK(&acf_root);
  348. ast_verb(2, "Registered custom function '" COLORIZE_FMT "'\n", COLORIZE(COLOR_BRCYAN, 0, acf->name));
  349. return 0;
  350. }
  351. int __ast_custom_function_register_escalating(struct ast_custom_function *acf, enum ast_custom_function_escalation escalation, struct ast_module *mod)
  352. {
  353. int res;
  354. res = __ast_custom_function_register(acf, mod);
  355. if (res != 0) {
  356. return -1;
  357. }
  358. switch (escalation) {
  359. case AST_CFE_NONE:
  360. break;
  361. case AST_CFE_READ:
  362. acf->read_escalates = 1;
  363. break;
  364. case AST_CFE_WRITE:
  365. acf->write_escalates = 1;
  366. break;
  367. case AST_CFE_BOTH:
  368. acf->read_escalates = 1;
  369. acf->write_escalates = 1;
  370. break;
  371. }
  372. return 0;
  373. }
  374. /*! \brief return a pointer to the arguments of the function,
  375. * and terminates the function name with '\\0'
  376. */
  377. static char *func_args(char *function)
  378. {
  379. char *args = strchr(function, '(');
  380. if (!args) {
  381. ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses. Assuming null argument.\n", function);
  382. } else {
  383. char *p;
  384. *args++ = '\0';
  385. if ((p = strrchr(args, ')'))) {
  386. *p = '\0';
  387. } else {
  388. ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
  389. }
  390. }
  391. return args;
  392. }
  393. void pbx_live_dangerously(int new_live_dangerously)
  394. {
  395. if (new_live_dangerously && !live_dangerously) {
  396. ast_log(LOG_WARNING, "Privilege escalation protection disabled!\n"
  397. "See https://wiki.asterisk.org/wiki/x/1gKfAQ for more details.\n");
  398. }
  399. if (!new_live_dangerously && live_dangerously) {
  400. ast_log(LOG_NOTICE, "Privilege escalation protection enabled.\n");
  401. }
  402. live_dangerously = new_live_dangerously;
  403. }
  404. int ast_thread_inhibit_escalations(void)
  405. {
  406. int *thread_inhibit_escalations;
  407. thread_inhibit_escalations = ast_threadstorage_get(
  408. &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
  409. if (thread_inhibit_escalations == NULL) {
  410. ast_log(LOG_ERROR, "Error inhibiting privilege escalations for current thread\n");
  411. return -1;
  412. }
  413. *thread_inhibit_escalations = 1;
  414. return 0;
  415. }
  416. int ast_thread_inhibit_escalations_swap(int inhibit)
  417. {
  418. int *thread_inhibit_escalations;
  419. int orig;
  420. thread_inhibit_escalations = ast_threadstorage_get(
  421. &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
  422. if (thread_inhibit_escalations == NULL) {
  423. ast_log(LOG_ERROR, "Error swapping privilege escalations inhibit for current thread\n");
  424. return -1;
  425. }
  426. orig = *thread_inhibit_escalations;
  427. *thread_inhibit_escalations = !!inhibit;
  428. return orig;
  429. }
  430. /*!
  431. * \brief Indicates whether the current thread inhibits the execution of
  432. * dangerous functions.
  433. *
  434. * \return True (non-zero) if dangerous function execution is inhibited.
  435. * \return False (zero) if dangerous function execution is allowed.
  436. */
  437. static int thread_inhibits_escalations(void)
  438. {
  439. int *thread_inhibit_escalations;
  440. thread_inhibit_escalations = ast_threadstorage_get(
  441. &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
  442. if (thread_inhibit_escalations == NULL) {
  443. ast_log(LOG_ERROR, "Error checking thread's ability to run dangerous functions\n");
  444. /* On error, assume that we are inhibiting */
  445. return 1;
  446. }
  447. return *thread_inhibit_escalations;
  448. }
  449. /*!
  450. * \brief Determines whether execution of a custom function's read function
  451. * is allowed.
  452. *
  453. * \param acfptr Custom function to check
  454. * \return True (non-zero) if reading is allowed.
  455. * \return False (zero) if reading is not allowed.
  456. */
  457. static int is_read_allowed(struct ast_custom_function *acfptr)
  458. {
  459. if (!acfptr) {
  460. return 1;
  461. }
  462. if (!read_escalates(acfptr)) {
  463. return 1;
  464. }
  465. if (!thread_inhibits_escalations()) {
  466. return 1;
  467. }
  468. if (live_dangerously) {
  469. /* Global setting overrides the thread's preference */
  470. ast_debug(2, "Reading %s from a dangerous context\n",
  471. acfptr->name);
  472. return 1;
  473. }
  474. /* We have no reason to allow this function to execute */
  475. return 0;
  476. }
  477. /*!
  478. * \brief Determines whether execution of a custom function's write function
  479. * is allowed.
  480. *
  481. * \param acfptr Custom function to check
  482. * \return True (non-zero) if writing is allowed.
  483. * \return False (zero) if writing is not allowed.
  484. */
  485. static int is_write_allowed(struct ast_custom_function *acfptr)
  486. {
  487. if (!acfptr) {
  488. return 1;
  489. }
  490. if (!write_escalates(acfptr)) {
  491. return 1;
  492. }
  493. if (!thread_inhibits_escalations()) {
  494. return 1;
  495. }
  496. if (live_dangerously) {
  497. /* Global setting overrides the thread's preference */
  498. ast_debug(2, "Writing %s from a dangerous context\n",
  499. acfptr->name);
  500. return 1;
  501. }
  502. /* We have no reason to allow this function to execute */
  503. return 0;
  504. }
  505. int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
  506. {
  507. char *copy = ast_strdupa(function);
  508. char *args = func_args(copy);
  509. struct ast_custom_function *acfptr = ast_custom_function_find(copy);
  510. int res;
  511. struct ast_module_user *u = NULL;
  512. if (acfptr == NULL) {
  513. ast_log(LOG_ERROR, "Function %s not registered\n", copy);
  514. } else if (!acfptr->read && !acfptr->read2) {
  515. ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
  516. } else if (!is_read_allowed(acfptr)) {
  517. ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
  518. } else if (acfptr->read) {
  519. if (acfptr->mod) {
  520. u = __ast_module_user_add(acfptr->mod, chan);
  521. }
  522. res = acfptr->read(chan, copy, args, workspace, len);
  523. if (acfptr->mod && u) {
  524. __ast_module_user_remove(acfptr->mod, u);
  525. }
  526. return res;
  527. } else {
  528. struct ast_str *str = ast_str_create(16);
  529. if (acfptr->mod) {
  530. u = __ast_module_user_add(acfptr->mod, chan);
  531. }
  532. res = acfptr->read2(chan, copy, args, &str, 0);
  533. if (acfptr->mod && u) {
  534. __ast_module_user_remove(acfptr->mod, u);
  535. }
  536. ast_copy_string(workspace, ast_str_buffer(str), len > ast_str_size(str) ? ast_str_size(str) : len);
  537. ast_free(str);
  538. return res;
  539. }
  540. return -1;
  541. }
  542. int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
  543. {
  544. char *copy = ast_strdupa(function);
  545. char *args = func_args(copy);
  546. struct ast_custom_function *acfptr = ast_custom_function_find(copy);
  547. int res;
  548. struct ast_module_user *u = NULL;
  549. if (acfptr == NULL) {
  550. ast_log(LOG_ERROR, "Function %s not registered\n", copy);
  551. } else if (!acfptr->read && !acfptr->read2) {
  552. ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
  553. } else if (!is_read_allowed(acfptr)) {
  554. ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
  555. } else {
  556. if (acfptr->mod) {
  557. u = __ast_module_user_add(acfptr->mod, chan);
  558. }
  559. ast_str_reset(*str);
  560. if (acfptr->read2) {
  561. /* ast_str enabled */
  562. res = acfptr->read2(chan, copy, args, str, maxlen);
  563. } else {
  564. /* Legacy function pointer, allocate buffer for result */
  565. int maxsize = ast_str_size(*str);
  566. if (maxlen > -1) {
  567. if (maxlen == 0) {
  568. if (acfptr->read_max) {
  569. maxsize = acfptr->read_max;
  570. } else {
  571. maxsize = VAR_BUF_SIZE;
  572. }
  573. } else {
  574. maxsize = maxlen;
  575. }
  576. ast_str_make_space(str, maxsize);
  577. }
  578. res = acfptr->read(chan, copy, args, ast_str_buffer(*str), maxsize);
  579. }
  580. if (acfptr->mod && u) {
  581. __ast_module_user_remove(acfptr->mod, u);
  582. }
  583. return res;
  584. }
  585. return -1;
  586. }
  587. int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
  588. {
  589. char *copy = ast_strdupa(function);
  590. char *args = func_args(copy);
  591. struct ast_custom_function *acfptr = ast_custom_function_find(copy);
  592. if (acfptr == NULL) {
  593. ast_log(LOG_ERROR, "Function %s not registered\n", copy);
  594. } else if (!acfptr->write) {
  595. ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
  596. } else if (!is_write_allowed(acfptr)) {
  597. ast_log(LOG_ERROR, "Dangerous function %s write blocked\n", copy);
  598. } else {
  599. int res;
  600. struct ast_module_user *u = NULL;
  601. if (acfptr->mod) {
  602. u = __ast_module_user_add(acfptr->mod, chan);
  603. }
  604. res = acfptr->write(chan, copy, args, value);
  605. if (acfptr->mod && u) {
  606. __ast_module_user_remove(acfptr->mod, u);
  607. }
  608. return res;
  609. }
  610. return -1;
  611. }
  612. static struct ast_cli_entry acf_cli[] = {
  613. AST_CLI_DEFINE(handle_show_functions, "Shows registered dialplan functions"),
  614. AST_CLI_DEFINE(handle_show_function, "Describe a specific dialplan function"),
  615. };
  616. static void unload_pbx_functions_cli(void)
  617. {
  618. ast_cli_unregister_multiple(acf_cli, ARRAY_LEN(acf_cli));
  619. }
  620. int load_pbx_functions_cli(void)
  621. {
  622. ast_cli_register_multiple(acf_cli, ARRAY_LEN(acf_cli));
  623. ast_register_cleanup(unload_pbx_functions_cli);
  624. return 0;
  625. }