Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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. More...
 
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. More...
 
static void __init_thread_inhibit_escalations_tl (void)
 A thread local indicating whether the current thread can run 'dangerous' dialplan functions. More...
 
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. More...
 
int ast_func_read (struct ast_channel *chan, const char *function, char *workspace, size_t len)
 executes a read operation on a function More...
 
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 More...
 
int ast_func_write (struct ast_channel *chan, const char *function, const char *value)
 executes a write operation on a function More...
 
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. More...
 
int ast_thread_inhibit_escalations_swap (int inhibit)
 Swap the current thread escalation inhibit setting. More...
 
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' More...
 
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. More...
 
static int is_write_allowed (struct ast_custom_function *acfptr)
 Determines whether execution of a custom function's write function is allowed. More...
 
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.). More...
 
static int read_escalates (const struct ast_custom_function *acf)
 Returns true if given custom function escalates privileges on read. More...
 
static int thread_inhibits_escalations (void)
 Indicates whether the current thread inhibits the execution of dangerous functions. More...
 
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. More...
 

Variables

static struct ast_cli_entry acf_cli []
 
static struct acf_root acf_root = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
static int live_dangerously
 Set to true (non-zero) to globally allow all dangerous dialplan functions to run. More...
 
static struct ast_threadstorage thread_inhibit_escalations_tl = { .once = PTHREAD_ONCE_INIT , .key_init = __init_thread_inhibit_escalations_tl , .custom_init = NULL , }
 

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 372 of file pbx_functions.c.

373{
374 struct ast_custom_function *cur;
375
376 if (!acf) {
377 return -1;
378 }
379
380 acf->mod = mod;
381#ifdef AST_XML_DOCS
382 acf->docsrc = AST_STATIC_DOC;
383#endif
384
385 if (acf_retrieve_docs(acf)) {
386 return -1;
387 }
388
390
392 if (cur) {
393 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
395 return -1;
396 }
397
398 /* Store in alphabetical order */
400 if (strcmp(acf->name, cur->name) < 0) {
402 break;
403 }
404 }
406 if (!cur) {
407 AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
408 }
409
411
412 ast_verb(5, "Registered custom function '" COLORIZE_FMT "'\n", COLORIZE(COLOR_BRCYAN, 0, acf->name));
413
414 return 0;
415}
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
#define ast_verb(level,...)
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:545
#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.
Definition: linkedlists.h:151
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:741
#define AST_RWLIST_INSERT_BEFORE_CURRENT
Definition: linkedlists.h:610
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.
Definition: pbx_functions.c:59
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
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_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 417 of file pbx_functions.c.

418{
419 int res;
420
421 res = __ast_custom_function_register(acf, mod);
422 if (res != 0) {
423 return -1;
424 }
425
426 switch (escalation) {
427 case AST_CFE_NONE:
428 break;
429 case AST_CFE_READ:
430 acf->read_escalates = 1;
431 break;
432 case AST_CFE_WRITE:
433 acf->write_escalates = 1;
434 break;
435 case AST_CFE_BOTH:
436 acf->read_escalates = 1;
437 acf->write_escalates = 1;
438 break;
439 }
440
441 return 0;
442}
@ AST_CFE_NONE
Definition: pbx.h:1550
@ AST_CFE_READ
Definition: pbx.h:1551
@ AST_CFE_WRITE
Definition: pbx.h:1552
@ AST_CFE_BOTH
Definition: pbx.h:1553
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.

◆ __init_thread_inhibit_escalations_tl()

static void __init_thread_inhibit_escalations_tl ( void  )
static

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

Definition at line 46 of file pbx_functions.c.

