Asterisk - The Open Source Telephony Project GIT-master-0deac78
Data Structures | Macros | Enumerations | Functions | Variables
func_curl.c File Reference

Curl - Load a URL. More...

#include "asterisk.h"
#include <curl/curl.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/cli.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/threadstorage.h"
#include "asterisk/test.h"
Include dependency graph for func_curl.c:

Go to the source code of this file.

Data Structures

struct  curl_args
 
struct  curl_settings
 
struct  curl_write_callback_data
 Callback data passed to WriteMemoryCallback. More...
 
struct  global_curl_info
 

Macros

#define CURLOPT_SPECIAL_FAILURE_CODE   999
 
#define CURLOPT_SPECIAL_HASHCOMPAT   ((CURLoption) -500)
 
#define CURLVERSION_ATLEAST(a, b, c)    ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c))))
 

Enumerations

enum  hashcompat { HASHCOMPAT_NO = 0 , HASHCOMPAT_YES , HASHCOMPAT_LEGACY }
 
enum  optiontype {
  OT_BOOLEAN , OT_INTEGER , OT_INTEGER_MS , OT_STRING ,
  OT_ENUM
}
 

Functions

static void __init_curl_instance (void)
 
static void __init_thread_escapebuf (void)
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static int acf_curl_exec (struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len)
 
static int acf_curl_helper (struct ast_channel *chan, struct curl_args *args)
 
static int acf_curl_write (struct ast_channel *chan, const char *cmd, char *name, const char *value)
 
static int acf_curlopt_helper (struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, ssize_t len)
 
static int acf_curlopt_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int acf_curlopt_read2 (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
 
static int acf_curlopt_write (struct ast_channel *chan, const char *cmd, char *name, const char *value)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void curl_instance_cleanup (void *data)
 
static int curl_instance_init (void *data)
 
static void curlds_free (void *data)
 
static int load_module (void)
 
static int parse_curlopt_key (const char *name, CURLoption *key, enum optiontype *ot)
 
static int unload_module (void)
 
static int url_is_vulnerable (const char *url)
 Check for potential HTTP injection risk. More...
 
static size_t WriteMemoryCallback (void *ptr, size_t size, size_t nmemb, void *data)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Load external URL" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_REALTIME_DEPEND2, .requires = "res_curl", }
 
static struct ast_custom_function acf_curl
 
static struct ast_custom_function acf_curlopt
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static const struct ast_datastore_info curl_info
 
static struct ast_threadstorage curl_instance = { .once = PTHREAD_ONCE_INIT , .key_init = __init_curl_instance , .custom_init = curl_instance_init , }
 
struct global_curl_info global_curl_info = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static struct ast_threadstorage thread_escapebuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_thread_escapebuf , .custom_init = NULL , }
 

Detailed Description

Curl - Load a URL.

Author
Tilghman Lesher curl-.nosp@m.2005.nosp@m.0919@.nosp@m.the-.nosp@m.tilgh.nosp@m.man..nosp@m.com
Note
Brian Wilkins bwilk.nosp@m.ins@.nosp@m.cfl.r.nosp@m.r.co.nosp@m.m (Added POST option)
ExtRef:
Depends on the CURL library - http://curl.haxx.se/

Definition in file func_curl.c.

Macro Definition Documentation

◆ CURLOPT_SPECIAL_FAILURE_CODE

#define CURLOPT_SPECIAL_FAILURE_CODE   999

Definition at line 267 of file func_curl.c.

◆ CURLOPT_SPECIAL_HASHCOMPAT

#define CURLOPT_SPECIAL_HASHCOMPAT   ((CURLoption) -500)

Definition at line 265 of file func_curl.c.

◆ CURLVERSION_ATLEAST

#define CURLVERSION_ATLEAST (   a,
  b,
  c 
)     ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c))))

Definition at line 262 of file func_curl.c.

Enumeration Type Documentation

◆ hashcompat

enum hashcompat
Enumerator
HASHCOMPAT_NO 
HASHCOMPAT_YES 
HASHCOMPAT_LEGACY 

Definition at line 306 of file func_curl.c.

306 {
307 HASHCOMPAT_NO = 0,
310};
@ HASHCOMPAT_NO
Definition: func_curl.c:307
@ HASHCOMPAT_LEGACY
Definition: func_curl.c:309
@ HASHCOMPAT_YES
Definition: func_curl.c:308

◆ optiontype

enum optiontype
Enumerator
OT_BOOLEAN 
OT_INTEGER 
OT_INTEGER_MS 
OT_STRING 
OT_ENUM 

Definition at line 298 of file func_curl.c.

298 {
302 OT_STRING,
303 OT_ENUM,
304};
@ OT_BOOLEAN
Definition: func_curl.c:299
@ OT_ENUM
Definition: func_curl.c:303
@ OT_STRING
Definition: func_curl.c:302
@ OT_INTEGER
Definition: func_curl.c:300
@ OT_INTEGER_MS
Definition: func_curl.c:301

Function Documentation

◆ __init_curl_instance()

static void __init_curl_instance ( void  )
static

Definition at line 740 of file func_curl.c.

