Asterisk - The Open Source Telephony Project GIT-master-80b953f
Loading...
Searching...
No Matches
Data Structures | Functions | Variables
pbx_functions.c File Reference

Custom function management routines. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/cli.h"
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/term.h"
#include "asterisk/threadstorage.h"
#include "asterisk/xmldoc.h"
#include "pbx_private.h"
Include dependency graph for pbx_functions.c:

Go to the source code of this file.

Data Structures

struct  acf_root
 Registered functions container. More...
 

Functions

int __ast_custom_function_register (struct ast_custom_function *acf, struct ast_module *mod)
 Register a custom function.
 
int __ast_custom_function_register_escalating (struct ast_custom_function *acf, enum ast_custom_function_escalation escalation, struct ast_module *mod)
 Register a custom function which requires escalated privileges.
 
static int acf_retrieve_docs (struct ast_custom_function *acf)
 
struct ast_custom_functionast_custom_function_find (const char *name)
 
static struct ast_custom_functionast_custom_function_find_nolock (const char *name)
 
int ast_custom_function_unregister (struct ast_custom_function *acf)
 Unregister a custom function.
 
int ast_func_read (struct ast_channel *chan, const char *function, char *workspace, size_t len)
 executes a read operation on a function
 
int ast_func_read2 (struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
 executes a read operation on a function
 
int ast_func_write (struct ast_channel *chan, const char *function, const char *value)
 executes a write operation on a function
 
int ast_thread_inhibit_escalations (void)
 Inhibit (in the current thread) the execution of dialplan functions which cause privilege escalations. If pbx_live_dangerously() has been called, this function has no effect.
 
int ast_thread_inhibit_escalations_swap (int inhibit)
 Swap the current thread escalation inhibit setting.
 
 AST_THREADSTORAGE_CUSTOM_SCOPE (thread_inhibit_escalations_tl, NULL, ast_free_ptr, static)
 A thread local indicating whether the current thread can run 'dangerous' dialplan functions.
 
static char * complete_functions (const char *word, int pos, int state)
 
static char * func_args (char *function)
 return a pointer to the arguments of the function, and terminates the function name with '\0'
 
static char * handle_show_function (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_show_functions (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int is_read_allowed (struct ast_custom_function *acfptr)
 Determines whether execution of a custom function's read function is allowed.
 
static int is_write_allowed (struct ast_custom_function *acfptr)
 Determines whether execution of a custom function's write function is allowed.
 
int load_pbx_functions_cli (void)
 
void pbx_live_dangerously (int new_live_dangerously)
 Enable/disable the execution of 'dangerous' functions from external protocols (AMI, etc.).
 
static int read_escalates (const struct ast_custom_function *acf)
 Returns true if given custom function escalates privileges on read.
 
static int thread_inhibits_escalations (void)
 Indicates whether the current thread inhibits the execution of dangerous functions.
 
static void unload_pbx_functions_cli (void)
 
static int write_escalates (const struct ast_custom_function *acf)
 Returns true if given custom function escalates privileges on write.
 

Variables

static struct ast_cli_entry acf_cli []
 
static struct acf_root acf_root = AST_RWLIST_HEAD_INIT_VALUE
 
static int live_dangerously
 Set to true (non-zero) to globally allow all dangerous dialplan functions to run.
 

Detailed Description

Custom function management routines.

Author
Corey Farrell git@c.nosp@m.fwar.nosp@m.e.com

Definition in file pbx_functions.c.

Function Documentation

◆ __ast_custom_function_register()

int __ast_custom_function_register ( struct ast_custom_function acf,
struct ast_module mod 
)

Register a custom function.

Definition at line 388 of file pbx_functions.c.

389{
390 struct ast_custom_function *cur;
391
392 if (!acf) {
393 return -1;
394 }
395
396 acf->mod = mod;
397#ifdef AST_XML_DOCS
398 acf->docsrc = AST_STATIC_DOC;
399#endif
400
401 if (acf_retrieve_docs(acf)) {
402 return -1;
403 }
404
406
408 if (cur) {
409 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
411 return -1;
412 }
413
414 /* Store in alphabetical order */
416 if (strcmp(acf->name, cur->name) < 0) {
418 break;
419 }
420 }
422 if (!cur) {
424 }
425
427
428 ast_verb(5, "Registered custom function '" COLORIZE_FMT "'\n", COLORIZE(COLOR_BRCYAN, 0, acf->name));
429
430 return 0;
431}
#define ast_log
Definition astobj2.c:42
#define LOG_ERROR
#define ast_verb(level,...)
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_RWLIST_TRAVERSE_SAFE_END
#define AST_RWLIST_INSERT_TAIL
#define AST_RWLIST_INSERT_BEFORE_CURRENT
static struct ast_custom_function * ast_custom_function_find_nolock(const char *name)
static int acf_retrieve_docs(struct ast_custom_function *acf)
Registered functions container.
Data structure associated with a custom dialplan function.
Definition pbx.h:118
struct ast_custom_function::@252 acflist
struct ast_module * mod
Definition pbx.h:142
enum ast_doc_src docsrc
Definition pbx.h:127
const char * name
Definition pbx.h:119
#define COLOR_BRCYAN
Definition term.h:63
#define COLORIZE(fg, bg, str)
Definition term.h:72
#define COLORIZE_FMT
Shortcut macros for coloring a set of text.
Definition term.h:71
@ AST_STATIC_DOC
Definition xmldoc.h:32

References acf_retrieve_docs(), ast_custom_function::acflist, ast_custom_function_find_nolock(), ast_log, AST_RWLIST_INSERT_BEFORE_CURRENT, AST_RWLIST_INSERT_TAIL, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, AST_STATIC_DOC, ast_verb, COLOR_BRCYAN, COLORIZE, COLORIZE_FMT, ast_custom_function::docsrc, LOG_ERROR, ast_custom_function::mod, and ast_custom_function::name.

Referenced by __ast_custom_function_register_escalating(), __init_manager(), ast_msg_init(), load_features_config(), and load_pbx().

◆ __ast_custom_function_register_escalating()

int __ast_custom_function_register_escalating ( struct ast_custom_function acf,
enum ast_custom_function_escalation  escalation,
struct ast_module mod 
)

Register a custom function which requires escalated privileges.

Examples would be SHELL() (for which a read needs permission to execute arbitrary code) or FILE() (for which write needs permission to change files on the filesystem).

Definition at line 433 of file pbx_functions.c.

434{
435 int res;
436
437 res = __ast_custom_function_register(acf, mod);
438 if (res != 0) {
439 return -1;
440 }
441
442 switch (escalation) {
443 case AST_CFE_NONE:
444 break;
445 case AST_CFE_READ:
446 acf->read_escalates = 1;
447 break;
448 case AST_CFE_WRITE:
449 acf->write_escalates = 1;
450 break;
451 case AST_CFE_BOTH:
452 acf->read_escalates = 1;
453 acf->write_escalates = 1;
454 break;
455 }
456
457 return 0;
458}
@ AST_CFE_NONE
Definition pbx.h:1554
@ AST_CFE_READ
Definition pbx.h:1555
@ AST_CFE_WRITE
Definition pbx.h:1556
@ AST_CFE_BOTH
Definition pbx.h:1557
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
Register a custom function.
unsigned int read_escalates
Definition pbx.h:143
unsigned int write_escalates
Definition pbx.h:147

References __ast_custom_function_register(), AST_CFE_BOTH, AST_CFE_NONE, AST_CFE_READ, AST_CFE_WRITE, ast_custom_function::mod, ast_custom_function::read_escalates, and ast_custom_function::write_escalates.

◆ acf_retrieve_docs()

static int acf_retrieve_docs ( struct ast_custom_function acf)
static

Definition at line 323 of file pbx_functions.c.

324{
325#ifdef AST_XML_DOCS
326 char *tmpxml;
327
328 /* Let's try to find it in the Documentation XML */
329 if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
330 return 0;
331 }
332
333 if (ast_string_field_init(acf, 128)) {
334 return -1;
335 }
336
337 if (ast_string_field_init_extended(acf, since)) {
339 return -1;
340 }
341
342 if (ast_string_field_init_extended(acf, provided_by)) {
344 return -1;
345 }
346
347 /* load synopsis */
348 tmpxml = ast_xmldoc_build_synopsis("function", acf->name, ast_module_name(acf->mod));
349 ast_string_field_set(acf, synopsis, tmpxml);
350 ast_free(tmpxml);
351
352 /* load provided_by */
353 tmpxml = ast_xmldoc_build_provided_by("function", acf->name, ast_module_name(acf->mod));
354 ast_string_field_set(acf, provided_by, tmpxml);
355 ast_free(tmpxml);
356
357 /* load since */
358 tmpxml = ast_xmldoc_build_since("function", acf->name, ast_module_name(acf->mod));
359 ast_string_field_set(acf, since, tmpxml);
360 ast_free(tmpxml);
361
362 /* load description */
363 tmpxml = ast_xmldoc_build_description("function", acf->name, ast_module_name(acf->mod));
364 ast_string_field_set(acf, desc, tmpxml);
365 ast_free(tmpxml);
366
367 /* load syntax */
368 tmpxml = ast_xmldoc_build_syntax("function", acf->name, ast_module_name(acf->mod));
369 ast_string_field_set(acf, syntax, tmpxml);
370 ast_free(tmpxml);
371
372 /* load arguments */
373 tmpxml = ast_xmldoc_build_arguments("function", acf->name, ast_module_name(acf->mod));
374 ast_string_field_set(acf, arguments, tmpxml);
375 ast_free(tmpxml);
376
377 /* load seealso */
378 tmpxml = ast_xmldoc_build_seealso("function", acf->name, ast_module_name(acf->mod));
379 ast_string_field_set(acf, seealso, tmpxml);
380 ast_free(tmpxml);
381
382 acf->docsrc = AST_XML_DOC;
383#endif
384
385 return 0;
386}
#define ast_free(a)
Definition astmm.h:180
static const char desc[]
Definition cdr_radius.c:84
static char * synopsis
Definition func_enum.c:166
const char * ast_module_name(const struct ast_module *mod)
Get the name of a module.
Definition loader.c:624
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_init_extended(x, field)
Initialize an extended string field.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
const ast_string_field desc
Definition pbx.h:126
const ast_string_field synopsis
Definition pbx.h:126
char * ast_xmldoc_build_description(const char *type, const char *name, const char *module)
Generate description documentation from XML.
Definition xmldoc.c:2418
char * ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
Get the syntax for a specified application or function.
Definition xmldoc.c:1252
char * ast_xmldoc_build_arguments(const char *type, const char *name, const char *module)
Generate the [arguments] tag based on type of node ('application', 'function' or 'agi') and name.
Definition xmldoc.c:2231
char * ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
Generate synopsis documentation from XML.
Definition xmldoc.c:2395
char * ast_xmldoc_build_since(const char *type, const char *name, const char *module)
Parse the <since> node content.
Definition xmldoc.c:1792
@ AST_XML_DOC
Definition xmldoc.h:31
char * ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
Parse the <see-also> node content.
Definition xmldoc.c:1707
char * ast_xmldoc_build_provided_by(const char *type, const char *name, const char *module)
Generate provided-by documentation from XML.
Definition xmldoc.c:1844

References ast_custom_function::arguments, ast_free, ast_module_name(), ast_string_field_free_memory, ast_string_field_init, ast_string_field_init_extended, ast_string_field_set, ast_strlen_zero(), AST_XML_DOC, ast_xmldoc_build_arguments(), ast_xmldoc_build_description(), ast_xmldoc_build_provided_by(), ast_xmldoc_build_seealso(), ast_xmldoc_build_since(), ast_xmldoc_build_synopsis(), ast_xmldoc_build_syntax(), desc, ast_custom_function::desc, ast_custom_function::docsrc, ast_custom_function::mod, ast_custom_function::name, ast_custom_function::seealso, synopsis, ast_custom_function::synopsis, and ast_custom_function::syntax.

Referenced by __ast_custom_function_register().

◆ ast_custom_function_find()

struct ast_custom_function * ast_custom_function_find ( const char *  name)

Definition at line 257 of file pbx_functions.c.

258{
259 struct ast_custom_function *acf;
260
264
265 return acf;
266}
static const char name[]
Definition format_mp3.c:68
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition linkedlists.h:78

References ast_custom_function_find_nolock(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, and name.

Referenced by ast_func_read(), ast_func_read2(), ast_func_write(), and handle_show_function().

◆ ast_custom_function_find_nolock()

static struct ast_custom_function * ast_custom_function_find_nolock ( const char *  name)
static

Definition at line 235 of file pbx_functions.c.

236{
237 struct ast_custom_function *cur;
238 int cmp;
239
241 cmp = strcmp(name, cur->name);
242 if (cmp > 0) {
243 continue;
244 }
245 if (!cmp) {
246 /* Found it. */
247 break;
248 }
249 /* Not in container. */
250 cur = NULL;
251 break;
252 }
253
254 return cur;
255}
#define AST_RWLIST_TRAVERSE
#define NULL
Definition resample.c:96

References ast_custom_function::acflist, AST_RWLIST_TRAVERSE, name, ast_custom_function::name, and NULL.

Referenced by __ast_custom_function_register(), and ast_custom_function_find().

◆ ast_custom_function_unregister()

int ast_custom_function_unregister ( struct ast_custom_function acf)

Unregister a custom function.

Definition at line 268 of file pbx_functions.c.

269{
270 struct ast_custom_function *cur;
271
272 if (!acf) {
273 return -1;
274 }
275
277 cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist);
278 if (cur) {
279#ifdef AST_XML_DOCS
280 if (cur->docsrc == AST_XML_DOC) {
282 }
283#endif
284 ast_verb(5, "Unregistered custom function %s\n", cur->name);
285 }
287
288 return cur ? 0 : -1;
289}
#define AST_RWLIST_REMOVE