62{

◆ acf_retrieve_docs()

static int acf_retrieve_docs ( struct ast_custom_function acf)
static

Definition at line 317 of file pbx_functions.c.

318{
319#ifdef AST_XML_DOCS
320 char *tmpxml;
321
322 /* Let's try to find it in the Documentation XML */
323 if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
324 return 0;
325 }
326
327 if (ast_string_field_init(acf, 128)) {
328 return -1;
329 }
330
331 if (ast_string_field_init_extended(acf, since)) {
333 return -1;
334 }
335
336 /* load synopsis */
337 tmpxml = ast_xmldoc_build_synopsis("function", acf->name, ast_module_name(acf->mod));
338 ast_string_field_set(acf, synopsis, tmpxml);
339 ast_free(tmpxml);
340
341 /* load since */
342 tmpxml = ast_xmldoc_build_since("function", acf->name, ast_module_name(acf->mod));
343 ast_string_field_set(acf, since, tmpxml);
344 ast_free(tmpxml);
345
346 /* load description */
347 tmpxml = ast_xmldoc_build_description("function", acf->name, ast_module_name(acf->mod));
348 ast_string_field_set(acf, desc, tmpxml);
349 ast_free(tmpxml);
350
351 /* load syntax */
352 tmpxml = ast_xmldoc_build_syntax("function", acf->name, ast_module_name(acf->mod));
353 ast_string_field_set(acf, syntax, tmpxml);
354 ast_free(tmpxml);
355
356 /* load arguments */
357 tmpxml = ast_xmldoc_build_arguments("function", acf->name, ast_module_name(acf->mod));
358 ast_string_field_set(acf, arguments, tmpxml);
359 ast_free(tmpxml);
360
361 /* load seealso */
362 tmpxml = ast_xmldoc_build_seealso("function", acf->name, ast_module_name(acf->mod));
363 ast_string_field_set(acf, seealso, tmpxml);
364 ast_free(tmpxml);
365
366 acf->docsrc = AST_XML_DOC;
367#endif
368
369 return 0;
370}
#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.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_init_extended(x, field)
Initialize an extended string field.
Definition: stringfields.h:401
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
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:2356
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:2169
char * ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
Generate synopsis documentation from XML.
Definition: xmldoc.c:2333
char * ast_xmldoc_build_since(const char *type, const char *name, const char *module)
Parse the <since> node content.
Definition: xmldoc.c:1787
@ 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:1702

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_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 251 of file pbx_functions.c.

252{
253 struct ast_custom_function *acf;
254
258
259 return acf;
260}
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 229 of file pbx_functions.c.

230{
231 struct ast_custom_function *cur;
232 int cmp;
233
234 AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
235 cmp = strcmp(name, cur->name);
236 if (cmp > 0) {
237 continue;
238 }
239 if (!cmp) {
240 /* Found it. */
241 break;
242 }
243 /* Not in container. */
244 cur = NULL;
245 break;
246 }
247
248 return cur;
249}
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#define NULL
Definition: resample.c:96

References 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 262 of file pbx_functions.c.

263{
264 struct ast_custom_function *cur;
265
266 if (!acf) {
267 return -1;
268 }
269
271 cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist);
272 if (cur) {
273#ifdef AST_XML_DOCS
274 if (cur->docsrc == AST_XML_DOC) {
276 }
277#endif
278 ast_verb(5, "Unregistered custom function %s\n", cur->name);
279 }
281
282 return cur ? 0 : -1;
283}
#define AST_RWLIST_REMOVE
Definition: linkedlists.h:885

References 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(), manager_shutdown(), message_shutdown(), reload(), unload_features_config(), 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 598 of file pbx_functions.c.

599{
600 char *copy = ast_strdupa(function);
601 char *args = func_args(copy);
603 int res;
604 struct ast_module_user *u = NULL;
605
606 if (acfptr == NULL) {
607 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
608 } else if (!acfptr->read && !acfptr->read2) {
609 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
610 } else if (!is_read_allowed(acfptr)) {
611 ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
612 } else if (acfptr->read) {
613 if (acfptr->mod) {
614 u = __ast_module_user_add(acfptr->mod, chan);
615 }
616 res = acfptr->read(chan, copy, args, workspace, len);
617 if (acfptr->mod && u) {
618 __ast_module_user_remove(acfptr->mod, u);
619 }
620
621 return res;
622 } else {
623 struct ast_str *str = ast_str_create(16);
624
625 if (acfptr->mod) {
626 u = __ast_module_user_add(acfptr->mod, chan);
627 }
628 res = acfptr->read2(chan, copy, args, &str, 0);
629 if (acfptr->mod && u) {
630 __ast_module_user_remove(acfptr->mod, u);
631 }
633 ast_free(str);
634
635 return res;
636 }
637
638 return -1;
639}
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'
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
size_t 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
const char * args

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 641 of file pbx_functions.c.