760{

◆ __init_thread_escapebuf()

static void __init_thread_escapebuf ( void  )
static

Definition at line 741 of file func_curl.c.

760{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1097 of file func_curl.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1097 of file func_curl.c.

◆ acf_curl_exec()

static int acf_curl_exec ( struct ast_channel chan,
const char *  cmd,
char *  info,
struct ast_str **  buf,
ssize_t  len 
)
static

Definition at line 935 of file func_curl.c.

936{
937 struct curl_args curl_params = { 0, };
938 int res;
939
943 );
944
946
947 if (ast_strlen_zero(info)) {
948 ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
949 return -1;
950 }
951
952 curl_params.url = args.url;
953 curl_params.postdata = args.postdata;
954 curl_params.cb_data.str = ast_str_create(16);
955 if (!curl_params.cb_data.str) {
956 return -1;
957 }
958
959 res = acf_curl_helper(chan, &curl_params);
960 ast_str_set(buf, len, "%s", ast_str_buffer(curl_params.cb_data.str));
961 ast_free(curl_params.cb_data.str);
962
963 return res;
964}
#define ast_free(a)
Definition: astmm.h:180
#define ast_log
Definition: astobj2.c:42
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args)
Definition: func_curl.c:774
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define LOG_WARNING
def info(msg)
static char url[512]
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
const char * postdata
Definition: func_curl.c:770
struct curl_write_callback_data cb_data
Definition: func_curl.c:771
const char * url
Definition: func_curl.c:769
struct ast_str * str
If a string is being built, the string buffer.
Definition: func_curl.c:694
const char * args

