-/** Functions and datatypes for the REST (HTTP) transport.
- *
- * @file rest.c
- *
- * Version: $Id$
- *
+/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * $Id$
+ *
+ * @brief Functions and datatypes for the REST (HTTP) transport.
+ * @file rest.c
*
- * Copyright 2012 Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
+ * @copyright 2012-2013 Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
*/
#include <freeradius-devel/ident.h>
#include <string.h>
#include <time.h>
-#include <curl/curl.h>
-#include <json/json.h>
-
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/libradius.h>
#include <freeradius-devel/connection.h>
HTTP_BODY_UNSUPPORTED, // HTTP_BODY_UNSUPPORTED
HTTP_BODY_UNSUPPORTED, // HTTP_BODY_INVALID
HTTP_BODY_POST, // HTTP_BODY_POST
+#ifdef HAVE_JSON
HTTP_BODY_JSON, // HTTP_BODY_JSON
+#else
+ HTTP_BODY_UNAVAILABLE,
+#endif
HTTP_BODY_UNSUPPORTED, // HTTP_BODY_XML
HTTP_BODY_UNSUPPORTED, // HTTP_BODY_YAML
HTTP_BODY_INVALID, // HTTP_BODY_HTML
const FR_NAME_NUMBER http_body_type_table[] = {
{ "unknown", HTTP_BODY_UNKNOWN },
{ "unsupported", HTTP_BODY_UNSUPPORTED },
+ { "unavailable", HTTP_BODY_UNAVAILABLE },
{ "invalid", HTTP_BODY_INVALID },
{ "post", HTTP_BODY_POST },
{ "json", HTTP_BODY_JSON },
{ NULL , -1 }
};
+#ifdef HAVE_JSON
/** Flags to control the conversion of JSON values to VALUE_PAIRs.
*
* These fields are set when parsing the expanded format for value pairs in
* @see json_pairmake_leaf
*/
typedef struct json_flags {
- boolean do_xlat; //!< If TRUE value will be expanded with xlat.
- boolean is_json; //!< If TRUE value will be inserted as raw JSON
+ int do_xlat; //!< If TRUE value will be expanded with xlat.
+ int is_json; //!< If TRUE value will be inserted as raw JSON
// (multiple values not supported).
- FR_TOKEN operator; //!< The operator that determines how the new VP
+ FR_TOKEN op; //!< The operator that determines how the new VP
// is processed. @see fr_tokens
} json_flags_t;
+#endif
/** Initialises libcurl.
*
long last_socket;
CURLcode ret;
- curl_easy_getinfo(candle, CURLINFO_LASTSOCKET, &last_socket);
+ ret = curl_easy_getinfo(candle, CURLINFO_LASTSOCKET, &last_socket);
if (ret != CURLE_OK) {
radlog(L_ERR,
"rlm_rest (%s): Couldn't determine socket"
goto end_chunk;
}
- RDEBUG2("Encoding attribute \"%s\"", current[0]->name);
+ RDEBUG2("Encoding attribute \"%s\"", current[0]->da->name);
if (ctx->state == READ_STATE_ATTR_BEGIN) {
- escaped = curl_escape(current[0]->name,
- strlen(current[0]->name));
+ escaped = curl_escape(current[0]->da->name,
+ strlen(current[0]->da->name));
len = strlen(escaped);
if (s < (1 + len)) {
* successive calls will return additional encoded VALUE_PAIRs.
*
* Only complete attribute headers
- * @verbatim "<name>":{"type":"<type>","value":['</pre> @endverbatim
+ * @verbatim "<name>":{"type":"<type>","value":[' @endverbatim
* and complete attribute values will be written to ptr.
*
* If an attribute occurs multiple times in the request the attribute values
* New attribute, write name, type, and beginning of
* value array.
*/
- RDEBUG2("Encoding attribute \"%s\"", current[0]->name);
+ RDEBUG2("Encoding attribute \"%s\"", current[0]->da->name);
if (ctx->state == READ_STATE_ATTR_BEGIN) {
- type = fr_int2str(dict_attr_types, current[0]->type,
+ type = fr_int2str(dict_attr_types, current[0]->da->type,
"¿Unknown?");
len = strlen(type);
- len += strlen(current[0]->name);
+ len += strlen(current[0]->da->name);
if (s < (23 + len)) goto no_space;
len = sprintf(p, "\"%s\":{\"type\":\"%s\",\"value\":[" ,
- current[0]->name, type);
+ current[0]->da->name, type);
p += len;
s -= len;
/*
* Multivalued attribute
*/
- if (current[1] &&
- ((current[0]->attribute == current[1]->attribute) &&
- (current[0]->vendor == current[1]->vendor))) {
+ if (current[1] &&
+ (current[0]->da == current[1]->da)) {
*p++ = ',';
current++;
* @see rest_read_ctx_free
*
* @param[in] request Current request.
- * @param[in] read to initialise.
+ * @param[in] ctx to initialise.
* @param[in] sort If TRUE VALUE_PAIRs will be sorted within the VALUE_PAIR
* pointer array.
*/
static void rest_read_ctx_init(REQUEST *request,
rlm_rest_read_t *ctx,
- boolean sort)
+ int sort)
{
unsigned short count = 0, i;
unsigned short swap;
/* TODO: Quicksort would be faster... */
do {
for(i = 1; i < count; i++) {
- assert(current[i-1]->attribute &&
- current[i]->attribute);
-
swap = 0;
- if ((current[i-1]->vendor > current[i]->vendor) ||
- ((current[i-1]->vendor == current[i]->vendor) &&
- (current[i-1]->attribute > current[i]->attribute)
- )) {
+ if (current[i-1]->da > current[i]->da) {
tmp = current[i];
current[i] = current[i-1];
current[i-1] = tmp;
*
* @see rest_read_ctx_init
*
- * @param[in] read to free.
+ * @param[in] ctx to free.
*/
static void rest_read_ctx_free(rlm_rest_read_t *ctx)
{
}
}
-/** Verify that value wasn't truncated when it was converted to a VALUE_PAIR
- *
- * Certain values may be truncated when they're converted into VALUE_PAIRs
- * for example 64bit integers converted to 32bit integers. Warn the user
- * when this happens.
- *
- * @param[in] raw string from decoder.
- * @param[in] vp containing parsed value.
- */
-static void rest_check_truncation(REQUEST *request, const char *raw,
- VALUE_PAIR *vp)
-{
- char cooked[1024];
-
- vp_prints_value(cooked, sizeof(cooked), vp, 0);
- if (strcmp(raw, cooked) != 0) {
- RDEBUG("WARNING: Value-Pair does not match POST value, "
- "truncation may have occurred");
- RDEBUG("\tValue (pair) : \"%s\"", cooked);
- RDEBUG("\tValue (post) : \"%s\"", raw);
- }
-}
-
/** Converts POST response into VALUE_PAIRs and adds them to the request
*
* Accepts VALUE_PAIRS in the same format as rest_encode_post, but with the
const char *attribute;
char *name = NULL;
char *value = NULL;
+
+ char buffer[1024];
const DICT_ATTR *da;
VALUE_PAIR *vp;
const DICT_ATTR **current, *processed[REST_BODY_MAX_ATTRS + 1];
- VALUE_PAIR *tmp;
- pair_lists_t list;
+ pair_lists_t list_name;
+ request_refs_t request_name;
REQUEST *reference = request;
VALUE_PAIR **vps;
* Empty response?
*/
while (isspace(*p)) p++;
-
- if (p == NULL) return FALSE;
+ if (*p == '\0') return FALSE;
while (((q = strchr(p, '=')) != NULL) &&
(count < REST_BODY_MAX_ATTRS)) {
p = (q + 1);
RDEBUG("Decoding attribute \"%s\"", name);
+
+ request_name = radius_request_name(&attribute, REQUEST_CURRENT);
+ if (request_name == REQUEST_UNKNOWN) {
+ RDEBUGW("Invalid request qualifier, skipping");
- if (!radius_ref_request(&reference, &attribute)) {
- RDEBUG("WARNING: Attribute name refers to outer request"
+ curl_free(name);
+
+ continue;
+ }
+
+ if (!radius_request(&reference, request_name)) {
+ RDEBUGW("Attribute name refers to outer request"
" but not in a tunnel, skipping");
curl_free(name);
continue;
}
- list = radius_list_name(&attribute, PAIR_LIST_REPLY);
- if (list == PAIR_LIST_UNKNOWN) {
- RDEBUG("WARNING: Invalid list qualifier, skipping");
+ list_name = radius_list_name(&attribute, PAIR_LIST_REPLY);
+ if (list_name == PAIR_LIST_UNKNOWN) {
+ RDEBUGW("Invalid list qualifier, skipping");
curl_free(name);
da = dict_attrbyname(attribute);
if (!da) {
- RDEBUG("WARNING: Attribute \"%s\" unknown, skipping",
+ RDEBUGW("Attribute \"%s\" unknown, skipping",
attribute);
curl_free(name);
continue;
}
- vps = radius_list(reference, list);
+ vps = radius_list(reference, list_name);
assert(vps);
RDEBUG2("\tLength : %i", curl_len);
RDEBUG2("\tValue : \"%s\"", value);
+
+ RDEBUG("Performing xlat expansion of response value");
+
+ if (!radius_xlat(buffer, sizeof(buffer),
+ value, request, NULL, NULL)) {
+ goto skip;
+ }
- vp = paircreate(da->attr, da->vendor, da->type);
+ vp = pairalloc(NULL, da);
if (!vp) {
radlog(L_ERR, "rlm_rest (%s): Failed creating"
- " value-pair", instance->xlat_name);
+ " valuepair", instance->xlat_name);
goto error;
}
- vp->operator = T_OP_SET;
+ vp->op = T_OP_SET;
/*
* Check to see if we've already processed an
*/
current = processed;
while (*current++) {
- if ((current[0]->attr == da->attr) &&
- (current[0]->vendor == da->vendor)) {
- vp->operator = T_OP_ADD;
+ if (current[0] == da) {
+ vp->op = T_OP_ADD;
break;
}
}
- if (vp->operator != T_OP_ADD) {
+ if (vp->op != T_OP_ADD) {
current[0] = da;
current[1] = NULL;
}
- tmp = pairparsevalue(vp, value);
- if (tmp == NULL) {
+ if (!pairparsevalue(vp, buffer)) {
RDEBUG("Incompatible value assignment, skipping");
pairbasicfree(vp);
goto skip;
}
- vp = tmp;
-
- rest_check_truncation(request, value, vp);
-
- vp->flags.do_xlat = 1;
-
- RDEBUG("Performing xlat expansion of response value", value);
- pairxlatmove(request, vps, &vp);
if (++count == REST_BODY_MAX_ATTRS) {
radlog(L_ERR, "rlm_rest (%s): At maximum"
}
+#ifdef HAVE_JSON
/** Converts JSON "value" key into VALUE_PAIR.
*
* If leaf is not in fact a leaf node, but contains JSON data, the data will
* @param[in] instance configuration data.
* @param[in] section configuration data.
* @param[in] request Current request.
- * @param[in] attribute name without qualifiers.
+ * @param[in] da Attribute to create.
* @param[in] flags containing the operator other flags controlling value
* expansion.
* @param[in] leaf object containing the VALUE_PAIR value.
REQUEST *request, const DICT_ATTR *da,
json_flags_t *flags, json_object *leaf)
{
- const char *value;
- VALUE_PAIR *vp, *tmp;
+ const char *value, *to_parse;
+ char buffer[1024];
+
+ VALUE_PAIR *vp;
/*
* Should encode any nested JSON structures into JSON strings.
RDEBUG2("\tLength : %i", strlen(value));
RDEBUG2("\tValue : \"%s\"", value);
- vp = paircreate(da->attr, da->vendor, da->type);
+ if (flags->do_xlat) {
+ if (!radius_xlat(buffer, sizeof(buffer), value,
+ request, NULL, NULL)) {
+ return NULL;
+ }
+
+ to_parse = buffer;
+ } else {
+ to_parse = value;
+ }
+
+ vp = paircreate(da->attr, da->vendor);
if (!vp) {
- radlog(L_ERR, "rlm_rest (%s): Failed creating value-pair",
+ radlog(L_ERR, "rlm_rest (%s): Failed creating valuepair",
instance->xlat_name);
return NULL;
}
- vp->operator = flags->operator;
-
- tmp = pairparsevalue(vp, value);
- if (tmp == NULL) {
+ vp->op = flags->op;
+
+ if (!pairparsevalue(vp, to_parse)) {
RDEBUG("Incompatible value assignment, skipping");
pairbasicfree(vp);
return NULL;
}
- vp = tmp;
-
- rest_check_truncation(request, value, vp);
-
- if (flags->do_xlat) vp->flags.do_xlat = 1;
return vp;
}
* @param[in] object containing root node, or parent node.
* @param[in] level Current nesting level.
* @param[in] max_attrs counter, decremented after each VALUE_PAIR is created,
- * when 0 no more attributes will be processed.
+ * when 0 no more attributes will be processed.
* @return VALUE_PAIR or NULL on error.
*/
static VALUE_PAIR *json_pairmake(rlm_rest_t *instance,
json_flags_t flags;
const DICT_ATTR *da;
- VALUE_PAIR *vp;
+ VALUE_PAIR *vp = NULL;
- pair_lists_t list;
+ request_refs_t request_name;
+ pair_lists_t list_name;
REQUEST *reference = request;
VALUE_PAIR **vps;
*/
entry = json_object_get_object(object)->head;
while (entry) {
- flags.operator = T_OP_SET;
+ flags.op = T_OP_SET;
flags.do_xlat = 1;
flags.is_json = 0;
* pairlist.
*/
RDEBUG2("Decoding attribute \"%s\"", name);
+
+ request_name = radius_request_name(&attribute, REQUEST_CURRENT);
+ if (request_name == REQUEST_UNKNOWN) {
+ RDEBUGW("Request qualifier unknown, skipping");
+
+ continue;
+ }
- if (!radius_ref_request(&reference, &attribute)) {
- RDEBUG("WARNING: Attribute name refers to outer request"
+ if (!radius_request(&reference, request_name)) {
+ RDEBUGW("Attribute name refers to outer request"
" but not in a tunnel, skipping");
continue;
}
- list = radius_list_name(&attribute, PAIR_LIST_REPLY);
- if (list == PAIR_LIST_UNKNOWN) {
- RDEBUG("WARNING: Invalid list qualifier, skipping");
+ list_name = radius_list_name(&attribute, PAIR_LIST_REPLY);
+ if (list_name == PAIR_LIST_UNKNOWN) {
+ RDEBUGW("Invalid list qualifier, skipping");
continue;
}
da = dict_attrbyname(attribute);
if (!da) {
- RDEBUG("WARNING: Attribute \"%s\" unknown, skipping",
+ RDEBUGW("Attribute \"%s\" unknown, skipping",
attribute);
continue;
}
- vps = radius_list(reference, list);
+ vps = radius_list(reference, list_name);
assert(vps);
*/
tmp = json_object_object_get(value, "op");
if (tmp) {
- flags.operator = fr_str2int(fr_tokens,
- json_object_get_string(tmp), 0);
-
- if (!flags.operator) {
+ flags.op = fr_str2int(fr_tokens, json_object_get_string(tmp), 0);
+ if (!flags.op) {
RDEBUG("Invalid operator value \"%s\","
" skipping", tmp);
continue;
}
}
- /*
- * Setup pairmake / recursion loop.
- */
- if (!flags.is_json &&
- json_object_is_type(value, json_type_array)) {
- len = json_object_array_length(value);
- if (!len) {
- RDEBUG("Zero length value array, skipping", value);
- continue;
- }
- idx = json_object_array_get_idx(value, 0);
- } else {
- len = 1;
- idx = value;
- }
-
- i = 0;
- do {
- if (!(*max_attrs)--) {
- radlog(L_ERR, "rlm_rest (%s): At maximum"
- " attribute limit", instance->xlat_name);
- return NULL;
- }
+ /*
+ * Setup pairmake / recursion loop.
+ */
+ if (!flags.is_json &&
+ json_object_is_type(value, json_type_array)) {
+ len = json_object_array_length(value);
+ if (!len) {
+ RDEBUG("Zero length value array, skipping",
+ value);
+ continue;
+ }
+ idx = json_object_array_get_idx(value, 0);
+ } else {
+ len = 1;
+ idx = value;
+ }
- /*
- * Automagically switch the op for multivalued
- * attributes.
- */
- if (((flags.operator == T_OP_SET) ||
- (flags.operator == T_OP_EQ)) && (len > 1)) {
- flags.operator = T_OP_ADD;
- }
+ i = 0;
+ do {
+ if (!(*max_attrs)--) {
+ radlog(L_ERR, "rlm_rest (%s): At "
+ "maximum attribute limit",
+ instance->xlat_name);
+ return NULL;
+ }
- if (!flags.is_json &&
- json_object_is_type(value, json_type_object)) {
- /* TODO: Insert nested VP into VP structure...*/
- RDEBUG("Found nested VP", value);
- vp = json_pairmake(instance, section,
- request, value,
- level + 1, max_attrs);
- } else {
- vp = json_pairmake_leaf(instance, section,
- request, da, &flags,
- idx);
-
- if (vp != NULL) {
- if (vp->flags.do_xlat) {
- RDEBUG("Performing xlat"
- " expansion of response"
- " value", value);
- }
+ /*
+ * Automagically switch the op for multivalued
+ * attributes.
+ */
+ if (((flags.op == T_OP_SET) ||
+ (flags.op == T_OP_EQ)) && (len > 1)) {
+ flags.op = T_OP_ADD;
+ }
- pairxlatmove(request, vps, &vp);
+ if (!flags.is_json &&
+ json_object_is_type(value, json_type_object)) {
+ /* TODO: Insert nested VP into VP structure...*/
+ RDEBUG("Found nested VP", value);
+ vp = json_pairmake(instance, section,
+ request, value,
+ level + 1, max_attrs);
+ } else {
+ vp = json_pairmake_leaf(instance, section,
+ request, da, &flags,
+ idx);
}
- }
- } while ((++i < len) && (idx = json_object_array_get_idx(value, i)));
+ } while ((++i < len) &&
+ (idx = json_object_array_get_idx(value, i)));
}
return vp;
*
* Converts the raw JSON string into a json-c object tree and passes it to
* json_pairmake. After the tree has been parsed json_object_put is called
- * which decrements the reference, count to the root node by one, and frees
+ * which decrements the reference count of the root node by one, and frees
* the entire tree.
*
* @see rest_encode_json
*
* @param[in] instance configuration data.
* @param[in] section configuration data.
- * @param[in] g to use.
- * @param[in] request Current request.
+ * @param[in,out] request Current request.
+ * @param[in] handle REST handle.
* @param[in] raw buffer containing JSON data.
* @param[in] rawlen Length of data in raw buffer.
* @return the number of VALUE_PAIRs processed or -1 on unrecoverable error.
*/
static int rest_decode_json(rlm_rest_t *instance,
UNUSED rlm_rest_section_t *section,
- UNUSED REQUEST *request, UNUSED void *handle,
+ REQUEST *request, UNUSED void *handle,
char *raw, UNUSED size_t rawlen)
{
const char *p = raw;
* Empty response?
*/
while (isspace(*p)) p++;
- if (p == NULL) return FALSE;
+ if (*p == '\0') return FALSE;
json = json_tokener_parse(p);
if (!json) {
return (REST_BODY_MAX_ATTRS - max);
}
+#endif
/** Processes incoming HTTP header data from libcurl.
*
ctx->code = atoi(p);
/*
- * Process reason_phrase (if present).
+ * Process reason_phrase (if present).
*/
if (p[3] == ' ') {
p += 4;
fr_int2str(http_body_type_table,
type, "¿Unknown?"));
ctx->type = HTTP_BODY_UNSUPPORTED;
+ } else if (supp == HTTP_BODY_UNAVAILABLE) {
+ RDEBUG("Type \"%s\" is currently"
+ " unavailable, please rebuild"
+ " this module with the required"
+ " headers",
+ fr_int2str(http_body_type_table,
+ type, "¿Unknown?"));
+ ctx->type = HTTP_BODY_UNSUPPORTED;
} else if (supp == HTTP_BODY_INVALID) {
RDEBUG("Type \"%s\" is not a valid web"
* @see rest_write_header
*
* @param[in] request Current request.
- * @param[in] data to initialise.
+ * @param[in] ctx data to initialise.
* @param[in] type Default http_body_type to use when decoding raw data, may be
* overwritten by rest_write_header.
*/
/** Frees the intermediary buffer created by rest_write.
*
- * @param[in] data to be freed.
+ * @param[in] ctx data to be freed.
*/
static void rest_write_free(rlm_rest_write_t *ctx)
{
* @param[in] section configuration data.
* @param[in] handle rlm_rest_handle_t to configure.
* @param[in] func to pass to libcurl for chunked.
- * transfers (NULL if not using chunked mode).
+ * transfers (NULL if not using chunked mode).
* @return TRUE on success FALSE on error.
*/
static int rest_request_config_body(rlm_rest_t *instance,
CURLOPT_CUSTOMREQUEST,
section->method);
if (ret != CURLE_OK) goto error;
+ break;
default:
assert(0);
if (section->username) {
radius_xlat(buffer, sizeof(buffer),
- section->username, request, NULL);
+ section->username, request, NULL, NULL);
ret = curl_easy_setopt(candle, CURLOPT_USERNAME,
buffer);
}
if (section->password) {
radius_xlat(buffer, sizeof(buffer),
- section->password, request, NULL);
+ section->password, request, NULL, NULL);
ret = curl_easy_setopt(candle, CURLOPT_PASSWORD,
buffer);
if (section->username) {
radius_xlat(buffer, sizeof(buffer),
- section->username, request, NULL);
+ section->username, request, NULL, NULL);
ret = curl_easy_setopt(candle,
CURLOPT_TLSAUTH_USERNAME,
}
if (section->password) {
radius_xlat(buffer, sizeof(buffer),
- section->password, request, NULL);
+ section->password, request, NULL, NULL);
ret = curl_easy_setopt(candle,
CURLOPT_TLSAUTH_PASSWORD,
}
/*
- * Set SSL authentication parameters
+ * Set SSL/TLS authentication parameters
*/
- if (section->certificate_file) {
+ if (section->tls_certfile) {
ret = curl_easy_setopt(candle,
CURLOPT_SSLCERT,
- section->certificate_file);
+ section->tls_certfile);
if (ret != CURLE_OK) goto error;
}
- if (section->file_type == FALSE) {
+ if (section->tls_keyfile) {
ret = curl_easy_setopt(candle,
- CURLOPT_SSLCERT,
- "DER");
- if (ret != CURLE_OK) goto error;
- }
-
- if (section->private_key_file) {
- ret = curl_easy_setopt(candle,
- CURLOPT_SSLCERT,
- section->private_key_file);
+ CURLOPT_SSLKEY,
+ section->tls_keyfile);
if (ret != CURLE_OK) goto error;
}
- if (section->private_key_password) {
+ if (section->tls_keypassword) {
ret = curl_easy_setopt(candle,
CURLOPT_KEYPASSWD,
- section->private_key_password);
+ section->tls_keypassword);
if (ret != CURLE_OK) goto error;
}
- if (section->ca_file) {
+ if (section->tls_cacertfile) {
ret = curl_easy_setopt(candle,
CURLOPT_ISSUERCERT,
- section->ca_file);
+ section->tls_cacertfile);
if (ret != CURLE_OK) goto error;
}
- if (section->ca_path) {
+ if (section->tls_cacertdir) {
ret = curl_easy_setopt(candle,
CURLOPT_CAPATH,
- section->ca_path);
+ section->tls_cacertdir);
if (ret != CURLE_OK) goto error;
}
- if (section->random_file) {
+ if (section->tls_randfile) {
ret = curl_easy_setopt(candle,
CURLOPT_RANDOM_FILE,
- section->random_file);
+ section->tls_randfile);
if (ret != CURLE_OK) goto error;
}
- ret = curl_easy_setopt(candle,
- CURLOPT_SSL_VERIFYHOST,
- (section->check_cert_cn == TRUE) ?
- 2 : 0);
- if (ret != CURLE_OK) goto error;
+ if (section->tls_verify_cert) {
+ ret = curl_easy_setopt(candle,
+ CURLOPT_SSL_VERIFYHOST,
+ (section->tls_verify_cert_cn == TRUE) ?
+ 2 : 0);
+ if (ret != CURLE_OK) goto error;
+ } else {
+ ret = curl_easy_setopt(candle,
+ CURLOPT_SSL_VERIFYPEER,
+ 0);
+ if (ret != CURLE_OK) goto error;
+ }
/*
* Tell CURL how to get HTTP body content, and how to process
switch (type)
{
+#ifdef HAVE_JSON
case HTTP_BODY_JSON:
rest_read_ctx_init(request,
&ctx->read, 1);
if (!ret) return -1;
break;
+#endif
case HTTP_BODY_POST:
rest_read_ctx_init(request,
return FALSE;
}
- RDEBUG("Processing body", ret);
+ RDEBUG("Processing body");
switch (ctx->write.type)
{
handle, ctx->write.buffer,
ctx->write.used);
break;
-
+#ifdef HAVE_JSON
case HTTP_BODY_JSON:
ret = rest_decode_json(instance, section, request,
handle, ctx->write.buffer,
ctx->write.used);
break;
-
+#endif
case HTTP_BODY_UNSUPPORTED:
+ case HTTP_BODY_UNAVAILABLE:
case HTTP_BODY_INVALID:
return -1;
*
* Encode special chars as per RFC 3986 section 4.
*
+ * @param[in] request Current request.
* @param[out] out Where to write escaped string.
* @param[in] outlen Size of out buffer.
* @param[in] raw string to be urlencoded.
+ * @param[in] arg pointer, gives context for escaping.
* @return length of data written to out (excluding NULL).
*/
-static size_t rest_uri_escape(char *out, size_t outlen, const char *raw)
+static size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen,
+ const char *raw, UNUSED void *arg)
{
char *escaped;
p = section->uri;
- while ((q = strchr(p, '/')) && (count++ < 3)) p = (q + 1);
+ /*
+ * All URLs must contain at least <scheme>://<server>/
+ */
+ while ((q = strchr(p, '/'))) {
+ p = q + 1;
+
+ if (++count == 3) {
+ break;
+ }
+ }
if (count != 3) {
radlog(L_ERR, "rlm_rest (%s): Error URI is malformed,"
path = (q + 1);
out = buffer;
- out += radius_xlat(out, bufsize, scheme, request, NULL);
+ out += radius_xlat(out, bufsize, scheme, request, NULL, NULL);
free(scheme);
out += radius_xlat(out, (bufsize - (buffer - out)), path, request,
- rest_uri_escape);
+ rest_uri_escape, NULL);
return (buffer - out);
}