642{
643 char *copy = ast_strdupa(function);
644 char *args = func_args(copy);
646 int res;
647 struct ast_module_user *u = NULL;
648
649 if (acfptr == NULL) {
650 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
651 } else if (!acfptr->read && !acfptr->read2) {
652 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
653 } else if (!is_read_allowed(acfptr)) {
654 ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
655 } else {
656 if (acfptr->mod) {
657 u = __ast_module_user_add(acfptr->mod, chan);
658 }
660 if (acfptr->read2) {
661 /* ast_str enabled */
662 res = acfptr->read2(chan, copy, args, str, maxlen);
663 } else {
664 /* Legacy function pointer, allocate buffer for result */
665 int maxsize = ast_str_size(*str);
666
667 if (maxlen > -1) {
668 if (maxlen == 0) {
669 if (acfptr->read_max) {
670 maxsize = acfptr->read_max;
671 } else {
673 }
674 } else {
675 maxsize = maxlen;
676 }
678 }
679 res = acfptr->read(chan, copy, args, ast_str_buffer(*str), maxsize);
680 ast_str_update(*str); /* Manually set the string length */
681 }
682 if (acfptr->mod && u) {
683 __ast_module_user_remove(acfptr->mod, u);
684 }
685
686 return res;
687 }
688
689 return -1;
690}
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(), 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 692 of file pbx_functions.c.

693{
694 char *copy = ast_strdupa(function);
695 char *args = func_args(copy);
697
698 if (acfptr == NULL) {
699 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
700 } else if (!acfptr->write) {
701 ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
702 } else if (!is_write_allowed(acfptr)) {
703 ast_log(LOG_ERROR, "Dangerous function %s write blocked\n", copy);
704 } else {
705 int res;
706 struct ast_module_user *u = NULL;
707
708 if (acfptr->mod) {
709 u = __ast_module_user_add(acfptr->mod, chan);
710 }
711 res = acfptr->write(chan, copy, args, value);
712 if (acfptr->mod && u) {
713 __ast_module_user_remove(acfptr->mod, u);
714 }
715
716 return res;
717 }
718
719 return -1;
720}
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(), confbridge_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 478 of file pbx_functions.c.

479{
480 int *thread_inhibit_escalations;
481
482 thread_inhibit_escalations = ast_threadstorage_get(
483 &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
484 if (thread_inhibit_escalations == NULL) {
485 ast_log(LOG_ERROR, "Error inhibiting privilege escalations for current thread\n");
486 return -1;
487 }
488
489 *thread_inhibit_escalations = 1;
490 return 0;
491}
static struct ast_threadstorage thread_inhibit_escalations_tl
Definition: pbx_functions.c:46
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.

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

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 493 of file pbx_functions.c.

494{
495 int *thread_inhibit_escalations;
496 int orig;
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 swapping privilege escalations inhibit for current thread\n");
502 return -1;
503 }
504
505 orig = *thread_inhibit_escalations;
506 *thread_inhibit_escalations = !!inhibit;
507 return orig;
508}

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

Referenced by ast_add_extension2_lockopt().

◆ 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);
119 AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
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_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 447 of file pbx_functions.c.

