pbx_functions.c 19 KB

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