References ast_custom_function::acflist, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_string_field_free_memory, ast_verb, AST_XML_DOC, ast_custom_function::docsrc, and ast_custom_function::name.

Referenced by __unload_module(), close_logger(), geoloc_dialplan_unload(), load_module(), load_module(), manager_shutdown(), message_shutdown(), reload(), unload_features_config(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_module(), unload_parking_bridge_features(), and unload_pbx().

◆ ast_func_read()

int ast_func_read ( struct ast_channel chan,
const char *  function,
char *  workspace,
size_t  len 
)

executes a read operation on a function

Parameters
chanChannel to execute on
functionData containing the function call string (will be modified)
workspaceA pointer to safe memory to use for a return value
lenthe number of bytes in workspace

This application executes a function in read mode on a given channel.

Return values
0success
non-zerofailure

Definition at line 614 of file pbx_functions.c.

615{
616 char *copy = ast_strdupa(function);
617 char *args = func_args(copy);
619 int res;
620 struct ast_module_user *u = NULL;
621
622 if (acfptr == NULL) {
623 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
624 } else if (!acfptr->read && !acfptr->read2) {
625 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
626 } else if (!is_read_allowed(acfptr)) {
627 ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
628 } else if (acfptr->read) {
629 if (acfptr->mod) {
630 u = __ast_module_user_add(acfptr->mod, chan);
631 }
632 res = acfptr->read(chan, copy, args, workspace, len);
633 if (acfptr->mod && u) {
634 __ast_module_user_remove(acfptr->mod, u);
635 }
636
637 return res;
638 } else {
639 struct ast_str *str = ast_str_create(16);
640
641 if (acfptr->mod) {
642 u = __ast_module_user_add(acfptr->mod, chan);
643 }
644 res = acfptr->read2(chan, copy, args, &str, 0);
645 if (acfptr->mod && u) {
646 __ast_module_user_remove(acfptr->mod, u);
647 }
649 ast_free(str);
650
651 return res;
652 }
653
654 return -1;
655}
const char * str
Definition app_jack.c:150
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct ast_module_user * __ast_module_user_add(struct ast_module *, struct ast_channel *)
Definition loader.c:809
void __ast_module_user_remove(struct ast_module *, struct ast_module_user *)
Definition loader.c:835
static int is_read_allowed(struct ast_custom_function *acfptr)
Determines whether execution of a custom function's read function is allowed.
struct ast_custom_function * ast_custom_function_find(const char *name)
static char * func_args(char *function)
return a pointer to the arguments of the function, and terminates the function name with '\0'
static struct @521 args
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
size_t attribute_pure ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition strings.h:742
ast_acf_read_fn_t read
Definition pbx.h:129
ast_acf_read2_fn_t read2
Definition pbx.h:137
struct ast_channel * chan
Definition loader.c:137
Support for dynamic strings.
Definition strings.h:623

References __ast_module_user_add(), __ast_module_user_remove(), args, ast_copy_string(), ast_custom_function_find(), ast_free, ast_log, ast_str_buffer(), ast_str_create, ast_str_size(), ast_strdupa, ast_module_user::chan, copy(), func_args(), is_read_allowed(), len(), LOG_ERROR, ast_custom_function::mod, NULL, ast_custom_function::read, ast_custom_function::read2, and str.

Referenced by action_getvar(), assign_uuid(), fetch_access_token(), fetch_google_access_token(), generate_status(), handle_eval_function(), handle_getvariable(), lua_get_variable_value(), and pbx_substitute_variables_helper_full_location().

◆ ast_func_read2()

int ast_func_read2 ( struct ast_channel chan,
const char *  function,
struct ast_str **  str,
ssize_t  maxlen 
)

executes a read operation on a function

Parameters
chanChannel to execute on
functionData containing the function call string (will be modified)
strA dynamic string buffer into which to place the result.
maxlen<0 if the dynamic buffer should not grow; >0 if the dynamic buffer should be limited to that number of bytes; 0 if the dynamic buffer has no upper limit

This application executes a function in read mode on a given channel.

Return values
0success
non-zerofailure

Definition at line 657 of file pbx_functions.c.

658{
659 char *copy = ast_strdupa(function);
660 char *args = func_args(copy);
662 int res;
663 struct ast_module_user *u = NULL;
664
665 if (acfptr == NULL) {
666 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
667 } else if (!acfptr->read && !acfptr->read2) {
668 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
669 } else if (!is_read_allowed(acfptr)) {
670 ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
671 } else {
672 if (acfptr->mod) {
673 u = __ast_module_user_add(acfptr->mod, chan);
674 }
676 if (acfptr->read2) {
677 /* ast_str enabled */
678 res = acfptr->read2(chan, copy, args, str, maxlen);
679 } else {
680 /* Legacy function pointer, allocate buffer for result */
681 int maxsize = ast_str_size(*str);
682
683 if (maxlen > -1) {
684 if (maxlen == 0) {
685 if (acfptr->read_max) {
686 maxsize = acfptr->read_max;
687 } else {
689 }
690 } else {
691 maxsize = maxlen;
692 }
694 }
695 res = acfptr->read(chan, copy, args, ast_str_buffer(*str), maxsize);
696 ast_str_update(*str); /* Manually set the string length */
697 }
698 if (acfptr->mod && u) {
699 __ast_module_user_remove(acfptr->mod, u);
700 }
701
702 return res;
703 }
704
705 return -1;
706}
static int maxsize
#define VAR_BUF_SIZE
Definition pbx_private.h:68
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition strings.h:693
#define ast_str_make_space(buf, new_len)
Definition strings.h:828
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
Definition strings.h:703
size_t read_max
Definition pbx.h:139

References __ast_module_user_add(), __ast_module_user_remove(), args, ast_custom_function_find(), ast_log, ast_str_buffer(), ast_str_make_space, ast_str_reset(), ast_str_size(), ast_str_update(), ast_strdupa, ast_module_user::chan, copy(), func_args(), is_read_allowed(), LOG_ERROR, maxsize, ast_custom_function::mod, NULL, ast_custom_function::read, ast_custom_function::read2, ast_custom_function::read_max, str, and VAR_BUF_SIZE.

Referenced by ast_ari_channels_get_channel_var(), ast_str_substitute_variables_full2(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), and channel_get_external_vars().

◆ ast_func_write()

int ast_func_write ( struct ast_channel chan,
const char *  function,
const char *  value 
)

executes a write operation on a function

Parameters
chanChannel to execute on
functionData containing the function call string (will be modified)
valueA value parameter to pass for writing

This application executes a function in write mode on a given channel.

Return values
0success
non-zerofailure

Definition at line 708 of file pbx_functions.c.

709{
710 char *copy = ast_strdupa(function);
711 char *args = func_args(copy);
713
714 if (acfptr == NULL) {
715 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
716 } else if (!acfptr->write) {
717 ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
718 } else if (!is_write_allowed(acfptr)) {
719 ast_log(LOG_ERROR, "Dangerous function %s write blocked\n", copy);
720 } else {
721 int res;
722 struct ast_module_user *u = NULL;
723
724 if (acfptr->mod) {
725 u = __ast_module_user_add(acfptr->mod, chan);
726 }
727 res = acfptr->write(chan, copy, args, value);
728 if (acfptr->mod && u) {
729 __ast_module_user_remove(acfptr->mod, u);
730 }
731
732 return res;
733 }
734
735 return -1;
736}
static int is_write_allowed(struct ast_custom_function *acfptr)
Determines whether execution of a custom function's write function is allowed.
ast_acf_write_fn_t write
Definition pbx.h:141
int value
Definition syslog.c:37

References __ast_module_user_add(), __ast_module_user_remove(), args, ast_custom_function_find(), ast_log, ast_strdupa, ast_module_user::chan, copy(), func_args(), is_write_allowed(), LOG_ERROR, ast_custom_function::mod, NULL, value, and ast_custom_function::write.

Referenced by ast_channel_hangupcause_hash_set(), AST_TEST_DEFINE(), chanavail_exec(), conf_run(), conf_run(), confbridge_exec(), disa_exec(), fetch_google_access_token(), pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), setup_profile_bridge(), setup_profile_caller(), and setup_profile_paged().