References acf_curl_helper(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_free, ast_log, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_create, ast_str_set(), ast_strlen_zero(), buf, curl_args::cb_data, sip_to_pjsip::info(), len(), LOG_WARNING, curl_args::postdata, curl_write_callback_data::str, curl_args::url, and url.

◆ acf_curl_helper()

static int acf_curl_helper ( struct ast_channel chan,
struct curl_args args 
)
static

Definition at line 774 of file func_curl.c.

775{
776 struct ast_str *escapebuf = ast_str_thread_get(&thread_escapebuf, 16);
777 int ret = 0;
778 long http_code = 0; /* read curl response */
779 size_t i;
780 struct ast_vector_int hasfailurecode = { NULL };
781 char *failurecodestrings,*found;
782 CURL **curl;
783 struct curl_settings *cur;
784 struct curl_slist *headers = NULL;
785 struct ast_datastore *store = NULL;
786 int hashcompat = 0;
788 char curl_errbuf[CURL_ERROR_SIZE + 1]; /* add one to be safe */
789
790 if (!escapebuf) {
791 return -1;
792 }
793
794 if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) {
795 ast_log(LOG_ERROR, "Cannot allocate curl structure\n");
796 return -1;
797 }
798
799 if (url_is_vulnerable(args->url)) {
800 ast_log(LOG_ERROR, "URL '%s' is vulnerable to HTTP injection attacks. Aborting CURL() call.\n", args->url);
801 return -1;
802 }
803
804 if (chan) {
806 }
807
808 AST_VECTOR_INIT(&hasfailurecode, 0); /*Initialize vector*/
811 if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
812 hashcompat = (long) cur->value;
813 } else if (cur->key == CURLOPT_HTTPHEADER) {
814 headers = curl_slist_append(headers, (char*) cur->value);
815 } else if (cur->key == CURLOPT_SPECIAL_FAILURE_CODE) {
816 failurecodestrings = (char*) cur->value;
817 while( (found = strsep(&failurecodestrings, ",")) != NULL) {
818 AST_VECTOR_APPEND(&hasfailurecode, atoi(found));
819 }
820 } else {
821 curl_easy_setopt(*curl, cur->key, cur->value);
822 }
823 }
825
826 if (chan) {
827 ast_channel_lock(chan);
829 ast_channel_unlock(chan);
830 if (store) {
831 list = store->data;
832 AST_LIST_LOCK(list);
833 AST_LIST_TRAVERSE(list, cur, list) {
834 if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
835 hashcompat = (long) cur->value;
836 } else if (cur->key == CURLOPT_HTTPHEADER) {
837 headers = curl_slist_append(headers, (char*) cur->value);
838 } else if (cur->key == CURLOPT_SPECIAL_FAILURE_CODE) {
839 failurecodestrings = (char*) cur->value;
840 while( (found = strsep(&failurecodestrings, ",")) != NULL) {
841 AST_VECTOR_APPEND(&hasfailurecode, atoi(found));
842 }
843 } else {
844 curl_easy_setopt(*curl, cur->key, cur->value);
845 }
846 }
847 }
848 }
849
850 curl_easy_setopt(*curl, CURLOPT_URL, args->url);
851 curl_easy_setopt(*curl, CURLOPT_FILE, (void *) &args->cb_data);
852
853 if (args->postdata) {
854 curl_easy_setopt(*curl, CURLOPT_POST, 1);
855 curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args->postdata);
856 }
857
858 /* Always assign the headers - even when NULL - in case we had
859 * custom headers the last time we used this shared cURL
860 * instance */
861 curl_easy_setopt(*curl, CURLOPT_HTTPHEADER, headers);
862
863 /* Temporarily assign a buffer for curl to write errors to. */
864 curl_errbuf[0] = curl_errbuf[CURL_ERROR_SIZE] = '\0';
865 curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, curl_errbuf);
866
867 if (curl_easy_perform(*curl) != 0) {
868 ast_log(LOG_WARNING, "%s ('%s')\n", curl_errbuf, args->url);
869 }
870
871 /* Reset buffer to NULL so curl doesn't try to write to it when the
872 * buffer is deallocated. Documentation is vague about allowing NULL
873 * here, but the source allows it. See: "typecheck: allow NULL to unset
874 * CURLOPT_ERRORBUFFER" (62bcf005f4678a93158358265ba905bace33b834). */
875 curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, (char*)NULL);
876 curl_easy_getinfo (*curl, CURLINFO_RESPONSE_CODE, &http_code);
877
878 for (i = 0; i < AST_VECTOR_SIZE(&hasfailurecode); ++i) {
879 if (http_code == AST_VECTOR_GET(&hasfailurecode,i)){
880 ast_log(LOG_NOTICE, "%s%sCURL '%s' returned response code (%ld).\n",
881 chan ? ast_channel_name(chan) : "",
882 chan ? ast_channel_name(chan) : ": ",
883 args->url,
884 http_code);
885 ret=-1;
886 break;
887 }
888 }
889 AST_VECTOR_FREE(&hasfailurecode); /* Release the vector*/
890
891 if (store) {
892 AST_LIST_UNLOCK(list);
893 }
894 curl_slist_free_all(headers);
895
896 if (args->postdata) {
897 curl_easy_setopt(*curl, CURLOPT_POST, 0);
898 }
899
900 if (args->cb_data.str && ast_str_strlen(args->cb_data.str)) {
901 ast_str_trim_blanks(args->cb_data.str);
902
903 ast_debug(3, "CURL returned str='%s'\n", ast_str_buffer(args->cb_data.str));
904 if (hashcompat) {
905 char *remainder = ast_str_buffer(args->cb_data.str);
906 char *piece;
907 struct ast_str *fields = ast_str_create(ast_str_strlen(args->cb_data.str) / 2);
908 struct ast_str *values = ast_str_create(ast_str_strlen(args->cb_data.str) / 2);
909 int rowcount = 0;
910 while (fields && values && (piece = strsep(&remainder, "&"))) {
911 char *name = strsep(&piece, "=");
913 if (piece) {
914 ast_uri_decode(piece, mode);
915 }
916 ast_uri_decode(name, mode);
917 ast_str_append(&fields, 0, "%s%s", rowcount ? "," : "", ast_str_set_escapecommas(&escapebuf, 0, name, INT_MAX));
918 ast_str_append(&values, 0, "%s%s", rowcount ? "," : "", ast_str_set_escapecommas(&escapebuf, 0, S_OR(piece, ""), INT_MAX));
919 rowcount++;
920 }
921 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
922 ast_str_set(&args->cb_data.str, 0, "%s", ast_str_buffer(values));
923 ast_free(fields);
925 }
926 }
927
928 if (chan) {
930 }
931
932 return ret;
933}
char * strsep(char **str, const char *delims)
const char * ast_channel_name(const struct ast_channel *chan)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
#define ast_channel_lock(chan)
Definition: channel.h:2972
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
#define ast_channel_unlock(chan)
Definition: channel.h:2973
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2369
static const char name[]
Definition: format_mp3.c:68
#define CURLOPT_SPECIAL_HASHCOMPAT
Definition: func_curl.c:265
static const struct ast_datastore_info curl_info
Definition: func_curl.c:271
#define CURLOPT_SPECIAL_FAILURE_CODE
Definition: func_curl.c:267
static struct ast_threadstorage thread_escapebuf
Definition: func_curl.c:741
static int url_is_vulnerable(const char *url)
Check for potential HTTP injection risk.
Definition: func_curl.c:759
static struct ast_threadstorage curl_instance
Definition: func_curl.c:740
hashcompat
Definition: func_curl.c:306
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define NULL
Definition: resample.c:96
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#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 * ast_str_set_escapecommas(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Set a dynamic string to a non-NULL terminated substring, with escaping of commas.
Definition: strings.h:1069
void ast_str_trim_blanks(struct ast_str *buf)
Trims trailing whitespace characters from an ast_str string.
Definition: strings.h:719
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:909
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
Structure used to handle boolean flags.
Definition: utils.h:217
Support for dynamic strings.
Definition: strings.h:623
Integer vector definition.
Definition: vector.h:52
void * value
Definition: func_curl.c:279
CURLoption key
Definition: func_curl.c:278
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
const struct ast_flags ast_uri_http
Definition: utils.c:719
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
Definition: utils.c:762
const struct ast_flags ast_uri_http_legacy
Definition: utils.c:720
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:620
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:185
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:267
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:691