448{
449 char *args = strchr(function, '(');
450
451 if (!args) {
452 ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses. Assuming null argument.\n", function);
453 } else {
454 char *p;
455 *args++ = '\0';
456 if ((p = strrchr(args, ')'))) {
457 *p = '\0';
458 } else {
459 ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
460 }
461 }
462 return args;
463}
#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, *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 since = ast_xmldoc_printable(S_OR(acf->since, "Not available"), 1);
175 description = ast_xmldoc_printable(S_OR(acf->desc, "Not available"), 1);
176 syntax = ast_xmldoc_printable(S_OR(acf->syntax, "Not available"), 1);
177 arguments = ast_xmldoc_printable(S_OR(acf->arguments, "Not available"), 1);
178 seealso = ast_xmldoc_printable(S_OR(acf->seealso, "Not available"), 1);
179 } else
180#endif
181 {
182 synopsis = ast_strdup(S_OR(acf->synopsis, "Not Available"));
183 since = ast_strdup(S_OR(acf->since, "Not Available"));
184 description = ast_strdup(S_OR(acf->desc, "Not Available"));
185 syntax = ast_strdup(S_OR(acf->syntax, "Not Available"));
186 arguments = ast_strdup(S_OR(acf->arguments, "Not Available"));
187 seealso = ast_strdup(S_OR(acf->seealso, "Not Available"));
188 }
189 /* check allocated memory. */
190 if (!synopsis || !since || !description || !syntax || !arguments || !seealso) {
191 rtn = CLI_FAILURE;
192 goto free_docs;
193 }
194
195 ast_cli(a->fd, "\n"
196 "%s -= Info about Function '%s' =- %s\n\n"
197 COLORIZE_FMT "\n"
198 "%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",
210 COLORIZE(COLOR_MAGENTA, 0, "[Synopsis]"), synopsis,
211 COLORIZE(COLOR_MAGENTA, 0, "[Since]"), since,
212 COLORIZE(COLOR_MAGENTA, 0, "[Description]"), description,
213 COLORIZE(COLOR_MAGENTA, 0, "[Syntax]"), syntax,
214 COLORIZE(COLOR_MAGENTA, 0, "[Arguments]"), arguments,
215 COLORIZE(COLOR_MAGENTA, 0, "[See Also]"), seealso
216 );
217
218free_docs:
220 ast_free(since);
221 ast_free(description);
225
226 return rtn;
227}
#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
89 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
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_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 540 of file pbx_functions.c.

541{
542 if (!acfptr) {
543 return 1;
544 }
545
546 if (!read_escalates(acfptr)) {
547 return 1;
548 }
549
551 return 1;
552 }
553
554 if (live_dangerously) {
555 /* Global setting overrides the thread's preference */
556 ast_debug(2, "Reading %s from a dangerous context\n",
557 acfptr->name);
558 return 1;
559 }
560
561 /* We have no reason to allow this function to execute */
562 return 0;
563}
#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.
Definition: pbx_functions.c:52

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 573 of file pbx_functions.c.

574{
575 if (!acfptr) {
576 return 1;
577 }
578
579 if (!write_escalates(acfptr)) {
580 return 1;
581 }
582
584 return 1;
585 }
586
587 if (live_dangerously) {
588 /* Global setting overrides the thread's preference */
589 ast_debug(2, "Writing %s from a dangerous context\n",
590 acfptr->name);
591 return 1;
592 }
593
594 /* We have no reason to allow this function to execute */
595 return 0;
596}
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 732 of file pbx_functions.c.

733{
736
737 return 0;
738}
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:666

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 465 of file pbx_functions.c.

466{
467 if (new_live_dangerously && !live_dangerously) {
468 ast_log(LOG_WARNING, "Privilege escalation protection disabled!\n"
469 "See https://docs.asterisk.org/Configuration/Dialplan/Privilege-Escalations-with-Dialplan-Functions/ for more details.\n");
470 }
471
472 if (!new_live_dangerously && live_dangerously) {
473 ast_log(LOG_NOTICE, "Privilege escalation protection enabled.\n");
474 }
475 live_dangerously = new_live_dangerously;
476}
#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 292 of file pbx_functions.c.

293{
294 return acf->read_escalates;
295}

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 517 of file pbx_functions.c.

518{
519 int *thread_inhibit_escalations;
520
521 thread_inhibit_escalations = ast_threadstorage_get(
522 &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
523 if (thread_inhibit_escalations == NULL) {
524 ast_log(LOG_ERROR, "Error checking thread's ability to run dangerous functions\n");
525 /* On error, assume that we are inhibiting */
526 return 1;
527 }
528
529 return *thread_inhibit_escalations;
530}

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

Referenced by is_read_allowed(), and is_write_allowed().

◆ unload_pbx_functions_cli()

static void unload_pbx_functions_cli ( void  )
static

Definition at line 727 of file pbx_functions.c.

728{
730}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30

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 304 of file pbx_functions.c.

305{
306 return acf->write_escalates;
307}

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)
Definition: pbx_functions.c:61
static char * handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 722 of file pbx_functions.c.

Referenced by load_pbx_functions_cli(), and unload_pbx_functions_cli().

◆ acf_root

struct acf_root acf_root = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
static

◆ 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().

◆ thread_inhibit_escalations_tl

struct ast_threadstorage thread_inhibit_escalations_tl = { .once = PTHREAD_ONCE_INIT , .key_init = __init_thread_inhibit_escalations_tl , .custom_init = NULL , }
static