◆ ast_thread_inhibit_escalations()

int ast_thread_inhibit_escalations ( void  )

Inhibit (in the current thread) the execution of dialplan functions which cause privilege escalations. If pbx_live_dangerously() has been called, this function has no effect.

Returns
0 if successfuly marked current thread.
Non-zero if marking current thread failed.

Definition at line 494 of file pbx_functions.c.

495{
496 int *thread_inhibit_escalations;
497
498 thread_inhibit_escalations = ast_threadstorage_get(
499 &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
500 if (thread_inhibit_escalations == NULL) {
501 ast_log(LOG_ERROR, "Error inhibiting privilege escalations for current thread\n");
502 return -1;
503 }
504
505 *thread_inhibit_escalations = 1;
506 return 0;
507}
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.

References ast_log, ast_threadstorage_get(), LOG_ERROR, and NULL.

Referenced by ast_add_extension2_lockopt(), and handle_tcptls_connection().

◆ ast_thread_inhibit_escalations_swap()

int ast_thread_inhibit_escalations_swap ( int  inhibit)

Swap the current thread escalation inhibit setting.

Since
11.24.0
Parameters
inhibitNew setting. Non-zero to inhibit.
Return values
1if dangerous function execution was inhibited.
0if dangerous function execution was allowed.
-1on error.

Definition at line 509 of file pbx_functions.c.

510{
511 int *thread_inhibit_escalations;
512 int orig;
513
514 thread_inhibit_escalations = ast_threadstorage_get(
515 &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
516 if (thread_inhibit_escalations == NULL) {
517 ast_log(LOG_ERROR, "Error swapping privilege escalations inhibit for current thread\n");
518 return -1;
519 }
520
521 orig = *thread_inhibit_escalations;
522 *thread_inhibit_escalations = !!inhibit;
523 return orig;
524}

References ast_log, ast_threadstorage_get(), LOG_ERROR, and NULL.

Referenced by ast_add_extension2_lockopt().

◆ AST_THREADSTORAGE_CUSTOM_SCOPE()

AST_THREADSTORAGE_CUSTOM_SCOPE ( thread_inhibit_escalations_tl  ,
NULL  ,
ast_free_ptr  ,
static   
)

A thread local indicating whether the current thread can run 'dangerous' dialplan functions.

◆ complete_functions()

static char * complete_functions ( const char *  word,
int  pos,
int  state 
)
static

Definition at line 105 of file pbx_functions.c.

106{
107 struct ast_custom_function *cur;
108 char *ret = NULL;
109 int which = 0;
110 int wordlen;
111 int cmp;
112
113 if (pos != 3) {
114 return NULL;
115 }
116
117 wordlen = strlen(word);
120 /*
121 * Do a case-insensitive search for convenience in this
122 * 'complete' function.
123 *
124 * We must search the entire container because the functions are
125 * sorted and normally found case sensitively.
126 */
127 cmp = strncasecmp(word, cur->name, wordlen);
128 if (!cmp) {
129 /* Found match. */
130 if (++which <= state) {
131 /* Not enough matches. */
132 continue;
133 }
134 ret = ast_strdup(cur->name);
135 break;
136 }
137 }
139
140 return ret;
141}
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
short word

References ast_custom_function::acflist, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, ast_custom_function::name, and NULL.

Referenced by handle_show_function().

◆ func_args()

static char * func_args ( char *  function)
static

return a pointer to the arguments of the function, and terminates the function name with '\0'

Definition at line 463 of file pbx_functions.c.

464{
465 char *args = strchr(function, '(');
466
467 if (!args) {
468 ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses. Assuming null argument.\n", function);
469 } else {
470 char *p;
471 *args++ = '\0';
472 if ((p = strrchr(args, ')'))) {
473 *p = '\0';
474 } else {
475 ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
476 }
477 }
478 return args;
479}
#define LOG_WARNING

References args, ast_log, and LOG_WARNING.

Referenced by ast_func_read(), ast_func_read2(), ast_func_write(), pjsip_acf_channel_read(), pjsip_acf_parse_uri_read(), and read_pjsip().

◆ handle_show_function()

static char * handle_show_function ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 143 of file pbx_functions.c.

144{
145 struct ast_custom_function *acf;
146 /* Maximum number of characters added by terminal coloring is 22 */
147 char *synopsis = NULL, *provided_by = NULL, *since = NULL, *description = NULL, *syntax = NULL, *arguments = NULL, *seealso = NULL;
148 char *rtn = CLI_SUCCESS;
149
150 switch (cmd) {
151 case CLI_INIT:
152 e->command = "core show function";
153 e->usage =
154 "Usage: core show function <function>\n"
155 " Describe a particular dialplan function.\n";
156 return NULL;
157 case CLI_GENERATE:
158 return complete_functions(a->word, a->pos, a->n);
159 }
160
161 if (a->argc != 4) {
162 return CLI_SHOWUSAGE;
163 }
164
165 if (!(acf = ast_custom_function_find(a->argv[3]))) {
166 ast_cli(a->fd, "No function by that name registered.\n");
167
168 return CLI_FAILURE;
169 }
170
171#ifdef AST_XML_DOCS
172 if (acf->docsrc == AST_XML_DOC) {
173 synopsis = ast_xmldoc_printable(S_OR(acf->synopsis, "Not available"), 1);
174 provided_by = ast_xmldoc_printable(S_OR(acf->provided_by, "Not available"), 1);
175 since = ast_xmldoc_printable(S_OR(acf->since, "Not available"), 1);
176 description = ast_xmldoc_printable(S_OR(acf->desc, "Not available"), 1);
177 syntax = ast_xmldoc_printable(S_OR(acf->syntax, "Not available"), 1);
178 arguments = ast_xmldoc_printable(S_OR(acf->arguments, "Not available"), 1);
179 seealso = ast_xmldoc_printable(S_OR(acf->seealso, "Not available"), 1);
180 } else
181#endif
182 {
183 synopsis = ast_strdup(S_OR(acf->synopsis, "Not Available"));
184 provided_by = ast_strdup(S_OR(acf->provided_by, "Not available"));
185 since = ast_strdup(S_OR(acf->since, "Not Available"));
186 description = ast_strdup(S_OR(acf->desc, "Not Available"));
187 syntax = ast_strdup(S_OR(acf->syntax, "Not Available"));
188 arguments = ast_strdup(S_OR(acf->arguments, "Not Available"));
189 seealso = ast_strdup(S_OR(acf->seealso, "Not Available"));
190 }
191 /* check allocated memory. */
192 if (!synopsis || !provided_by || !since || !description || !syntax || !arguments || !seealso) {
193 rtn = CLI_FAILURE;
194 goto free_docs;
195 }
196
197 ast_cli(a->fd, "\n"
198 "%s -= Info about Function '%s' =- %s\n\n"
199 COLORIZE_FMT "\n"
200 "%s\n\n"
201 COLORIZE_FMT "\n"
202 "%s\n\n"
203 COLORIZE_FMT "\n"
204 "%s\n\n"
205 COLORIZE_FMT "\n"
206 "%s\n\n"
207 COLORIZE_FMT "\n"
208 "%s\n\n"
209 COLORIZE_FMT "\n"
210 "%s\n\n"
211 COLORIZE_FMT "\n"
212 "%s\n\n",
214 COLORIZE(COLOR_MAGENTA, 0, "[Synopsis]"), synopsis,
215 COLORIZE(COLOR_MAGENTA, 0, "[Provided By]"), provided_by,
216 COLORIZE(COLOR_MAGENTA, 0, "[Since]"), since,
217 COLORIZE(COLOR_MAGENTA, 0, "[Description]"), description,
218 COLORIZE(COLOR_MAGENTA, 0, "[Syntax]"), syntax,
219 COLORIZE(COLOR_MAGENTA, 0, "[Arguments]"), arguments,
220 COLORIZE(COLOR_MAGENTA, 0, "[See Also]"), seealso
221 );
222
223free_docs:
225 ast_free(provided_by);
226 ast_free(since);
227 ast_free(description);
231
232 return rtn;
233}
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
static char * complete_functions(const char *word, int pos, int state)
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
const ast_string_field seealso
Definition pbx.h:126
const ast_string_field syntax
Definition pbx.h:126
const ast_string_field arguments
Definition pbx.h:126
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition term.c:357
#define COLOR_MAGENTA
Definition term.h:60
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition term.c:341
static struct test_val a
char * ast_xmldoc_printable(const char *bwinput, int withcolors)
Colorize and put delimiters (instead of tags) to the xmldoc output.
Definition xmldoc.c:241

References a, ast_custom_function::arguments, ast_cli(), ast_custom_function_find(), ast_free, ast_strdup, ast_term_color(), ast_term_reset(), AST_XML_DOC, ast_xmldoc_printable(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, COLOR_MAGENTA, COLORIZE, COLORIZE_FMT, ast_cli_entry::command, complete_functions(), ast_custom_function::desc, ast_custom_function::docsrc, ast_custom_function::name, NULL, S_OR, ast_custom_function::seealso, synopsis, ast_custom_function::synopsis, ast_custom_function::syntax, and ast_cli_entry::usage.

◆ handle_show_functions()

static char * handle_show_functions ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 61 of file pbx_functions.c.

62{
63 struct ast_custom_function *acf;
64 int count_acf = 0;
65 int like = 0;
66
67 switch (cmd) {
68 case CLI_INIT:
69 e->command = "core show functions [like]";
70 e->usage =
71 "Usage: core show functions [like <text>]\n"
72 " List builtin functions, optionally only those matching a given string\n";
73 return NULL;
74 case CLI_GENERATE:
75 return NULL;
76 }
77
78 if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
79 like = 1;
80 } else if (a->argc != 3) {
81 return CLI_SHOWUSAGE;
82 }
83
84 ast_cli(a->fd, "%s Custom Functions:\n"
85 "--------------------------------------------------------------------------------\n",
86 like ? "Matching" : "Installed");
87
90 if (!like || strstr(acf->name, a->argv[4])) {
91 count_acf++;
92 ast_cli(a->fd, "%-20.20s %-35.35s %s\n",
93 S_OR(acf->name, ""),
94 S_OR(acf->syntax, ""),
95 S_OR(acf->synopsis, ""));
96 }
97 }
99
100 ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
101
102 return CLI_SUCCESS;
103}