References args, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_debug, ast_free, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_set(), ast_str_set_escapecommas(), ast_str_strlen(), ast_str_thread_get(), ast_str_trim_blanks(), ast_threadstorage_get(), ast_uri_decode(), ast_uri_http, ast_uri_http_legacy, AST_VECTOR_APPEND, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, curl_info, curl_instance, CURLOPT_SPECIAL_FAILURE_CODE, CURLOPT_SPECIAL_HASHCOMPAT, ast_datastore::data, HASHCOMPAT_LEGACY, curl_settings::key, LOG_ERROR, LOG_NOTICE, LOG_WARNING, name, NULL, pbx_builtin_setvar_helper(), S_OR, strsep(), thread_escapebuf, url_is_vulnerable(), and curl_settings::value.

Referenced by acf_curl_exec(), and acf_curl_write().

◆ acf_curl_write()

static int acf_curl_write ( struct ast_channel chan,
const char *  cmd,
char *  name,
const char *  value 
)
static

Definition at line 966 of file func_curl.c.

967{
968 struct curl_args curl_params = { 0, };
969 int res;
970 char *args_value = ast_strdupa(value);
972 AST_APP_ARG(file_path);
973 );
974
975 AST_STANDARD_APP_ARGS(args, args_value);
976
977 if (ast_strlen_zero(name)) {
978 ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
979 return -1;
980 }
981
982 if (ast_strlen_zero(args.file_path)) {
983 ast_log(LOG_WARNING, "CURL requires a file to write\n");
984 return -1;
985 }
986
987 curl_params.url = name;
988 curl_params.cb_data.out_file = fopen(args.file_path, "w");
989 if (!curl_params.cb_data.out_file) {
990 ast_log(LOG_WARNING, "Failed to open file %s: %s (%d)\n",
991 args.file_path,
992 strerror(errno),
993 errno);
994 return -1;
995 }
996
997 res = acf_curl_helper(chan, &curl_params);
998
999 fclose(curl_params.cb_data.out_file);
1000
1001 return res;
1002}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int errno
FILE * out_file
If a file is being retrieved, the file to write to.
Definition: func_curl.c:698
int value
Definition: syslog.c:37

References acf_curl_helper(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), curl_args::cb_data, errno, LOG_WARNING, name, curl_write_callback_data::out_file, curl_args::url, and value.

◆ acf_curlopt_helper()

static int acf_curlopt_helper ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
struct ast_str **  bufstr,
ssize_t  len 
)
static

Definition at line 566 of file func_curl.c.

567{
568 struct ast_datastore *store;
569 struct global_curl_info *list[2] = { &global_curl_info, NULL };
570 struct curl_settings *cur = NULL;
571 CURLoption key;
572 enum optiontype ot;
573 int i;
574
575 if (parse_curlopt_key(data, &key, &ot)) {
576 ast_log(LOG_ERROR, "Unrecognized option: '%s'\n", data);
577 return -1;
578 }
579
580 if (chan) {
581 /* If we have a channel, we want to read the options set there before
582 falling back to the global settings */
583 ast_channel_lock(chan);
585 ast_channel_unlock(chan);
586
587 if (store) {
588 list[0] = store->data;
590 }
591 }
592
593 for (i = 0; i < 2; i++) {
594 if (!list[i]) {
595 break;
596 }
598 AST_LIST_TRAVERSE(list[i], cur, list) {
599 if (cur->key == key) {
600 if (ot == OT_BOOLEAN || ot == OT_INTEGER) {
601 if (buf) {
602 snprintf(buf, len, "%ld", (long) cur->value);
603 } else {
604 ast_str_set(bufstr, len, "%ld", (long) cur->value);
605 }
606 } else if (ot == OT_INTEGER_MS) {
607 if ((long) cur->value % 1000 == 0) {
608 if (buf) {
609 snprintf(buf, len, "%ld", (long)cur->value / 1000);
610 } else {
611 ast_str_set(bufstr, len, "%ld", (long) cur->value / 1000);
612 }
613 } else {
614 if (buf) {
615 snprintf(buf, len, "%.3f", (double) ((long) cur->value) / 1000.0);
616 } else {
617 ast_str_set(bufstr, len, "%.3f", (double) ((long) cur->value) / 1000.0);
618 }
619 }
620 } else if (ot == OT_STRING) {
621 ast_debug(1, "Found entry %p, with key %d and value %p\n", cur, cur->key, cur->value);
622 if (buf) {
624 } else {
625 ast_str_set(bufstr, 0, "%s", (char *) cur->value);
626 }
627 } else if (key == CURLOPT_PROXYTYPE) {
628 const char *strval = "unknown";
629 if (0) {
630#if CURLVERSION_ATLEAST(7,15,2)
631 } else if ((long)cur->value == CURLPROXY_SOCKS4) {
632 strval = "socks4";
633#endif
634#if CURLVERSION_ATLEAST(7,18,0)
635 } else if ((long)cur->value == CURLPROXY_SOCKS4A) {
636 strval = "socks4a";
637#endif
638 } else if ((long)cur->value == CURLPROXY_SOCKS5) {
639 strval = "socks5";
640#if CURLVERSION_ATLEAST(7,18,0)
641 } else if ((long)cur->value == CURLPROXY_SOCKS5_HOSTNAME) {
642 strval = "socks5hostname";
643#endif
644#if CURLVERSION_ATLEAST(7,10,0)
645 } else if ((long)cur->value == CURLPROXY_HTTP) {
646 strval = "http";
647#endif
648 }
649 if (buf) {
650 ast_copy_string(buf, strval, len);
651 } else {
652 ast_str_set(bufstr, 0, "%s", strval);
653 }
654 } else if (key == CURLOPT_SPECIAL_HASHCOMPAT) {
655 const char *strval = "unknown";
656 if ((long) cur->value == HASHCOMPAT_LEGACY) {
657 strval = "legacy";
658 } else if ((long) cur->value == HASHCOMPAT_YES) {
659 strval = "yes";
660 } else if ((long) cur->value == HASHCOMPAT_NO) {
661 strval = "no";
662 }
663 if (buf) {
664 ast_copy_string(buf, strval, len);
665 } else {
666 ast_str_set(bufstr, 0, "%s", strval);
667 }
668 }
669 break;
670 }
671 }
673 if (cur) {
674 break;
675 }
676 }
677
678 return cur ? 0 : -1;
679}
optiontype
Definition: func_curl.c:298
struct global_curl_info global_curl_info
static int parse_curlopt_key(const char *name, CURLoption *key, enum optiontype *ot)
Definition: func_curl.c:312
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
struct curl_settings::@171 list

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_str_set(), buf, curl_info, CURLOPT_SPECIAL_HASHCOMPAT, ast_datastore::data, global_curl_info, HASHCOMPAT_LEGACY, HASHCOMPAT_NO, HASHCOMPAT_YES, curl_settings::key, len(), curl_settings::list, LOG_ERROR, NULL, OT_BOOLEAN, OT_INTEGER, OT_INTEGER_MS, OT_STRING, parse_curlopt_key(), and curl_settings::value.

