262#define CURLVERSION_ATLEAST(a,b,c) \ 
  263    ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c)))) 
 
  265#define CURLOPT_SPECIAL_HASHCOMPAT ((CURLoption) -500) 
  267#define CURLOPT_SPECIAL_FAILURE_CODE 999 
  314    if (!strcasecmp(
name, 
"header")) {
 
  315        *
key = CURLOPT_HEADER;
 
  317    } 
else if (!strcasecmp(
name, 
"httpheader")) {
 
  318        *
key = CURLOPT_HTTPHEADER;
 
  320    } 
else if (!strcasecmp(
name, 
"httpauth")) {
 
  321        *
key = CURLOPT_HTTPAUTH;
 
  323    } 
else if (!strcasecmp(
name, 
"proxy")) {
 
  324        *
key = CURLOPT_PROXY;
 
  326    } 
else if (!strcasecmp(
name, 
"proxyport")) {
 
  327        *
key = CURLOPT_PROXYPORT;
 
  329    } 
else if (!strcasecmp(
name, 
"proxytype")) {
 
  330        *
key = CURLOPT_PROXYTYPE;
 
  332    } 
else if (!strcasecmp(
name, 
"dnstimeout")) {
 
  333        *
key = CURLOPT_DNS_CACHE_TIMEOUT;
 
  335    } 
else if (!strcasecmp(
name, 
"userpwd")) {
 
  336        *
key = CURLOPT_USERPWD;
 
  338    } 
else if (!strcasecmp(
name, 
"proxyuserpwd")) {
 
  339        *
key = CURLOPT_PROXYUSERPWD;
 
  341    } 
else if (!strcasecmp(
name, 
"followlocation")) {
 
  342        *
key = CURLOPT_FOLLOWLOCATION;
 
  344    } 
else if (!strcasecmp(
name, 
"maxredirs")) {
 
  345        *
key = CURLOPT_MAXREDIRS;
 
  347    } 
else if (!strcasecmp(
name, 
"referer")) {
 
  348        *
key = CURLOPT_REFERER;
 
  350    } 
else if (!strcasecmp(
name, 
"useragent")) {
 
  351        *
key = CURLOPT_USERAGENT;
 
  353    } 
else if (!strcasecmp(
name, 
"cookie")) {
 
  354        *
key = CURLOPT_COOKIE;
 
  356    } 
else if (!strcasecmp(
name, 
"ftptimeout")) {
 
  357        *
key = CURLOPT_FTP_RESPONSE_TIMEOUT;
 
  359    } 
else if (!strcasecmp(
name, 
"httptimeout")) {
 
  360#if CURLVERSION_ATLEAST(7,16,2) 
  361        *
key = CURLOPT_TIMEOUT_MS;
 
  364        *
key = CURLOPT_TIMEOUT;
 
  367    } 
else if (!strcasecmp(
name, 
"conntimeout")) {
 
  368#if CURLVERSION_ATLEAST(7,16,2) 
  369        *
key = CURLOPT_CONNECTTIMEOUT_MS;
 
  372        *
key = CURLOPT_CONNECTTIMEOUT;
 
  375    } 
else if (!strcasecmp(
name, 
"ftptext")) {
 
  376        *
key = CURLOPT_TRANSFERTEXT;
 
  378    } 
else if (!strcasecmp(
name, 
"ssl_verifypeer")) {
 
  379        *
key = CURLOPT_SSL_VERIFYPEER;
 
  381    } 
else if (!strcasecmp(
name, 
"ssl_verifyhost")) {
 
  382        *
key = CURLOPT_SSL_VERIFYHOST;
 
  384    } 
else if (!strcasecmp(
name, 
"ssl_cainfo")) {
 
  385        *
key = CURLOPT_CAINFO;
 
  387    } 
else if (!strcasecmp(
name, 
"ssl_capath")) {
 
  388        *
key = CURLOPT_CAPATH;
 
  390    } 