References a, ast_custom_function::acflist, ast_cli(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_custom_function::name, NULL, S_OR, ast_custom_function::synopsis, ast_custom_function::syntax, and ast_cli_entry::usage.

◆ is_read_allowed()

static int is_read_allowed ( struct ast_custom_function acfptr)
static

Determines whether execution of a custom function's read function is allowed.

Parameters
acfptrCustom function to check
Returns
True (non-zero) if reading is allowed.
False (zero) if reading is not allowed.

Definition at line 556 of file pbx_functions.c.

557{
558 if (!acfptr) {
559 return 1;
560 }
561
562 if (!read_escalates(acfptr)) {
563 return 1;
564 }
565
567 return 1;
568 }
569
570 if (live_dangerously) {
571 /* Global setting overrides the thread's preference */
572 ast_debug(2, "Reading %s from a dangerous context\n",
573 acfptr->name);
574 return 1;
575 }
576
577 /* We have no reason to allow this function to execute */
578 return 0;
579}
#define ast_debug(level,...)
Log a DEBUG message.
static int thread_inhibits_escalations(void)
Indicates whether the current thread inhibits the execution of dangerous functions.
static int read_escalates(const struct ast_custom_function *acf)
Returns true if given custom function escalates privileges on read.
static int live_dangerously
Set to true (non-zero) to globally allow all dangerous dialplan functions to run.