Referenced by acf_curlopt_read(), and acf_curlopt_read2().

◆ acf_curlopt_read()

static int acf_curlopt_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 681 of file func_curl.c.

682{
683 return acf_curlopt_helper(chan, cmd, data, buf, NULL, len);
684}
static int acf_curlopt_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, ssize_t len)
Definition: func_curl.c:566

References acf_curlopt_helper(), buf, len(), and NULL.

◆ acf_curlopt_read2()

static int acf_curlopt_read2 ( struct ast_channel chan,
const char *  cmd,
char *  data,
struct ast_str **  buf,
ssize_t  len 
)
static

Definition at line 686 of file func_curl.c.

687{
688 return acf_curlopt_helper(chan, cmd, data, NULL, buf, len);
689}

References acf_curlopt_helper(), buf, len(), and NULL.

◆ acf_curlopt_write()

static int acf_curlopt_write ( struct ast_channel chan,
const char *  cmd,
char *  name,
const char *  value 
)
static

Definition at line 417 of file func_curl.c.

418{
419 struct ast_datastore *store;
420 struct global_curl_info *list;
421 struct curl_settings *cur, *new = NULL;
422 CURLoption key;
423 enum optiontype ot;
424
425 if (chan) {
426 ast_channel_lock(chan);
427 if (!(store = ast_channel_datastore_find(chan, &curl_info, NULL))) {
428 /* Create a new datastore */
429 if (!(store = ast_datastore_alloc(&curl_info, NULL))) {
430 ast_log(LOG_ERROR, "Unable to allocate new datastore. Cannot set any CURL options\n");
431 ast_channel_unlock(chan);
432 return -1;
433 }
434
435 if (!(list = ast_calloc(1, sizeof(*list)))) {
436 ast_log(LOG_ERROR, "Unable to allocate list head. Cannot set any CURL options\n");
437 ast_datastore_free(store);
438 ast_channel_unlock(chan);
439 return -1;
440 }
441
442 store->data = list;
444 ast_channel_datastore_add(chan, store);
445 } else {
446 list = store->data;
447 }
448 ast_channel_unlock(chan);
449 } else {
450 /* Populate the global structure */
452 }
453
454 if (!parse_curlopt_key(name, &key, &ot)) {
455 if (ot == OT_BOOLEAN) {
456 if ((new = ast_calloc(1, sizeof(*new)))) {
457 new->value = (void *)((long) ast_true(value));
458 }
459 } else if (ot == OT_INTEGER) {
460 long tmp = atol(value);
461 if ((new = ast_calloc(1, sizeof(*new)))) {
462 new->value = (void *)tmp;
463 }
464 } else if (ot == OT_INTEGER_MS) {
465 long tmp = atof(value) * 1000.0;
466 if ((new = ast_calloc(1, sizeof(*new)))) {
467 new->value = (void *)tmp;
468 }
469 } else if (ot == OT_STRING) {
470 if ((new = ast_calloc(1, sizeof(*new) + strlen(value) + 1))) {
471 new->value = (char *)new + sizeof(*new);
472 strcpy(new->value, value);
473 }
474 } else if (ot == OT_ENUM) {
475 if (key == CURLOPT_PROXYTYPE) {
476 long ptype =
477#if CURLVERSION_ATLEAST(7,10,0)
478 CURLPROXY_HTTP;
479#else
480 CURLPROXY_SOCKS5;
481#endif
482 if (0) {
483#if CURLVERSION_ATLEAST(7,15,2)
484 } else if (!strcasecmp(value, "socks4")) {
485 ptype = CURLPROXY_SOCKS4;
486#endif
487#if CURLVERSION_ATLEAST(7,18,0)
488 } else if (!strcasecmp(value, "socks4a")) {
489 ptype = CURLPROXY_SOCKS4A;
490#endif
491#if CURLVERSION_ATLEAST(7,18,0)
492 } else if (!strcasecmp(value, "socks5")) {
493 ptype = CURLPROXY_SOCKS5;
494#endif
495#if CURLVERSION_ATLEAST(7,18,0)
496 } else if (!strncasecmp(value, "socks5", 6)) {
497 ptype = CURLPROXY_SOCKS5_HOSTNAME;
498#endif
499 }
500
501 if ((new = ast_calloc(1, sizeof(*new)))) {
502 new->value = (void *)ptype;
503 }
504 } else if (key == CURLOPT_HTTPAUTH) {
505 long authtype = 0;
506 char *authmethod, *authstr = ast_strdupa(value);
507 while ((authmethod = strsep(&authstr, ","))) {
508 if (!strcasecmp(authmethod, "basic")) {
509 authtype |= CURLAUTH_BASIC;
510 } else if (!strcasecmp(authmethod, "digest")) {
511 authtype |= CURLAUTH_DIGEST;
512 } else {
513 ast_log(LOG_WARNING, "Auth method '%s' invalid or not supported\n", authmethod);
514 return -1;
515 }
516 }
517 if (!authmethod) {
518 ast_log(LOG_WARNING, "Auth method '%s' invalid or not supported\n", value);
519 }
520 if ((new = ast_calloc(1, sizeof(*new)))) {
521 new->value = (void *)authtype;
522 }
523 } else if (key == CURLOPT_SPECIAL_HASHCOMPAT) {
524 if ((new = ast_calloc(1, sizeof(*new)))) {
525 new->value = (void *) (long) (!strcasecmp(value, "legacy") ? HASHCOMPAT_LEGACY : ast_true(value) ? HASHCOMPAT_YES : HASHCOMPAT_NO);
526 }
527 } else {
528 /* Highly unlikely */
529 goto yuck;
530 }
531 }
532
533 /* Memory allocation error */
534 if (!new) {
535 return -1;
536 }
537
538 new->key = key;
539 } else {
540yuck:
541 ast_log(LOG_ERROR, "Unrecognized option: %s\n", name);
542 return -1;
543 }
544
545 /* Remove any existing entry, only http headers are left */
547 if (new->key != CURLOPT_HTTPHEADER) {
549 if (cur->key == new->key) {
551 ast_free(cur);
552 break;
553 }
554 }
556 }
557
558 /* Insert new entry */
559 ast_debug(1, "Inserting entry %p with key %d and value %p\n", new, new->key, new->value);
562
563 return 0;
564}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2355
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2235

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), ast_debug, ast_free, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log, ast_strdupa, ast_true(), curl_info, CURLOPT_SPECIAL_HASHCOMPAT, ast_datastore::data, global_curl_info, HASHCOMPAT_LEGACY, HASHCOMPAT_NO, HASHCOMPAT_YES, curl_settings::key, curl_settings::list, LOG_ERROR, LOG_WARNING, name, NULL, OT_BOOLEAN, OT_ENUM, OT_INTEGER, OT_INTEGER_MS, OT_STRING, parse_curlopt_key(), strsep(), and value.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1097 of file func_curl.c.