else if (!strcasecmp(
name, 
"ssl_cert")) {
 
  391        *
key = CURLOPT_SSLCERT;
 
  393    } 
else if (!strcasecmp(
name, 
"ssl_certtype")) {
 
  394        *
key = CURLOPT_SSLCERTTYPE;
 
  396    } 
else if (!strcasecmp(
name, 
"ssl_key")) {
 
  397        *
key = CURLOPT_SSLKEY;
 
  399    } 
else if (!strcasecmp(
name, 
"ssl_keytype")) {
 
  400        *
key = CURLOPT_SSLKEYTYPE;
 
  402    } 
else if (!strcasecmp(
name, 
"ssl_keypasswd")) {
 
  403        *
key = CURLOPT_KEYPASSWD;
 
  405    } 
else if (!strcasecmp(
name, 
"hashcompat")) {
 
  408    } 
else if (!strcasecmp(
name, 
"failurecodes")) {
 
 
  430                ast_log(
LOG_ERROR, 
"Unable to allocate new datastore.  Cannot set any CURL options\n");
 
  436                ast_log(
LOG_ERROR, 
"Unable to allocate list head.  Cannot set any CURL options\n");
 
  460            long tmp = atol(
value);
 
  462                new->value = (
void *)tmp;
 
  465            long tmp = atof(
value) * 1000.0;
 
  467                new->value = (
void *)tmp;
 
  471                new->value = (
char *)
new + 
sizeof(*
new);
 
  472                strcpy(new->value, 
value);
 
  475            if (
key == CURLOPT_PROXYTYPE) {
 
  477#if CURLVERSION_ATLEAST(7,10,0) 
  483#if CURLVERSION_ATLEAST(7,15,2) 
  484                } 
else if (!strcasecmp(
value, 
"socks4")) {
 
  485                    ptype = CURLPROXY_SOCKS4;
 
  487#if CURLVERSION_ATLEAST(7,18,0) 
  488                } 
else if (!strcasecmp(
value, 
"socks4a")) {
 
  489                    ptype = CURLPROXY_SOCKS4A;
 
  491#if CURLVERSION_ATLEAST(7,18,0) 
  492                } 
else if (!strcasecmp(
value, 
"socks5")) {
 
  493                    ptype = CURLPROXY_SOCKS5;
 
  495#if CURLVERSION_ATLEAST(7,18,0) 
  496                } 
else if (!strncasecmp(
value, 
"socks5", 6)) {
 
  497                    ptype = CURLPROXY_SOCKS5_HOSTNAME;
 
  502                    new->value = (
void *)ptype;
 
  504            } 
else if (
key == CURLOPT_HTTPAUTH) {
 
  507                while ((authmethod = 
strsep(&authstr, 
","))) {
 
  508                    if (!strcasecmp(authmethod, 
"basic")) {
 
  509                        authtype |= CURLAUTH_BASIC;
 
  510                    } 
else if (!strcasecmp(authmethod, 
"digest")) {
 
  511                        authtype |= CURLAUTH_DIGEST;
 
  521                    new->value = (
void *)authtype;
 
  547    if (new->key != CURLOPT_HTTPHEADER) {
 
  549            if (cur->
key == new->key) {
 
  559    ast_debug(1, 
"Inserting entry %p with key %d and value %p\n", 
new, new->key, new->value);
 
 
  593    for (i = 0; i < 2; i++) {
 
  607                    if ((
long) cur->
value % 1000 == 0) {
 
  609                            snprintf(
buf, 
len, 
"%ld", (
long)cur->
value / 1000);
 
  615                            snprintf(
buf, 
len, 
"%.3f", (
double) ((
long) cur->
value) / 1000.0);
 
  621                    ast_debug(1, 
"Found entry %p, with key %d and value %p\n", cur, cur->
key, cur->
value);
 
  627                } 
else if (
key == CURLOPT_PROXYTYPE) {
 
  628                    const char *strval = 
"unknown";
 
  630#if CURLVERSION_ATLEAST(7,15,2) 
  631                    } 
else if ((
long)cur->
value == CURLPROXY_SOCKS4) {
 
  634#if CURLVERSION_ATLEAST(7,18,0) 
  635                    } 
else if ((
long)cur->
value == CURLPROXY_SOCKS4A) {
 
  638                    } 
else if ((
long)cur->
value == CURLPROXY_SOCKS5) {
 
  640#if CURLVERSION_ATLEAST(7,18,0) 
  641                    } 
else if ((
long)cur->
value == CURLPROXY_SOCKS5_HOSTNAME) {
 
  642                        strval = 
"socks5hostname";
 
  644#if CURLVERSION_ATLEAST(7,10,0) 
  645                    } 
else if ((
long)cur->
value == CURLPROXY_HTTP) {
 
  655                    const char *strval = 
"unknown";
 
 
  703    register int realsize = 0;
 
  707        realsize = size * nmemb;
 
  710        realsize = fwrite(ptr, size, nmemb, cb_data->
out_file);
 
 
  720    if (!(*curl = curl_easy_init()))
 
  723    curl_easy_setopt(*curl, CURLOPT_NOSIGNAL, 1);
 
  724    curl_easy_setopt(*curl, CURLOPT_TIMEOUT, 180);
 
 
  735    curl_easy_cleanup(*curl);
 
 
  761    if (strpbrk(
url, 
"\r\n")) {
 
 
  781    char *failurecodestrings,*found;
 
  784    struct curl_slist *headers = 
NULL;
 
  788    char curl_errbuf[CURL_ERROR_SIZE + 1]; 
 
  800        ast_log(
LOG_ERROR, 
"URL '%s' is vulnerable to HTTP injection attacks. Aborting CURL() call.\n", 
args->url);
 
  813        } 
else if (cur->
key == CURLOPT_HTTPHEADER) {
 
  814            headers = curl_slist_append(headers, (
char*) cur->
value);
 
  816            failurecodestrings = (
char*) cur->
value;
 
  817            while( (found = 
strsep(&failurecodestrings, 
",")) != 
NULL) {
 
  821            curl_easy_setopt(*curl, cur->
key, cur->
value);
 
  836                } 
else if (cur->
key == CURLOPT_HTTPHEADER) {
 
  837                    headers = curl_slist_append(headers, (
char*) cur->
value);
 
  839                    failurecodestrings = (
char*) cur->
value;
 
  840                    while( (found = 
strsep(&failurecodestrings, 
",")) != 
NULL) {
 
  844                    curl_easy_setopt(*curl, cur->
key, cur->
value);
 
  850    curl_easy_setopt(*curl, CURLOPT_URL, 
args->url);
 
  851    curl_easy_setopt(*curl, CURLOPT_FILE, (
void *) &
args->cb_data);
 
  853    if (
args->postdata) {
 
  854        curl_easy_setopt(*curl, CURLOPT_POST, 1);
 
  855        curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, 
args->postdata);
 
  861    curl_easy_setopt(*curl, CURLOPT_HTTPHEADER, headers);
 
  864    curl_errbuf[0] = curl_errbuf[CURL_ERROR_SIZE] = 
'\0';
 
  865    curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, curl_errbuf);
 
  867    if (curl_easy_perform(*curl) != 0) {
 
  875    curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, (
char*)
NULL);
 
  876    curl_easy_getinfo (*curl, CURLINFO_RESPONSE_CODE, &http_code);
 
  894    curl_slist_free_all(headers);
 
  896    if (
args->postdata) {
 
  897        curl_easy_setopt(*curl, CURLOPT_POST, 0);
 
  910            while (fields && 
values && (piece = 
strsep(&remainder, 
"&"))) {
 
 
 1017#ifdef TEST_FRAMEWORK 
 1020    const char *bad_urls [] = {
 
 1021        "http://example.com\r\nDELETE http://example.com/everything",
 
 1022        "http://example.com\rDELETE http://example.com/everything",
 
 1023        "http://example.com\nDELETE http://example.com/everything",
 
 1024        "\r\nhttp://example.com",
 
 1025        "\rhttp://example.com",
 
 1026        "\nhttp://example.com",
 
 1027        "http://example.com\r\n",
 
 1028        "http://example.com\r",
 
 1029        "http://example.com\n",
 
 1031    const char *good_urls [] = {
 
 1032        "http://example.com",
 
 1033        "http://example.com/%5Cr%5Cn",
 
 1040        info->name = 
"vulnerable_url";
 
 1041        info->category = 
"/funcs/func_curl/";
 
 1042        info->summary = 
"cURL vulnerable URL test";
 
 1044            "Ensure that any combination of '\\r' or '\\n' in a URL invalidates the URL";
 
 1049    for (i = 0; i < 
ARRAY_LEN(bad_urls); ++i) {
 
 1056    for (i = 0; i < 
ARRAY_LEN(good_urls); ++i) {
 
 1096    .
requires = 
"res_curl",
 
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define AST_CURL_USER_AGENT
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_calloc(num, len)
A wrapper for calloc()
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
#define ast_channel_lock(chan)
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
#define ast_channel_unlock(chan)
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.
Standard Command Line Interface.
#define ast_datastore_alloc(info, uid)
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Generic File Format Support. Should be included by clients of the file handling routines....
#define CURLOPT_SPECIAL_HASHCOMPAT
static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args)
static int acf_curlopt_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
static void curl_instance_cleanup(void *data)
static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len)
static const struct ast_datastore_info curl_info
static int acf_curlopt_write(struct ast_channel *chan, const char *cmd, char *name, const char *value)
static int curl_instance_init(void *data)
static int acf_curlopt_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
#define CURLOPT_SPECIAL_FAILURE_CODE
static void curlds_free(void *data)
static int url_is_vulnerable(const char *url)
Check for potential HTTP injection risk.
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_curl_write(struct ast_channel *chan, const char *cmd, char *name, const char *value)
static struct ast_custom_function acf_curlopt
static int load_module(void)
static int unload_module(void)
static struct ast_custom_function acf_curl
static int parse_curlopt_key(const char *name, CURLoption *key, enum optiontype *ot)
static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#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 ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_LOCK(head)
Locks a list.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Asterisk locking-related definitions:
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODPRI_REALTIME_DEPEND2
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
Core PBX routines and definitions.
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 ast_custom_function_register_escalating(acf, escalation)
Register a custom function which requires escalated privileges.
#define ast_custom_function_register(acf)
Register a custom function.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
size_t attribute_pure ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
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.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
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.
void ast_str_trim_blanks(struct ast_str *buf)
Trims trailing whitespace characters from an ast_str string.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Main Channel structure associated with a channel.
Data structure associated with a custom dialplan function.
Structure for a data store type.
Structure for a data store object.
Structure used to handle boolean flags.
Support for dynamic strings.
Integer vector definition.
struct curl_write_callback_data cb_data
struct curl_settings::@178 list
Callback data passed to WriteMemoryCallback.
struct ast_str * str
If a string is being built, the string buffer.
ssize_t len
The max size of str.
FILE * out_file
If a file is being retrieved, the file to write to.
#define AST_TEST_REGISTER(cb)
#define ast_test_status_update(a, b, c...)
#define AST_TEST_UNREGISTER(cb)
#define AST_TEST_DEFINE(hdr)
Definitions to aid in the use of thread local storage.
#define AST_THREADSTORAGE_CUSTOM(a, b, c)
Define a thread storage variable, with custom initialization and cleanup.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
const struct ast_flags ast_uri_http
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
const struct ast_flags ast_uri_http_legacy
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.