References ast_debug, live_dangerously, ast_custom_function::name, read_escalates(), and thread_inhibits_escalations().

Referenced by ast_func_read(), and ast_func_read2().

◆ is_write_allowed()

static int is_write_allowed ( struct ast_custom_function acfptr)
static

Determines whether execution of a custom function's write function is allowed.

Parameters
acfptrCustom function to check
Returns
True (non-zero) if writing is allowed.
False (zero) if writing is not allowed.

Definition at line 589 of file pbx_functions.c.

590{
591 if (!acfptr) {
592 return 1;
593 }
594
595 if (!write_escalates(acfptr)) {
596 return 1;
597 }
598
600 return 1;
601 }
602
603 if (live_dangerously) {
604 /* Global setting overrides the thread's preference */
605 ast_debug(2, "Writing %s from a dangerous context\n",
606 acfptr->name);
607 return 1;
608 }
609
610 /* We have no reason to allow this function to execute */
611 return 0;
612}
static int write_escalates(const struct ast_custom_function *acf)
Returns true if given custom function escalates privileges on write.

References ast_debug, live_dangerously, ast_custom_function::name, thread_inhibits_escalations(), and write_escalates().

Referenced by ast_func_write().

◆ load_pbx_functions_cli()

int load_pbx_functions_cli ( void  )