◆ curl_instance_cleanup()

static void curl_instance_cleanup ( void *  data)
static

Definition at line 731 of file func_curl.c.

732{
733 CURL **curl = data;
734
735 curl_easy_cleanup(*curl);
736
737 ast_free(data);
738}

References ast_free.

◆ curl_instance_init()

static int curl_instance_init ( void *  data)
static

Definition at line 716 of file func_curl.c.

717{
718 CURL **curl = data;
719
720 if (!(*curl = curl_easy_init()))
721 return -1;
722
723 curl_easy_setopt(*curl, CURLOPT_NOSIGNAL, 1);
724 curl_easy_setopt(*curl, CURLOPT_TIMEOUT, 180);
725 curl_easy_setopt(*curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
726 curl_easy_setopt(*curl, CURLOPT_USERAGENT, AST_CURL_USER_AGENT);
727
728 return 0;
729}
#define AST_CURL_USER_AGENT
Definition: asterisk.h:44
static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
Definition: func_curl.c:701

References AST_CURL_USER_AGENT, and WriteMemoryCallback().

◆ curlds_free()

static void curlds_free ( void *  data)
static

Definition at line 284 of file func_curl.c.

285{
287 struct curl_settings *setting;
288 if (!list) {
289 return;
290 }
291 while ((setting = AST_LIST_REMOVE_HEAD(list, list))) {
292 ast_free(setting);
293 }
295 ast_free(list);
296}
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833

References ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_REMOVE_HEAD, and curl_settings::list.

◆ load_module()

static int load_module ( void  )
static

Definition at line 1079 of file func_curl.c.

1080{
1081 int res;
1082
1085
1086 AST_TEST_REGISTER(vulnerable_url);
1087
1088 return res;
1089}
static struct ast_custom_function acf_curlopt
Definition: func_curl.c:1010
static struct ast_custom_function acf_curl
Definition: func_curl.c:1004
#define ast_custom_function_register_escalating(acf, escalation)
Register a custom function which requires escalated privileges.
Definition: pbx.h:1571
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1562
@ AST_CFE_WRITE
Definition: pbx.h:1555
#define AST_TEST_REGISTER(cb)
Definition: test.h:127

References acf_curl, acf_curlopt, AST_CFE_WRITE, ast_custom_function_register, ast_custom_function_register_escalating, and AST_TEST_REGISTER.

◆ parse_curlopt_key()

static int parse_curlopt_key ( const char *  name,
CURLoption *  key,
enum optiontype ot 
)
static

Definition at line 312 of file func_curl.c.

313{
314 if (!strcasecmp(name, "header")) {
315 *key = CURLOPT_HEADER;
316 *ot = OT_BOOLEAN;
317 } else if (!strcasecmp(name, "httpheader")) {
318 *key = CURLOPT_HTTPHEADER;
319 *ot = OT_STRING;
320 } else if (!strcasecmp(name, "httpauth")) {
321 *key = CURLOPT_HTTPAUTH;
322 *ot = OT_ENUM;
323 } else if (!strcasecmp(name, "proxy")) {
324 *key = CURLOPT_PROXY;
325 *ot = OT_STRING;
326 } else if (!strcasecmp(name, "proxyport")) {
327 *key = CURLOPT_PROXYPORT;
328 *ot = OT_INTEGER;
329 } else if (!strcasecmp(name, "proxytype")) {
330 *key = CURLOPT_PROXYTYPE;
331 *ot = OT_ENUM;
332 } else if (!strcasecmp(name, "dnstimeout")) {
333 *key = CURLOPT_DNS_CACHE_TIMEOUT;
334 *ot = OT_INTEGER;
335 } else if (!strcasecmp(name, "userpwd")) {
336 *key = CURLOPT_USERPWD;
337 *ot = OT_STRING;
338 } else if (!strcasecmp(name, "proxyuserpwd")) {
339 *key = CURLOPT_PROXYUSERPWD;
340 *ot = OT_STRING;
341 } else if (!strcasecmp(name, "followlocation")) {
342 *key = CURLOPT_FOLLOWLOCATION;
343 *ot = OT_BOOLEAN;
344 } else if (!strcasecmp(name, "maxredirs")) {
345 *key = CURLOPT_MAXREDIRS;
346 *ot = OT_INTEGER;
347 } else if (!strcasecmp(name, "referer")) {
348 *key = CURLOPT_REFERER;
349 *ot = OT_STRING;
350 } else if (!strcasecmp(name, "useragent")) {
351 *key = CURLOPT_USERAGENT;
352 *ot = OT_STRING;
353 } else if (!strcasecmp(name, "cookie")) {
354 *key = CURLOPT_COOKIE;
355 *ot = OT_STRING;
356 } else if (!strcasecmp(name, "ftptimeout")) {
357 *key = CURLOPT_FTP_RESPONSE_TIMEOUT;
358 *ot = OT_INTEGER;
359 } else if (!strcasecmp(name, "httptimeout")) {
360#if CURLVERSION_ATLEAST(7,16,2)
361 *key = CURLOPT_TIMEOUT_MS;
362 *ot = OT_INTEGER_MS;
363#else
364 *key = CURLOPT_TIMEOUT;
365 *ot = OT_INTEGER;
366#endif
367 } else if (!strcasecmp(name, "conntimeout")) {
368#if CURLVERSION_ATLEAST(7,16,2)
369 *key = CURLOPT_CONNECTTIMEOUT_MS;
370 *ot = OT_INTEGER_MS;
371#else
372 *key = CURLOPT_CONNECTTIMEOUT;
373 *ot = OT_INTEGER;
374#endif
375 } else if (!strcasecmp(name, "ftptext")) {
376 *key = CURLOPT_TRANSFERTEXT;
377 *ot = OT_BOOLEAN;
378 } else if (!strcasecmp(name, "ssl_verifypeer")) {
379 *key = CURLOPT_SSL_VERIFYPEER;
380 *ot = OT_BOOLEAN;
381 } else if (!strcasecmp(name, "ssl_verifyhost")) {
382 *key = CURLOPT_SSL_VERIFYHOST;
383 *ot = OT_INTEGER;
384 } else if (!strcasecmp(name, "ssl_cainfo")) {
385 *key = CURLOPT_CAINFO;
386 *ot = OT_STRING;
387 } else if (!strcasecmp(name, "ssl_capath")) {
388 *key = CURLOPT_CAPATH;
389 *ot = OT_STRING;
390 } else if (!strcasecmp(name, "ssl_cert")) {
391 *key = CURLOPT_SSLCERT;
392 *ot = OT_STRING;
393 } else if (!strcasecmp(name, "ssl_certtype")) {
394 *key = CURLOPT_SSLCERTTYPE;
395 *ot = OT_STRING;
396 } else if (!strcasecmp(name, "ssl_key")) {
397 *key = CURLOPT_SSLKEY;
398 *ot = OT_STRING;
399 } else if (!strcasecmp(name, "ssl_keytype")) {
400 *key = CURLOPT_SSLKEYTYPE;
401 *ot = OT_STRING;
402 } else if (!strcasecmp(name, "ssl_keypasswd")) {
403 *key = CURLOPT_KEYPASSWD;
404 *ot = OT_STRING;
405 } else if (!strcasecmp(name, "hashcompat")) {
407 *ot = OT_ENUM;
408 } else if (!strcasecmp(name, "failurecodes")) {
410 *ot = OT_STRING;
411 } else {
412 return -1;
413 }
414 return 0;
415}

References CURLOPT_SPECIAL_FAILURE_CODE, CURLOPT_SPECIAL_HASHCOMPAT, curl_settings::key, name, OT_BOOLEAN, OT_ENUM, OT_INTEGER, OT_INTEGER_MS, and OT_STRING.

Referenced by acf_curlopt_helper(), and acf_curlopt_write().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1067 of file func_curl.c.

1068{
1069 int res;
1070
1073
1074 AST_TEST_UNREGISTER(vulnerable_url);
1075
1076 return res;
1077}
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

References acf_curl, acf_curlopt, ast_custom_function_unregister(), and AST_TEST_UNREGISTER.

◆ url_is_vulnerable()

static int url_is_vulnerable ( const char *  url)
static

Check for potential HTTP injection risk.

CVE-2014-8150 brought up the fact that HTTP proxies are subject to injection attacks. An HTTP URL sent to a proxy contains a carriage-return linefeed combination, followed by a complete HTTP request. Proxies will handle this as two separate HTTP requests rather than as a malformed URL.

libcURL patched this vulnerability in version 7.40.0, but we have no guarantee that Asterisk systems will be using an up-to-date cURL library. Therefore, we implement the same fix as libcURL for determining if a URL is vulnerable to an injection attack.

Parameters
urlThe URL to check for vulnerability
Return values
0The URL is not vulnerable
1The URL is vulnerable.

Definition at line 759 of file func_curl.c.

760{
761 if (strpbrk(url, "\r\n")) {
762 return 1;
763 }
764
765 return 0;
766}

References url.

Referenced by acf_curl_helper().

◆ WriteMemoryCallback()

static size_t WriteMemoryCallback ( void *  ptr,
size_t  size,
size_t  nmemb,
void *  data 
)
static

Definition at line 701 of file func_curl.c.

702{
703 register int realsize = 0;
704 struct curl_write_callback_data *cb_data = data;
705
706 if (cb_data->str) {
707 realsize = size * nmemb;
708 ast_str_append_substr(&cb_data->str, 0, ptr, realsize);
709 } else if (cb_data->out_file) {
710 realsize = fwrite(ptr, size, nmemb, cb_data->out_file);
711 }
712
713 return realsize;
714}
char * ast_str_append_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string.
Definition: strings.h:1062
Callback data passed to WriteMemoryCallback.
Definition: func_curl.c:692

References ast_str_append_substr(), curl_write_callback_data::out_file, and curl_write_callback_data::str.

Referenced by curl_instance_init().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Load external URL" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_REALTIME_DEPEND2, .requires = "res_curl", }
static

Definition at line 1097 of file func_curl.c.

◆ acf_curl

struct ast_custom_function acf_curl
static
Initial value:
= {
.name = "CURL",
.read2 = acf_curl_exec,
.write = acf_curl_write,
}
static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len)
Definition: func_curl.c:935
static int acf_curl_write(struct ast_channel *chan, const char *cmd, char *name, const char *value)
Definition: func_curl.c:966

Definition at line 1004 of file func_curl.c.

Referenced by load_module(), and unload_module().

◆ acf_curlopt

struct ast_custom_function acf_curlopt
static

Definition at line 1010 of file func_curl.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1097 of file func_curl.c.

◆ curl_info

const struct ast_datastore_info curl_info
static
Initial value:
= {
.type = "CURL",
.destroy = curlds_free,
}
static void curlds_free(void *data)
Definition: func_curl.c:284

Definition at line 271 of file func_curl.c.

Referenced by acf_curl_helper(), acf_curlopt_helper(), and acf_curlopt_write().

◆ curl_instance

struct ast_threadstorage curl_instance = { .once = PTHREAD_ONCE_INIT , .key_init = __init_curl_instance , .custom_init = curl_instance_init , }
static

Definition at line 740 of file func_curl.c.

Referenced by acf_curl_helper().

◆ global_curl_info

struct global_curl_info global_curl_info = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }

◆ thread_escapebuf

struct ast_threadstorage thread_escapebuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_thread_escapebuf , .custom_init = NULL , }
static

Definition at line 741 of file func_curl.c.

Referenced by acf_curl_helper().