Provided by pbx_functions.c

Definition at line 748 of file pbx_functions.c.

749{
752
753 return 0;
754}
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition clicompat.c:19
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
static void unload_pbx_functions_cli(void)
static struct ast_cli_entry acf_cli[]
#define ARRAY_LEN(a)
Definition utils.h:706

References acf_cli, ARRAY_LEN, ast_cli_register_multiple, ast_register_cleanup(), and unload_pbx_functions_cli().

Referenced by asterisk_daemon().

◆ pbx_live_dangerously()

void pbx_live_dangerously ( int  new_live_dangerously)

Enable/disable the execution of 'dangerous' functions from external protocols (AMI, etc.).

These dialplan functions (such as SHELL) provide an opportunity for privilege escalation. They are okay to invoke from the dialplan, but external protocols with permission controls should not normally invoke them.

This function can globally enable/disable the execution of dangerous functions from external protocols.

Parameters
new_live_dangerouslyIf true, enable the execution of escalating functions from external protocols.

Definition at line 481 of file pbx_functions.c.

482{
483 if (new_live_dangerously && !live_dangerously) {
484 ast_log(LOG_WARNING, "Privilege escalation protection disabled!\n"
485 "See https://docs.asterisk.org/Configuration/Dialplan/Privilege-Escalations-with-Dialplan-Functions/ for more details.\n");
486 }
487
488 if (!new_live_dangerously && live_dangerously) {
489 ast_log(LOG_NOTICE, "Privilege escalation protection enabled.\n");
490 }
491 live_dangerously = new_live_dangerously;
492}
#define LOG_NOTICE

References ast_log, live_dangerously, LOG_NOTICE, and LOG_WARNING.

Referenced by load_asterisk_conf().

◆ read_escalates()

static int read_escalates ( const struct ast_custom_function acf)
static

Returns true if given custom function escalates privileges on read.

Parameters
acfCustom function to query.
Returns
True (non-zero) if reads escalate privileges.
False (zero) if reads just read.

Definition at line 298 of file pbx_functions.c.

299{
300 return acf->read_escalates;
301}

References ast_custom_function::read_escalates.

Referenced by is_read_allowed().

◆ thread_inhibits_escalations()

static int thread_inhibits_escalations ( void  )
static

Indicates whether the current thread inhibits the execution of dangerous functions.

Returns
True (non-zero) if dangerous function execution is inhibited.
False (zero) if dangerous function execution is allowed.

Definition at line 533 of file pbx_functions.c.

534{
535 int *thread_inhibit_escalations;
536
537 thread_inhibit_escalations = ast_threadstorage_get(
538 &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
539 if (thread_inhibit_escalations == NULL) {
540 ast_log(LOG_ERROR, "Error checking thread's ability to run dangerous functions\n");
541 /* On error, assume that we are inhibiting */
542 return 1;
543 }
544
545 return *thread_inhibit_escalations;
546}

References ast_log, ast_threadstorage_get(), LOG_ERROR, and NULL.

Referenced by is_read_allowed(), and is_write_allowed().

◆ unload_pbx_functions_cli()

static void unload_pbx_functions_cli ( void  )
static

Definition at line 743 of file pbx_functions.c.

744{
746}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408

References acf_cli, ARRAY_LEN, and ast_cli_unregister_multiple().

Referenced by load_pbx_functions_cli().

◆ write_escalates()

static int write_escalates ( const struct ast_custom_function acf)
static

Returns true if given custom function escalates privileges on write.

Parameters
acfCustom function to query.
Returns
True (non-zero) if writes escalate privileges.
False (zero) if writes just write.

Definition at line 310 of file pbx_functions.c.

311{
312 return acf->write_escalates;
313}

References ast_custom_function::write_escalates.

Referenced by is_write_allowed().

Variable Documentation

◆ acf_cli

struct ast_cli_entry acf_cli[]
static
Initial value:
= {
{ .handler = handle_show_functions , .summary = "Shows registered dialplan functions" ,},
{ .handler = handle_show_function , .summary = "Describe a specific dialplan function" ,},
}
static char * handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 738 of file pbx_functions.c.

738 {
739 AST_CLI_DEFINE(handle_show_functions, "Shows registered dialplan functions"),
740 AST_CLI_DEFINE(handle_show_function, "Describe a specific dialplan function"),
741};
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197

Referenced by load_pbx_functions_cli(), and unload_pbx_functions_cli().

◆ acf_root

◆ live_dangerously

int live_dangerously
static

Set to true (non-zero) to globally allow all dangerous dialplan functions to run.

Definition at line 52 of file pbx_functions.c.

Referenced by is_read_allowed(), is_write_allowed(), and pbx_live_dangerously().