Merge tag 'release_3_0_12' into branch moonshot-fr-3.0.12-upgrade.
[freeradius.git] / src / modules / rlm_rest / rest.c
1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16
17 /**
18  * $Id$
19  *
20  * @brief Functions and datatypes for the REST (HTTP) transport.
21  * @file rest.c
22  *
23  * @copyright 2012-2014  Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
24  */
25
26 RCSID("$Id$")
27
28 #include <ctype.h>
29 #include <string.h>
30 #include <time.h>
31
32 #include <freeradius-devel/rad_assert.h>
33 #include <freeradius-devel/radiusd.h>
34 #include <freeradius-devel/libradius.h>
35 #include <freeradius-devel/connection.h>
36
37 #include "rest.h"
38
39 /*
40  * This is a workaround to backward versions.
41  */
42 #if defined(HAVE_JSON) && !defined(JSON_C_MINOR_VERSION) /* The versions less then 10, don't declare the 'JSON_C_MINOR_VERSION'*/
43 int json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value);
44 int json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value) {
45         *value = json_object_object_get(jso, key);
46
47         return (*value != NULL);
48 }
49 #endif
50
51 /** Table of encoder/decoder support.
52  *
53  * Indexes in this table match the http_body_type_t enum, and should be
54  * updated if additional enum values are added.
55  *
56  * @see http_body_type_t
57  */
58 const http_body_type_t http_body_type_supported[HTTP_BODY_NUM_ENTRIES] = {
59         HTTP_BODY_UNKNOWN,              // HTTP_BODY_UNKNOWN
60         HTTP_BODY_UNSUPPORTED,          // HTTP_BODY_UNSUPPORTED
61         HTTP_BODY_UNSUPPORTED,          // HTTP_BODY_UNAVAILABLE
62         HTTP_BODY_UNSUPPORTED,          // HTTP_BODY_INVALID
63         HTTP_BODY_NONE,                 // HTTP_BODY_NONE
64         HTTP_BODY_CUSTOM_XLAT,          // HTTP_BODY_CUSTOM_XLAT
65         HTTP_BODY_CUSTOM_LITERAL,       // HTTP_BODY_CUSTOM_LITERAL
66         HTTP_BODY_POST,                 // HTTP_BODY_POST
67 #ifdef HAVE_JSON
68         HTTP_BODY_JSON,                 // HTTP_BODY_JSON
69 #else
70         HTTP_BODY_UNAVAILABLE,
71 #endif
72         HTTP_BODY_UNSUPPORTED,          // HTTP_BODY_XML
73         HTTP_BODY_UNSUPPORTED,          // HTTP_BODY_YAML
74         HTTP_BODY_INVALID,              // HTTP_BODY_HTML
75         HTTP_BODY_PLAIN                 // HTTP_BODY_PLAIN
76 };
77
78 /*
79  *      Lib CURL doesn't define symbols for unsupported auth methods
80  */
81 #ifndef CURLOPT_TLSAUTH_SRP
82 #  define CURLOPT_TLSAUTH_SRP   0
83 #endif
84 #ifndef CURLAUTH_BASIC
85 #  define CURLAUTH_BASIC        0
86 #endif
87 #ifndef CURLAUTH_DIGEST
88 #  define CURLAUTH_DIGEST       0
89 #endif
90 #ifndef CURLAUTH_DIGEST_IE
91 #  define CURLAUTH_DIGEST_IE    0
92 #endif
93 #ifndef CURLAUTH_GSSNEGOTIATE
94 #  define CURLAUTH_GSSNEGOTIATE 0
95 #endif
96 #ifndef CURLAUTH_NTLM
97 #  define CURLAUTH_NTLM         0
98 #endif
99 #ifndef CURLAUTH_NTLM_WB
100 #  define CURLAUTH_NTLM_WB      0
101 #endif
102
103 /*
104  *  CURL headers do:
105  *
106  *  #define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param)
107  */
108 DIAG_OPTIONAL
109 DIAG_OFF(disabled-macro-expansion)
110 #define SET_OPTION(_x, _y)\
111 do {\
112         if ((ret = curl_easy_setopt(candle, _x, _y)) != CURLE_OK) {\
113                 option = STRINGIFY(_x);\
114                 goto error;\
115         }\
116 } while (0)
117
118 const unsigned long http_curl_auth[HTTP_AUTH_NUM_ENTRIES] = {
119         0,                      // HTTP_AUTH_UNKNOWN
120         0,                      // HTTP_AUTH_NONE
121         CURLOPT_TLSAUTH_SRP,    // HTTP_AUTH_TLS_SRP
122         CURLAUTH_BASIC,         // HTTP_AUTH_BASIC
123         CURLAUTH_DIGEST,        // HTTP_AUTH_DIGEST
124         CURLAUTH_DIGEST_IE,     // HTTP_AUTH_DIGEST_IE
125         CURLAUTH_GSSNEGOTIATE,  // HTTP_AUTH_GSSNEGOTIATE
126         CURLAUTH_NTLM,          // HTTP_AUTH_NTLM
127         CURLAUTH_NTLM_WB,       // HTTP_AUTH_NTLM_WB
128         CURLAUTH_ANY,           // HTTP_AUTH_ANY
129         CURLAUTH_ANYSAFE        // HTTP_AUTH_ANY_SAFE
130 };
131
132
133 /** Conversion table for method config values.
134  *
135  * HTTP verb strings for http_method_t enum values. Used by libcurl in the
136  * status line of the outgoing HTTP header, by rest_response_header for decoding
137  * incoming HTTP responses, and by the configuration parser.
138  *
139  * @note must be kept in sync with http_method_t enum.
140  *
141  * @see http_method_t
142  * @see fr_str2int
143  * @see fr_int2str
144  */
145 const FR_NAME_NUMBER http_method_table[] = {
146         { "UNKNOWN",                            HTTP_METHOD_UNKNOWN     },
147         { "GET",                                HTTP_METHOD_GET         },
148         { "POST",                               HTTP_METHOD_POST        },
149         { "PUT",                                HTTP_METHOD_PUT         },
150         { "PATCH",                              HTTP_METHOD_PATCH       },
151         { "DELETE",                             HTTP_METHOD_DELETE      },
152
153         {  NULL , -1 }
154 };
155
156 /** Conversion table for type config values.
157  *
158  * Textual names for http_body_type_t enum values, used by the
159  * configuration parser.
160  *
161  * @see http_body_Type_t
162  * @see fr_str2int
163  * @see fr_int2str
164  */
165 const FR_NAME_NUMBER http_body_type_table[] = {
166         { "unknown",                            HTTP_BODY_UNKNOWN       },
167         { "unsupported",                        HTTP_BODY_UNSUPPORTED   },
168         { "unavailable",                        HTTP_BODY_UNAVAILABLE   },
169         { "invalid",                            HTTP_BODY_INVALID       },
170         { "none",                               HTTP_BODY_NONE          },
171         { "post",                               HTTP_BODY_POST          },
172         { "json",                               HTTP_BODY_JSON          },
173         { "xml",                                HTTP_BODY_XML           },
174         { "yaml",                               HTTP_BODY_YAML          },
175         { "html",                               HTTP_BODY_HTML          },
176         { "plain",                              HTTP_BODY_PLAIN         },
177
178         {  NULL , -1 }
179 };
180
181 const FR_NAME_NUMBER http_auth_table[] = {
182         { "none",                               HTTP_AUTH_NONE          },
183         { "srp",                                HTTP_AUTH_TLS_SRP       },
184         { "basic",                              HTTP_AUTH_BASIC         },
185         { "digest",                             HTTP_AUTH_DIGEST        },
186         { "digest-ie",                          HTTP_AUTH_DIGEST_IE     },
187         { "gss-negotiate",                      HTTP_AUTH_GSSNEGOTIATE  },
188         { "ntlm",                               HTTP_AUTH_NTLM          },
189         { "ntlm-winbind",                       HTTP_AUTH_NTLM_WB       },
190         { "any",                                HTTP_AUTH_ANY           },
191         { "safe",                               HTTP_AUTH_ANY_SAFE      },
192
193         {  NULL , -1 }
194 };
195
196 /** Conversion table for "Content-Type" header values.
197  *
198  * Used by rest_response_header for parsing incoming headers.
199  *
200  * Values we expect to see in the 'Content-Type:' header of the incoming
201  * response.
202  *
203  * Some data types (like YAML) do no have standard MIME types defined,
204  * so multiple types, are listed here.
205  *
206  * @see http_body_Type_t
207  * @see fr_str2int
208  * @see fr_int2str
209  */
210 const FR_NAME_NUMBER http_content_type_table[] = {
211         { "application/x-www-form-urlencoded",  HTTP_BODY_POST          },
212         { "application/json",                   HTTP_BODY_JSON          },
213         { "text/html",                          HTTP_BODY_HTML          },
214         { "text/plain",                         HTTP_BODY_PLAIN         },
215         { "text/xml",                           HTTP_BODY_XML           },
216         { "text/yaml",                          HTTP_BODY_YAML          },
217         { "text/x-yaml",                        HTTP_BODY_YAML          },
218         { "application/yaml",                   HTTP_BODY_YAML          },
219         { "application/x-yaml",                 HTTP_BODY_YAML          },
220
221         {  NULL , -1 }
222 };
223
224 /*
225  *      Encoder specific structures.
226  *      @todo split encoders/decoders into submodules.
227  */
228 typedef struct rest_custom_data {
229         char const *p;          //!< how much text we've sent so far.
230 } rest_custom_data_t;
231
232 #ifdef HAVE_JSON
233 /** Flags to control the conversion of JSON values to VALUE_PAIRs.
234  *
235  * These fields are set when parsing the expanded format for value pairs in
236  * JSON, and control how json_pair_make_leaf and json_pair_make convert the JSON
237  * value, and move the new VALUE_PAIR into an attribute list.
238  *
239  * @see json_pair_make
240  * @see json_pair_make_leaf
241  */
242 typedef struct json_flags {
243         int do_xlat;            //!< If true value will be expanded with xlat.
244         int is_json;            //!< If true value will be inserted as raw JSON
245                                 // (multiple values not supported).
246         FR_TOKEN op;            //!< The operator that determines how the new VP
247                                 // is processed. @see fr_tokens
248 } json_flags_t;
249 #endif
250
251 /** Initialises libcurl.
252  *
253  * Allocates global variables and memory required for libcurl to function.
254  * MUST only be called once per module instance.
255  *
256  * rest_cleanup must not be called if rest_init fails.
257  *
258  * @see rest_cleanup
259  *
260  * @param[in] instance configuration data.
261  * @return 0 if init succeeded -1 if it failed.
262  */
263 int rest_init(rlm_rest_t *instance)
264 {
265         static bool version_done;
266         CURLcode ret;
267
268         /* developer sanity */
269         rad_assert((sizeof(http_body_type_supported) / sizeof(*http_body_type_supported)) == HTTP_BODY_NUM_ENTRIES);
270
271         ret = curl_global_init(CURL_GLOBAL_ALL);
272         if (ret != CURLE_OK) {
273                 ERROR("rlm_rest (%s): CURL init returned error: %i - %s",
274                       instance->xlat_name,
275                       ret, curl_easy_strerror(ret));
276
277                 curl_global_cleanup();
278                 return -1;
279         }
280
281         if (!version_done) {
282                 curl_version_info_data *curlversion;
283
284                 version_done = true;
285
286                 curlversion = curl_version_info(CURLVERSION_NOW);
287                 if (strcmp(LIBCURL_VERSION, curlversion->version) != 0) {
288                         WARN("rlm_rest: libcurl version changed since the server was built");
289                         WARN("rlm_rest: linked: %s built: %s", curlversion->version, LIBCURL_VERSION);
290                 }
291
292                 INFO("rlm_rest: libcurl version: %s", curl_version());
293         }
294
295         return 0;
296 }
297
298 /** Cleans up after libcurl.
299  *
300  * Wrapper around curl_global_cleanup, frees any memory allocated by rest_init.
301  * Must only be called once per call of rest_init.
302  *
303  * @see rest_init
304  */
305 void rest_cleanup(void)
306 {
307         curl_global_cleanup();
308 }
309
310
311 /** Frees a libcurl handle, and any additional memory used by context data.
312  *
313  * @param[in] randle rlm_rest_handle_t to close and free.
314  * @return returns true.
315  */
316 static int _mod_conn_free(rlm_rest_handle_t *randle)
317 {
318         curl_easy_cleanup(randle->handle);
319
320         return 0;
321 }
322
323 /** Creates a new connection handle for use by the FR connection API.
324  *
325  * Matches the fr_connection_create_t function prototype, is passed to
326  * fr_connection_pool_init, and called when a new connection is required by the
327  * connection pool API.
328  *
329  * Creates an instances of rlm_rest_handle_t, and rlm_rest_curl_context_t
330  * which hold the context data required for generating requests and parsing
331  * responses.
332  *
333  * If instance->connect_uri is not NULL libcurl will attempt to open a
334  * TCP socket to the server specified in the URI. This is done so that when the
335  * socket is first used, there will already be a cached TCP connection to the
336  * REST server associated with the curl handle.
337  *
338  * @see fr_connection_pool_init
339  * @see fr_connection_create_t
340  * @see connection.c
341  */
342 void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
343 {
344         rlm_rest_t *inst = instance;
345
346         rlm_rest_handle_t       *randle = NULL;
347         rlm_rest_curl_context_t *curl_ctx = NULL;
348
349         CURL *candle = curl_easy_init();
350
351         CURLcode ret = CURLE_OK;
352         char const *option = "unknown";
353
354         if (!candle) {
355                 ERROR("rlm_rest (%s): Failed to create CURL handle", inst->xlat_name);
356                 return NULL;
357         }
358
359         SET_OPTION(CURLOPT_CONNECTTIMEOUT_MS, inst->connect_timeout);
360
361         if (inst->connect_uri) {
362                 /*
363                  *  re-establish TCP connection to webserver. This would usually be
364                  *  done on the first request, but we do it here to minimise
365                  *  latency.
366                  */
367                 SET_OPTION(CURLOPT_SSL_VERIFYPEER, 0);
368                 SET_OPTION(CURLOPT_SSL_VERIFYHOST, 0);
369                 SET_OPTION(CURLOPT_CONNECT_ONLY, 1);
370                 SET_OPTION(CURLOPT_URL, inst->connect_uri);
371                 SET_OPTION(CURLOPT_NOSIGNAL, 1);
372
373                 DEBUG("rlm_rest (%s): Connecting to \"%s\"", inst->xlat_name, inst->connect_uri);
374
375                 ret = curl_easy_perform(candle);
376                 if (ret != CURLE_OK) {
377                         ERROR("rlm_rest (%s): Connection failed: %i - %s", inst->xlat_name, ret, curl_easy_strerror(ret));
378
379                         goto connection_error;
380                 }
381         } else {
382                 DEBUG2("rlm_rest (%s): Skipping pre-connect, connect_uri not specified", inst->xlat_name);
383         }
384
385         /*
386          *  Allocate memory for the connection handle abstraction.
387          */
388         randle = talloc_zero(ctx, rlm_rest_handle_t);
389         curl_ctx = talloc_zero(randle, rlm_rest_curl_context_t);
390
391         curl_ctx->headers = NULL; /* CURL needs this to be NULL */
392         curl_ctx->request.instance = inst;
393
394         randle->ctx = curl_ctx;
395         randle->handle = candle;
396         talloc_set_destructor(randle, _mod_conn_free);
397
398         /*
399          *  Clear any previously configured options for the first request.
400          */
401         curl_easy_reset(candle);
402
403         return randle;
404
405         /*
406          *  Cleanup for error conditions.
407          */
408 error:
409         ERROR("rlm_rest (%s): Failed setting curl option %s: %s (%i)", inst->xlat_name, option,
410               curl_easy_strerror(ret), ret);
411
412         /*
413          *  So we don't leak CURL handles.
414          */
415 connection_error:
416         curl_easy_cleanup(candle);
417         if (randle) talloc_free(randle);
418
419         return NULL;
420 }
421
422 /** Verifies that the last TCP socket associated with a handle is still active.
423  *
424  * Quieries libcurl to try and determine if the TCP socket associated with a
425  * connection handle is still viable.
426  *
427  * @param[in] instance configuration data.
428  * @param[in] handle to check.
429  * @returns false if the last socket is dead, or if the socket state couldn't be
430  *      determined, else true.
431  */
432 int mod_conn_alive(void *instance, void *handle)
433 {
434         rlm_rest_t              *inst = instance;
435         rlm_rest_handle_t       *randle = handle;
436         CURL                    *candle = randle->handle;
437
438         long last_socket;
439         CURLcode ret;
440
441         ret = curl_easy_getinfo(candle, CURLINFO_LASTSOCKET, &last_socket);
442         if (ret != CURLE_OK) {
443                 ERROR("rlm_rest (%s): Couldn't determine socket state: %i - %s", inst->xlat_name, ret,
444                       curl_easy_strerror(ret));
445
446                 return false;
447         }
448
449         if (last_socket == -1) {
450                 return false;
451         }
452
453         return true;
454 }
455
456 /** Copies a pre-expanded xlat string to the output buffer
457  *
458  * @param[out] out Char buffer to write encoded data to.
459  * @param[in] size Multiply by nmemb to get the length of ptr.
460  * @param[in] nmemb Multiply by size to get the length of ptr.
461  * @param[in] userdata rlm_rest_request_t to keep encoding state between calls.
462  * @return length of data (including NULL) written to ptr, or 0 if no more
463  *      data to write.
464  */
465 static size_t rest_encode_custom(void *out, size_t size, size_t nmemb, void *userdata)
466 {
467         rlm_rest_request_t *ctx = userdata;
468         rest_custom_data_t *data = ctx->encoder;
469
470         size_t  freespace = (size * nmemb) - 1;
471         size_t  len;
472
473         len = strlcpy(out, data->p, freespace);
474         if (is_truncated(len, freespace)) {
475                 data->p += (freespace - 1);
476                 return freespace - 1;
477         }
478         data->p += len;
479
480         return len;
481 }
482
483 /** Encodes VALUE_PAIR linked list in POST format
484  *
485  * This is a stream function matching the rest_read_t prototype. Multiple
486  * successive calls will return additional encoded VALUE_PAIRs.
487  * Only complete attribute headers @verbatim '<name>=' @endverbatim and values
488  * will be written to the ptr buffer.
489  *
490  * POST request format is:
491  * @verbatim <attribute0>=<value0>&<attribute1>=<value1>&<attributeN>=<valueN>@endverbatim
492  *
493  * All attributes and values are url encoded. There is currently no support for
494  * nested attributes, or attribute qualifiers.
495  *
496  * Nested attributes may be added in the future using
497  * @verbatim <attribute-outer>:<attribute-inner>@endverbatim
498  * to denotate nesting.
499  *
500  * Requires libcurl for url encoding.
501  *
502  * @see rest_decode_post
503  *
504  * @param[out] out Char buffer to write encoded data to.
505  * @param[in] size Multiply by nmemb to get the length of ptr.
506  * @param[in] nmemb Multiply by size to get the length of ptr.
507  * @param[in] userdata rlm_rest_request_t to keep encoding state between calls.
508  * @return length of data (including NULL) written to ptr, or 0 if no more
509  *      data to write.
510  */
511 static size_t rest_encode_post(void *out, size_t size, size_t nmemb, void *userdata)
512 {
513         rlm_rest_request_t      *ctx = userdata;
514         REQUEST                 *request = ctx->request; /* Used by RDEBUG */
515         VALUE_PAIR              *vp;
516
517         char *p = out;          /* Position in buffer */
518         char *encoded = p;      /* Position in buffer of last fully encoded attribute or value */
519         char *escaped;          /* Pointer to current URL escaped data */
520
521         size_t len = 0;
522         size_t freespace = (size * nmemb) - 1;
523
524         /* Allow manual chunking */
525         if ((ctx->chunk) && (ctx->chunk <= freespace)) {
526                 freespace = (ctx->chunk - 1);
527         }
528
529         if (ctx->state == READ_STATE_END) return 0;
530
531         /* Post data requires no headers */
532         if (ctx->state == READ_STATE_INIT) ctx->state = READ_STATE_ATTR_BEGIN;
533
534         while (freespace > 0) {
535                 vp = fr_cursor_current(&ctx->cursor);
536                 if (!vp) {
537                         ctx->state = READ_STATE_END;
538
539                         break;
540                 }
541
542                 RDEBUG2("Encoding attribute \"%s\"", vp->da->name);
543
544                 if (ctx->state == READ_STATE_ATTR_BEGIN) {
545                         escaped = curl_escape(vp->da->name, strlen(vp->da->name));
546                         if (!escaped) {
547                                 REDEBUG("Failed escaping string \"%s\"", vp->da->name);
548                                 return 0;
549                         }
550
551                         len = strlen(escaped);
552                         if (freespace < (1 + len)) {
553                                 curl_free(escaped);
554                                 goto no_space;
555                         }
556
557                         len = sprintf(p, "%s=", escaped);
558                         curl_free(escaped);
559                         p += len;
560                         freespace -= len;
561
562                         /*
563                          *  We wrote the attribute header, record progress.
564                          */
565                         encoded = p;
566                         ctx->state = READ_STATE_ATTR_CONT;
567                 }
568
569                 /*
570                  *  Write out single attribute string.
571                  */
572                 len = vp_prints_value(p, freespace, vp, 0);
573                 if (is_truncated(len, freespace)) goto no_space;
574
575                 RINDENT();
576                 RDEBUG3("Length : %zd", len);
577                 REXDENT();
578                 if (len > 0) {
579                         escaped = curl_escape(p, len);
580                         if (!escaped) {
581                                 REDEBUG("Failed escaping string \"%s\"", vp->da->name);
582                                 return 0;
583                         }
584                         len = strlen(escaped);
585
586                         if (freespace < len) {
587                                 curl_free(escaped);
588                                 goto no_space;
589                         }
590
591                         len = strlcpy(p, escaped, len + 1);
592
593                         curl_free(escaped);
594
595                         RINDENT();
596                         RDEBUG3("Value  : %s", p);
597                         REXDENT();
598
599                         p += len;
600                         freespace -= len;
601                 }
602
603                 /*
604                  *  there are more attributes, insert a separator
605                  */
606                 if (fr_cursor_next(&ctx->cursor)) {
607                         if (freespace < 1) goto no_space;
608                         *p++ = '&';
609                         freespace--;
610                 }
611
612                 /*
613                  *  We wrote one full attribute value pair, record progress.
614                  */
615                 encoded = p;
616
617                 ctx->state = READ_STATE_ATTR_BEGIN;
618         }
619
620         *p = '\0';
621
622         len = p - (char *)out;
623
624         RDEBUG3("POST Data: %s", (char *)out);
625         RDEBUG3("Returning %zd bytes of POST data", len);
626
627         return len;
628
629         /*
630          *  Cleanup for error conditions
631          */
632 no_space:
633         *encoded = '\0';
634
635         len = encoded - (char *)out;
636
637         RDEBUG3("POST Data: %s", (char *)out);
638
639         /*
640          *  The buffer wasn't big enough to encode a single attribute chunk.
641          */
642         if (len == 0) {
643                 REDEBUG("Failed encoding attribute");
644         } else {
645                 RDEBUG3("Returning %zd bytes of POST data (buffer full or chunk exceeded)", len);
646         }
647
648         return len;
649 }
650
651 #ifdef HAVE_JSON
652 /** Encodes VALUE_PAIR linked list in JSON format
653  *
654  * This is a stream function matching the rest_read_t prototype. Multiple
655  * successive calls will return additional encoded VALUE_PAIRs.
656  *
657  * Only complete attribute headers
658  * @verbatim "<name>":{"type":"<type>","value":[' @endverbatim
659  * and complete attribute values will be written to ptr.
660  *
661  * If an attribute occurs multiple times in the request the attribute values
662  * will be concatenated into a single value array.
663  *
664  * JSON request format is:
665 @verbatim
666 {
667         "<attribute0>":{
668                 "type":"<type0>",
669                 "value":[<value0>,<value1>,<valueN>]
670         },
671         "<attribute1>":{
672                 "type":"<type1>",
673                 "value":[...]
674         },
675         "<attributeN>":{
676                 "type":"<typeN>",
677                 "value":[...]
678         },
679 }
680 @endverbatim
681  *
682  * @param[out] out Char buffer to write encoded data to.
683  * @param[in] size Multiply by nmemb to get the length of ptr.
684  * @param[in] nmemb Multiply by size to get the length of ptr.
685  * @param[in] userdata rlm_rest_request_t to keep encoding state between calls.
686  * @return length of data (including NULL) written to ptr, or 0 if no more
687  *      data to write.
688  */
689 static size_t rest_encode_json(void *out, size_t size, size_t nmemb, void *userdata)
690 {
691         rlm_rest_request_t      *ctx = userdata;
692         REQUEST                 *request = ctx->request; /* Used by RDEBUG */
693         VALUE_PAIR              *vp, *next;
694
695         char *p = out;          /* Position in buffer */
696         char *encoded = p;      /* Position in buffer of last fully encoded attribute or value */
697
698         char const *type;
699
700         size_t len = 0;
701         size_t freespace = (size * nmemb) - 1;          /* account for the \0 byte here */
702
703         rad_assert(freespace > 0);
704
705         /* Allow manual chunking */
706         if ((ctx->chunk) && (ctx->chunk <= freespace)) {
707                 freespace = (ctx->chunk - 1);
708         }
709
710         if (ctx->state == READ_STATE_END) return 0;
711
712         if (ctx->state == READ_STATE_INIT) {
713                 ctx->state = READ_STATE_ATTR_BEGIN;
714
715                 if (freespace < 1) goto no_space;
716                 *p++ = '{';
717                 freespace--;
718         }
719
720         for (;;) {
721                 vp = fr_cursor_current(&ctx->cursor);
722
723                 /*
724                  *  We've encoded all the VPs
725                  *
726                  *  The check for READ_STATE_ATTR_BEGIN is needed as we might be in
727                  *  READ_STATE_ATTR_END, and need to close out the current attribute
728                  *  array.
729                  */
730                 if (!vp && (ctx->state == READ_STATE_ATTR_BEGIN)) {
731                         if (freespace < 1) goto no_space;
732                         *p++ = '}';
733                         freespace--;
734
735                         ctx->state = READ_STATE_END;
736
737                         break;
738                 }
739
740                 if (ctx->state == READ_STATE_ATTR_BEGIN) {
741                         /*
742                          *  New attribute, write name, type, and beginning of value array.
743                          */
744                         RDEBUG2("Encoding attribute \"%s\"", vp->da->name);
745
746                         type = fr_int2str(dict_attr_types, vp->da->type, "<INVALID>");
747
748                         len = snprintf(p, freespace + 1, "\"%s\":{\"type\":\"%s\",\"value\":[", vp->da->name, type);
749                         if (len >= freespace) goto no_space;
750                         p += len;
751                         freespace -= len;
752
753                         RINDENT();
754                         RDEBUG3("Type   : %s", type);
755                         REXDENT();
756                         /*
757                          *  We wrote the attribute header, record progress
758                          */
759                         encoded = p;
760                         ctx->state = READ_STATE_ATTR_CONT;
761                 }
762
763                 if (ctx->state == READ_STATE_ATTR_CONT) {
764                         for (;;) {
765                                 size_t attr_space;
766
767                                 rad_assert(vp); /* coverity */
768
769                                 /*
770                                  *  We need at least a single byte to write out the
771                                  *  shortest attribute value.
772                                  */
773                                 if (freespace < 1) goto no_space;
774
775                                 /*
776                                  *  Code below expects length of the buffer, so we
777                                  *  add +1 to freespace.
778                                  *
779                                  *  If we know we need a comma after the value, we
780                                  *  need to -1 to make sure we have enough room to
781                                  *  write that out.
782                                  */
783                                 attr_space = fr_cursor_next_peek(&ctx->cursor) ? freespace - 1 : freespace;
784                                 len = vp_prints_value_json(p, attr_space + 1, vp);
785                                 if (is_truncated(len, attr_space + 1)) goto no_space;
786
787                                 /*
788                                  *  Show actual value length minus quotes
789                                  */
790                                 RINDENT();
791                                 RDEBUG3("Length : %zu", (size_t) (*p == '"') ? (len - 2) : len);
792                                 RDEBUG3("Value  : %s", p);
793                                 REXDENT();
794
795                                 p += len;
796                                 freespace -= len;
797                                 encoded = p;
798
799                                 /*
800                                  *  Multivalued attribute, we sorted all the attributes earlier, so multiple
801                                  *  instances should occur in a contiguous block.
802                                  */
803                                 if ((next = fr_cursor_next(&ctx->cursor)) && (vp->da == next->da)) {
804                                         rad_assert(freespace >= 1);
805                                         *p++ = ',';
806                                         freespace--;
807
808                                         /*
809                                          *  We wrote one attribute value, record progress.
810                                          */
811                                         encoded = p;
812                                         vp = next;
813                                         continue;
814                                 }
815                                 break;
816                         }
817                         ctx->state = READ_STATE_ATTR_END;
818                 }
819
820                 if (ctx->state == READ_STATE_ATTR_END) {
821                         next = fr_cursor_current(&ctx->cursor);
822                         if (freespace < 2) goto no_space;
823                         *p++ = ']';
824                         *p++ = '}';
825                         freespace -= 2;
826
827                         if (next) {
828                                 if (freespace < 1) goto no_space;
829                                 *p++ = ',';
830                                 freespace--;
831                         }
832
833                         /*
834                          *  We wrote one full attribute value pair, record progress.
835                          */
836                         encoded = p;
837                         ctx->state = READ_STATE_ATTR_BEGIN;
838                 }
839         }
840
841         *p = '\0';
842
843         len = p - (char *)out;
844
845         RDEBUG3("JSON Data: %s", (char *)out);
846         RDEBUG3("Returning %zd bytes of JSON data", len);
847
848         return len;
849
850         /*
851          *  Were out of buffer space
852          */
853 no_space:
854         *encoded = '\0';
855
856         len = encoded - (char *)out;
857
858         RDEBUG3("JSON Data: %s", (char *)out);
859
860         /*
861          *  The buffer wasn't big enough to encode a single attribute chunk.
862          */
863         if (len == 0) {
864                 REDEBUG("AVP exceeds buffer length or chunk");
865         } else {
866                 RDEBUG2("Returning %zd bytes of JSON data (buffer full or chunk exceeded)", len);
867         }
868
869         return len;
870 }
871 #endif
872
873 /** Emulates successive libcurl calls to an encoding function
874  *
875  * This function is used when the request will be sent to the HTTP server as one
876  * contiguous entity. A buffer of REST_BODY_INIT bytes is allocated and passed
877  * to the stream encoding function.
878  *
879  * If the stream function does not return 0, a new buffer is allocated which is
880  * the size of the previous buffer + REST_BODY_INIT bytes, the data from the
881  * previous buffer is copied, and freed, and another call is made to the stream
882  * function, passing a pointer into the new buffer at the end of the previously
883  * written data.
884  *
885  * This process continues until the stream function signals (by returning 0)
886  * that it has no more data to write.
887  *
888  * @param[out] buffer where the pointer to the alloced buffer should
889  *      be written.
890  * @param[in] func Stream function.
891  * @param[in] limit Maximum buffer size to alloc.
892  * @param[in] userdata rlm_rest_request_t to keep encoding state between calls to
893  *      stream function.
894  * @return the length of the data written to the buffer (excluding NULL) or -1
895  *      if alloc >= limit.
896  */
897 static ssize_t rest_request_encode_wrapper(char **buffer, rest_read_t func, size_t limit, void *userdata)
898 {
899         char *previous = NULL;
900         char *current = NULL;
901
902         size_t alloc = REST_BODY_INIT;  /* Size of buffer to alloc */
903         size_t used = 0;                /* Size of data written */
904         size_t len = 0;
905
906         while (alloc <= limit) {
907                 current = rad_malloc(alloc);
908
909                 if (previous) {
910                         strlcpy(current, previous, used + 1);
911                         free(previous);
912                 }
913
914                 len = func(current + used, alloc - used, 1, userdata);
915                 used += len;
916                 if (!len) {
917                         *buffer = current;
918                         return used;
919                 }
920
921                 alloc = alloc * 2;
922                 previous = current;
923         };
924
925         free(current);
926
927         return -1;
928 }
929
930 /** (Re-)Initialises the data in a rlm_rest_request_t.
931  *
932  * Resets the values of a rlm_rest_request_t to their defaults.
933  *
934  * @param[in] request Current request.
935  * @param[in] ctx to initialise.
936  * @param[in] sort If true VALUE_PAIRs will be sorted within the VALUE_PAIR
937  *      pointer array.
938  */
939 static void rest_request_init(REQUEST *request, rlm_rest_request_t *ctx, bool sort)
940 {
941         /*
942          *      Setup stream read data
943          */
944         ctx->request = request;
945         ctx->state = READ_STATE_INIT;
946
947         /*
948          *      Sorts pairs in place, oh well...
949          */
950         if (sort) {
951                 fr_pair_list_sort(&request->packet->vps, fr_pair_cmp_by_da_tag);
952         }
953         fr_cursor_init(&ctx->cursor, &request->packet->vps);
954 }
955
956 /** Converts plain response into a single VALUE_PAIR
957  *
958  * @param[in] instance configuration data.
959  * @param[in] section configuration data.
960  * @param[in] handle rlm_rest_handle_t to use.
961  * @param[in] request Current request.
962  * @param[in] raw buffer containing POST data.
963  * @param[in] rawlen Length of data in raw buffer.
964  * @return the number of VALUE_PAIRs processed or -1 on unrecoverable error.
965  */
966 static int rest_decode_plain(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
967                              REQUEST *request, UNUSED void *handle, char *raw, size_t rawlen)
968 {
969         VALUE_PAIR *vp;
970
971         /*
972          *  Empty response?
973          */
974         if (*raw == '\0') return 0;
975
976         /*
977          *  Use rawlen to protect against overrun, and to cope with any binary data
978          */
979         vp = pair_make_reply("REST-HTTP-Body", NULL, T_OP_ADD);
980         fr_pair_value_bstrncpy(vp, raw, rawlen);
981
982         RDEBUG2("Adding reply:REST-HTTP-Body += \"%s\"", vp->vp_strvalue);
983
984         return 1;
985 }
986
987 /** Converts POST response into VALUE_PAIRs and adds them to the request
988  *
989  * Accepts VALUE_PAIRS in the same format as rest_encode_post, but with the
990  * addition of optional attribute list qualifiers as part of the attribute name
991  * string.
992  *
993  * If no qualifiers are specified, will default to the request list.
994  *
995  * POST response format is:
996  * @verbatim [outer.][<list>:]<attribute0>=<value0>&[outer.][<list>:]<attribute1>=<value1>&[outer.][<list>:]<attributeN>=<valueN> @endverbatim
997  *
998  * @see rest_encode_post
999  *
1000  * @param[in] instance configuration data.
1001  * @param[in] section configuration data.
1002  * @param[in] handle rlm_rest_handle_t to use.
1003  * @param[in] request Current request.
1004  * @param[in] raw buffer containing POST data.
1005  * @param[in] rawlen Length of data in raw buffer.
1006  * @return the number of VALUE_PAIRs processed or -1 on unrecoverable error.
1007  */
1008 static int rest_decode_post(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
1009                             REQUEST *request, void *handle, char *raw, size_t rawlen)
1010 {
1011         rlm_rest_handle_t       *randle = handle;
1012         CURL                    *candle = randle->handle;
1013
1014         char const *p = raw, *q;
1015
1016         char const *attribute;
1017         char *name  = NULL;
1018         char *value = NULL;
1019
1020         char *expanded = NULL;
1021
1022         DICT_ATTR const *da;
1023         VALUE_PAIR *vp;
1024
1025         pair_lists_t list_name;
1026         request_refs_t request_name;
1027         REQUEST *reference = request;
1028         VALUE_PAIR **vps;
1029         TALLOC_CTX *ctx;
1030
1031         size_t len;
1032         int curl_len; /* Length from last curl_easy_unescape call */
1033
1034         int count = 0;
1035         int ret;
1036
1037         /*
1038          *      Empty response?
1039          */
1040         while (isspace(*p)) p++;
1041         if (*p == '\0') return 0;
1042
1043         while (((q = strchr(p, '=')) != NULL) && (count < REST_BODY_MAX_ATTRS)) {
1044                 reference = request;
1045
1046                 name = curl_easy_unescape(candle, p, (q - p), &curl_len);
1047                 p = (q + 1);
1048
1049                 RDEBUG2("Parsing attribute \"%s\"", name);
1050
1051                 /*
1052                  *  The attribute pointer is updated to point to the portion of
1053                  *  the string after the list qualifier.
1054                  */
1055                 attribute = name;
1056                 attribute += radius_request_name(&request_name, attribute, REQUEST_CURRENT);
1057                 if (request_name == REQUEST_UNKNOWN) {
1058                         RWDEBUG("Invalid request qualifier, skipping");
1059
1060                         curl_free(name);
1061
1062                         continue;
1063                 }
1064
1065                 if (radius_request(&reference, request_name) < 0) {
1066                         RWDEBUG("Attribute name refers to outer request but not in a tunnel, skipping");
1067
1068                         curl_free(name);
1069
1070                         continue;
1071                 }
1072
1073                 attribute += radius_list_name(&list_name, attribute, PAIR_LIST_REPLY);
1074                 if (list_name == PAIR_LIST_UNKNOWN) {
1075                         RWDEBUG("Invalid list qualifier, skipping");
1076                         curl_free(name);
1077
1078                         continue;
1079                 }
1080
1081                 da = dict_attrbyname(attribute);
1082                 if (!da) {
1083                         RWDEBUG("Attribute \"%s\" unknown, skipping", attribute);
1084
1085                         curl_free(name);
1086
1087                         continue;
1088                 }
1089
1090                 vps = radius_list(reference, list_name);
1091                 rad_assert(vps);
1092
1093                 RINDENT();
1094                 RDEBUG3("Type  : %s", fr_int2str(dict_attr_types, da->type, "<INVALID>"));
1095
1096                 ctx = radius_list_ctx(reference, list_name);
1097
1098                 q = strchr(p, '&');
1099                 len = (!q) ? (rawlen - (p - raw)) : (unsigned)(q - p);
1100
1101                 value = curl_easy_unescape(candle, p, len, &curl_len);
1102
1103                 /*
1104                  *  If we found a delimiter we want to skip over it,
1105                  *  if we didn't we do *NOT* want to skip over the end
1106                  *  of the buffer...
1107                  */
1108                 p += (!q) ? len : (len + 1);
1109
1110                 RDEBUG3("Length : %i", curl_len);
1111                 RDEBUG3("Value  : \"%s\"", value);
1112                 REXDENT();
1113
1114                 RDEBUG2("Performing xlat expansion of response value");
1115
1116                 if (radius_axlat(&expanded, request, value, NULL, NULL) < 0) {
1117                         goto skip;
1118                 }
1119
1120                 vp = fr_pair_afrom_da(ctx, da);
1121                 if (!vp) {
1122                         REDEBUG("Failed creating valuepair");
1123                         talloc_free(expanded);
1124
1125                         goto error;
1126                 }
1127
1128                 ret = fr_pair_value_from_str(vp, expanded, -1);
1129                 TALLOC_FREE(expanded);
1130                 if (ret < 0) {
1131                         RWDEBUG("Incompatible value assignment, skipping");
1132                         talloc_free(vp);
1133                         goto skip;
1134                 }
1135
1136                 fr_pair_add(vps, vp);
1137
1138                 count++;
1139
1140         skip:
1141                 curl_free(name);
1142                 curl_free(value);
1143
1144                 continue;
1145
1146         error:
1147                 curl_free(name);
1148                 curl_free(value);
1149
1150                 return count;
1151         }
1152
1153         if (!count) {
1154                 REDEBUG("Malformed POST data \"%s\"", raw);
1155         }
1156
1157         return count;
1158
1159 }
1160
1161 #ifdef HAVE_JSON
1162 /** Converts JSON "value" key into VALUE_PAIR.
1163  *
1164  * If leaf is not in fact a leaf node, but contains JSON data, the data will
1165  * written to the attribute in JSON string format.
1166  *
1167  * @param[in] instance configuration data.
1168  * @param[in] section configuration data.
1169  * @param[in] ctx to allocate new VALUE_PAIRs in.
1170  * @param[in] request Current request.
1171  * @param[in] da Attribute to create.
1172  * @param[in] flags containing the operator other flags controlling value
1173  *      expansion.
1174  * @param[in] leaf object containing the VALUE_PAIR value.
1175  * @return The VALUE_PAIR just created, or NULL on error.
1176  */
1177 static VALUE_PAIR *json_pair_make_leaf(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
1178                                       TALLOC_CTX *ctx, REQUEST *request, DICT_ATTR const *da,
1179                                       json_flags_t *flags, json_object *leaf)
1180 {
1181         char const *value, *to_parse;
1182         char *expanded = NULL;
1183         int ret;
1184
1185         VALUE_PAIR *vp;
1186
1187         if (json_object_is_type(leaf, json_type_null)) {
1188                 RDEBUG3("Got null value for attribute \"%s\", skipping...", da->name);
1189
1190                 return NULL;
1191         }
1192
1193         /*
1194          *      Should encode any nested JSON structures into JSON strings.
1195          *
1196          *      "I knew you liked JSON so I put JSON in your JSON!"
1197          */
1198         value = json_object_get_string(leaf);
1199         if (!value) {
1200                 RWDEBUG("Failed getting string value for attribute \"%s\", skipping...", da->name);
1201
1202                 return NULL;
1203         }
1204
1205         RINDENT();
1206         RDEBUG3("Type   : %s", fr_int2str(dict_attr_types, da->type, "<INVALID>"));
1207         RDEBUG3("Length : %zu", strlen(value));
1208         RDEBUG3("Value  : \"%s\"", value);
1209         REXDENT();
1210
1211         if (flags->do_xlat) {
1212                 if (radius_axlat(&expanded, request, value, NULL, NULL) < 0) {
1213                         return NULL;
1214                 }
1215
1216                 to_parse = expanded;
1217         } else {
1218                 to_parse = value;
1219         }
1220
1221         vp = fr_pair_afrom_da(ctx, da);
1222         if (!vp) {
1223                 RWDEBUG("Failed creating valuepair for attribute \"%s\", skipping...", da->name);
1224                 talloc_free(expanded);
1225
1226                 return NULL;
1227         }
1228
1229         vp->op = flags->op;
1230
1231         ret = fr_pair_value_from_str(vp, to_parse, -1);
1232         talloc_free(expanded);
1233         if (ret < 0) {
1234                 RWDEBUG("Incompatible value assignment for attribute \"%s\", skipping...", da->name);
1235                 talloc_free(vp);
1236
1237                 return NULL;
1238         }
1239
1240         return vp;
1241 }
1242
1243 /** Processes JSON response and converts it into multiple VALUE_PAIRs
1244  *
1245  * Processes JSON attribute declarations in the format below. Will recurse when
1246  * processing nested attributes. When processing nested attributes flags and
1247  * operators from previous attributes are not inherited.
1248  *
1249  * JSON response format is:
1250 @verbatim
1251 {
1252         "<attribute0>":{
1253                 "do_xlat":<bool>,
1254                 "is_json":<bool>,
1255                 "op":"<operator>",
1256                 "value":[<value0>,<value1>,<valueN>]
1257         },
1258         "<attribute1>":{
1259                 "value":{
1260                         "<nested-attribute0>":{
1261                                 "op":"<operator>",
1262                                 "value":<value0>
1263                         }
1264                 }
1265         },
1266         "<attribute2>":"<value0>",
1267         "<attributeN>":[<value0>,<value1>,<valueN>]
1268 }
1269 @endverbatim
1270  *
1271  * JSON valuepair flags:
1272  *  - do_xlat   (optional) Controls xlat expansion of values. Defaults to true.
1273  *  - is_json   (optional) If true, any nested JSON data will be copied to the
1274  *                         VALUE_PAIR in string form. Defaults to true.
1275  *  - op        (optional) Controls how the attribute is inserted into
1276  *                         the target list. Defaults to ':=' (T_OP_SET).
1277  *
1278  * If "op" is ':=' or '=', it will be automagically changed to '+=' for the
1279  * second and subsequent values in multivalued attributes. This does not work
1280  * between multiple attribute declarations.
1281  *
1282  * @see fr_tokens
1283  *
1284  * @param[in] instance configuration data.
1285  * @param[in] section configuration data.
1286  * @param[in] request Current request.
1287  * @param[in] object containing root node, or parent node.
1288  * @param[in] level Current nesting level.
1289  * @param[in] max counter, decremented after each VALUE_PAIR is created,
1290  *            when 0 no more attributes will be processed.
1291  * @return number of attributes created or < 0 on error.
1292  */
1293 static int json_pair_make(rlm_rest_t *instance, rlm_rest_section_t *section,
1294                          REQUEST *request, json_object *object, UNUSED int level, int max)
1295 {
1296         struct lh_entry *entry;
1297         int max_attrs = max;
1298
1299         if (!json_object_is_type(object, json_type_object)) {
1300 #ifdef HAVE_JSON_TYPE_TO_NAME
1301                 REDEBUG("Can't process VP container, expected JSON object"
1302                         "got \"%s\", skipping...",
1303                         json_type_to_name(json_object_get_type(object)));
1304 #else
1305                 REDEBUG("Can't process VP container, expected JSON object"
1306                         ", skipping...");
1307 #endif
1308                 return -1;
1309         }
1310
1311         /*
1312          *      Process VP container
1313          */
1314         for (entry = json_object_get_object(object)->head;
1315              entry;
1316              entry = entry->next) {
1317                 int i = 0, elements;
1318                 struct json_object *value, *element, *tmp;
1319                 TALLOC_CTX *ctx;
1320
1321                 char const *name = (char const *)entry->k;
1322
1323                 json_flags_t flags = {
1324                         .op = T_OP_SET,
1325                         .do_xlat = 1,
1326                         .is_json = 0
1327                 };
1328
1329                 vp_tmpl_t dst;
1330                 REQUEST *current = request;
1331                 VALUE_PAIR **vps, *vp = NULL;
1332
1333                 memset(&dst, 0, sizeof(dst));
1334
1335                 /* Fix the compiler warnings regarding const... */
1336                 memcpy(&value, &entry->v, sizeof(value));
1337
1338                 /*
1339                  *  Resolve attribute name to a dictionary entry and pairlist.
1340                  */
1341                 RDEBUG2("Parsing attribute \"%s\"", name);
1342
1343                 if (tmpl_from_attr_str(&dst, name, REQUEST_CURRENT, PAIR_LIST_REPLY, false, false) <= 0) {
1344                         RWDEBUG("Failed parsing attribute: %s, skipping...", fr_strerror());
1345                         continue;
1346                 }
1347
1348                 if (radius_request(&current, dst.tmpl_request) < 0) {
1349                         RWDEBUG("Attribute name refers to outer request but not in a tunnel, skipping...");
1350                         continue;
1351                 }
1352
1353                 vps = radius_list(current, dst.tmpl_list);
1354                 if (!vps) {
1355                         RWDEBUG("List not valid in this context, skipping...");
1356                         continue;
1357                 }
1358                 ctx = radius_list_ctx(current, dst.tmpl_list);
1359
1360                 /*
1361                  *  Alternative JSON structure which allows operator,
1362                  *  and other flags to be specified.
1363                  *
1364                  *      "<name>":{
1365                  *              "do_xlat":<bool>,
1366                  *              "is_json":<bool>,
1367                  *              "op":"<op>",
1368                  *              "value":<value>
1369                  *      }
1370                  *
1371                  *      Where value is a:
1372                  *        - []  Multivalued array
1373                  *        - {}  Nested Valuepair
1374                  *        - *   Integer or string value
1375                  */
1376                 if (json_object_is_type(value, json_type_object)) {
1377                         /*
1378                          *  Process operator if present.
1379                          */
1380                         if (json_object_object_get_ex(value, "op", &tmp)) {
1381                                 flags.op = fr_str2int(fr_tokens, json_object_get_string(tmp), 0);
1382                                 if (!flags.op) {
1383                                         RWDEBUG("Invalid operator value \"%s\", skipping...",
1384                                                 json_object_get_string(tmp));
1385                                         continue;
1386                                 }
1387                         }
1388
1389                         /*
1390                          *  Process optional do_xlat bool.
1391                          */
1392                         if (json_object_object_get_ex(value, "do_xlat", &tmp)) {
1393                                 flags.do_xlat = json_object_get_boolean(tmp);
1394                         }
1395
1396                         /*
1397                          *  Process optional is_json bool.
1398                          */
1399                         if (json_object_object_get_ex(value, "is_json", &tmp)) {
1400                                 flags.is_json = json_object_get_boolean(tmp);
1401                         }
1402
1403                         /*
1404                          *  Value key must be present if were using the expanded syntax.
1405                          */
1406                         if (!json_object_object_get_ex(value, "value", &value)) {
1407                                 RWDEBUG("Value key missing, skipping...");
1408                                 continue;
1409                         }
1410                 }
1411
1412                 /*
1413                  *  Setup fr_pair_make / recursion loop.
1414                  */
1415                 if (!flags.is_json && json_object_is_type(value, json_type_array)) {
1416                         elements = json_object_array_length(value);
1417                         if (!elements) {
1418                                 RWDEBUG("Zero length value array, skipping...");
1419                                 continue;
1420                         }
1421                         element = json_object_array_get_idx(value, 0);
1422                 } else {
1423                         elements = 1;
1424                         element = value;
1425                 }
1426
1427                 /*
1428                  *  A JSON 'value' key, may have multiple elements, iterate
1429                  *  over each of them, creating a new VALUE_PAIR.
1430                  */
1431                 do {
1432                         if (max_attrs-- <= 0) {
1433                                 RWDEBUG("At maximum attribute limit");
1434                                 return max;
1435                         }
1436
1437                         /*
1438                          *  Automagically switch the op for multivalued attributes.
1439                          */
1440                         if (((flags.op == T_OP_SET) || (flags.op == T_OP_EQ)) && (i >= 1)) {
1441                                 flags.op = T_OP_ADD;
1442                         }
1443
1444                         if (json_object_is_type(element, json_type_object) && !flags.is_json) {
1445                                 /* TODO: Insert nested VP into VP structure...*/
1446                                 RWDEBUG("Found nested VP, these are not yet supported, skipping...");
1447
1448                                 continue;
1449
1450                                 /*
1451                                 vp = json_pair_make(instance, section,
1452                                                    request, value,
1453                                                    level + 1, max_attrs);*/
1454                         } else {
1455                                 vp = json_pair_make_leaf(instance, section, ctx, request,
1456                                                         dst.tmpl_da, &flags, element);
1457                                 if (!vp) continue;
1458                         }
1459                         rdebug_pair(2, request, vp, NULL);
1460                         radius_pairmove(current, vps, vp, false);
1461                 /*
1462                  *  If we call json_object_array_get_idx on something that's not an array
1463                  *  the behaviour appears to be to occasionally segfault.
1464                  */
1465                 } while ((++i < elements) && (element = json_object_array_get_idx(value, i)));
1466         }
1467
1468         return max - max_attrs;
1469 }
1470
1471 /** Converts JSON response into VALUE_PAIRs and adds them to the request.
1472  *
1473  * Converts the raw JSON string into a json-c object tree and passes it to
1474  * json_pair_make. After the tree has been parsed json_object_put is called
1475  * which decrements the reference count of the root node by one, and frees
1476  * the entire tree.
1477  *
1478  * @see rest_encode_json
1479  * @see json_pair_make
1480  *
1481  * @param[in] instance configuration data.
1482  * @param[in] section configuration data.
1483  * @param[in,out] request Current request.
1484  * @param[in] handle REST handle.
1485  * @param[in] raw buffer containing JSON data.
1486  * @param[in] rawlen Length of data in raw buffer.
1487  * @return the number of VALUE_PAIRs processed or -1 on unrecoverable error.
1488  */
1489 static int rest_decode_json(rlm_rest_t *instance, rlm_rest_section_t *section,
1490                             REQUEST *request, UNUSED void *handle, char *raw, UNUSED size_t rawlen)
1491 {
1492         char const *p = raw;
1493
1494         struct json_object *json;
1495
1496         int ret;
1497
1498         /*
1499          *  Empty response?
1500          */
1501         while (isspace(*p)) p++;
1502         if (*p == '\0') return 0;
1503
1504         json = json_tokener_parse(p);
1505         if (!json) {
1506                 REDEBUG("Malformed JSON data \"%s\"", raw);
1507                 return -1;
1508         }
1509
1510         ret = json_pair_make(instance, section, request, json, 0, REST_BODY_MAX_ATTRS);
1511
1512         /*
1513          *  Decrement reference count for root object, should free entire JSON tree.
1514          */
1515         json_object_put(json);
1516
1517         return ret;
1518 }
1519 #endif
1520
1521 /** Processes incoming HTTP header data from libcurl.
1522  *
1523  * Processes the status line, and Content-Type headers from the incoming HTTP
1524  * response.
1525  *
1526  * Matches prototype for CURLOPT_HEADERFUNCTION, and will be called directly
1527  * by libcurl.
1528  *
1529  * @param[in] in Char buffer where inbound header data is written.
1530  * @param[in] size Multiply by nmemb to get the length of ptr.
1531  * @param[in] nmemb Multiply by size to get the length of ptr.
1532  * @param[in] userdata rlm_rest_response_t to keep parsing state between calls.
1533  * @return Length of data processed, or 0 on error.
1534  */
1535 static size_t rest_response_header(void *in, size_t size, size_t nmemb, void *userdata)
1536 {
1537         rlm_rest_response_t *ctx = userdata;
1538         REQUEST *request = ctx->request; /* Used by RDEBUG */
1539
1540         char const *p = in, *q;
1541
1542         size_t const t = (size * nmemb);
1543         size_t s = t;
1544         size_t len;
1545
1546         http_body_type_t type;
1547
1548         /*
1549          *  Curl seems to throw these (\r\n) in before the next set of headers when
1550          *  looks like it's just a body separator and safe to ignore after we
1551          *  receive a 100 Continue.
1552          */
1553         if (t == 2 && ((p[0] == '\r') && (p[1] == '\n'))) return t;
1554
1555         switch (ctx->state) {
1556         case WRITE_STATE_INIT:
1557                 RDEBUG2("Processing response header");
1558
1559                 /*
1560                  *  HTTP/<version> <reason_code>[ <reason_phrase>]\r\n
1561                  *
1562                  *  "HTTP/1.1 " (8) + "100 " (4) + "\r\n" (2) = 14
1563                  */
1564                 if (s < 14) {
1565                         REDEBUG("Malformed HTTP header: Status line too short");
1566                         goto malformed;
1567                 }
1568                 /*
1569                  *  Check start of header matches...
1570                  */
1571                 if (strncasecmp("HTTP/", p, 5) != 0) {
1572                         REDEBUG("Malformed HTTP header: Missing HTTP version");
1573                         goto malformed;
1574                 }
1575                 p += 5;
1576                 s -= 5;
1577
1578                 /*
1579                  *  Skip the version field, next space should mark start of reason_code.
1580                  */
1581                 q = memchr(p, ' ', s);
1582                 if (!q) {
1583                         RDEBUG("Malformed HTTP header: Missing reason code");
1584                         goto malformed;
1585                 }
1586
1587                 s -= (q - p);
1588                 p  = q;
1589
1590                 /*
1591                  *  Process reason_code.
1592                  *
1593                  *  " 100" (4) + "\r\n" (2) = 6
1594                  */
1595                 if (s < 6) {
1596                         REDEBUG("Malformed HTTP header: Reason code too short");
1597                         goto malformed;
1598                 }
1599                 p++;
1600                 s--;
1601
1602                 /*  Char after reason code must be a space, or \r */
1603                 if (!((p[3] == ' ') || (p[3] == '\r'))) goto malformed;
1604
1605                 ctx->code = atoi(p);
1606
1607                 /*
1608                  *  Process reason_phrase (if present).
1609                  */
1610                 RINDENT();
1611                 if (p[3] == ' ') {
1612                         p += 4;
1613                         s -= 4;
1614
1615                         q = memchr(p, '\r', s);
1616                         if (!q) goto malformed;
1617
1618                         len = (q - p);
1619
1620                         RDEBUG2("Status : %i (%.*s)", ctx->code, (int) len, p);
1621                 } else {
1622                         RDEBUG2("Status : %i", ctx->code);
1623                 }
1624                 REXDENT();
1625
1626                 ctx->state = WRITE_STATE_PARSE_HEADERS;
1627
1628                 break;
1629
1630         case WRITE_STATE_PARSE_HEADERS:
1631                 if ((s >= 14) &&
1632                     (strncasecmp("Content-Type: ", p, 14) == 0)) {
1633                         p += 14;
1634                         s -= 14;
1635
1636                         /*
1637                          *  Check to see if there's a parameter separator.
1638                          */
1639                         q = memchr(p, ';', s);
1640
1641                         /*
1642                          *  If there's not, find the end of this header.
1643                          */
1644                         if (!q) q = memchr(p, '\r', s);
1645
1646                         len = !q ? s : (size_t) (q - p);
1647                         type = fr_substr2int(http_content_type_table, p, HTTP_BODY_UNKNOWN, len);
1648
1649                         RINDENT();
1650                         RDEBUG2("Type   : %s (%.*s)", fr_int2str(http_body_type_table, type, "<INVALID>"),
1651                                 (int) len, p);
1652                         REXDENT();
1653
1654                         /*
1655                          *  Assume the force_to value has already been validated.
1656                          */
1657                         if (ctx->force_to != HTTP_BODY_UNKNOWN) {
1658                                 if (ctx->force_to != ctx->type) {
1659                                         RDEBUG3("Forcing body type to \"%s\"",
1660                                                 fr_int2str(http_body_type_table, ctx->force_to, "<INVALID>"));
1661                                         ctx->type = ctx->force_to;
1662                                 }
1663                         /*
1664                          *  Figure out if the type is supported by one of the decoders.
1665                          */
1666                         } else {
1667                                 ctx->type = http_body_type_supported[type];
1668                                 switch (ctx->type) {
1669                                 case HTTP_BODY_UNKNOWN:
1670                                         RWDEBUG("Couldn't determine type, using the request's type \"%s\".",
1671                                                 fr_int2str(http_body_type_table, type, "<INVALID>"));
1672                                         break;
1673
1674                                 case HTTP_BODY_UNSUPPORTED:
1675                                         REDEBUG("Type \"%s\" is currently unsupported",
1676                                                 fr_int2str(http_body_type_table, type, "<INVALID>"));
1677                                         break;
1678
1679                                 case HTTP_BODY_UNAVAILABLE:
1680                                         REDEBUG("Type \"%s\" is unavailable, please rebuild this module with the required "
1681                                                 "library", fr_int2str(http_body_type_table, type, "<INVALID>"));
1682                                         break;
1683
1684                                 case HTTP_BODY_INVALID:
1685                                         REDEBUG("Type \"%s\" is not a valid web API data markup format",
1686                                                 fr_int2str(http_body_type_table, type, "<INVALID>"));
1687                                         break;
1688
1689                                 /* supported type */
1690                                 default:
1691                                         break;
1692                                 }
1693                         }
1694                 }
1695                 break;
1696
1697         default:
1698                 break;
1699         }
1700
1701         /*
1702          *  If we got a 100 Continue, we need to send additional payload data.
1703          *  reset the state to WRITE_STATE_INIT, so that when were called again
1704          *  we overwrite previous header data with that from the proper header.
1705          */
1706         if (ctx->code == 100) {
1707                 RDEBUG2("Continuing...");
1708                 ctx->state = WRITE_STATE_INIT;
1709         }
1710
1711         return t;
1712
1713 malformed:
1714         {
1715                 char escaped[1024];
1716
1717                 fr_prints(escaped, sizeof(escaped), (char *) in, t, '\0');
1718
1719                 REDEBUG("Received %zu bytes of response data: %s", t, escaped);
1720                 ctx->code = -1;
1721         }
1722
1723         return (t - s);
1724 }
1725
1726 /** Processes incoming HTTP body data from libcurl.
1727  *
1728  * Writes incoming body data to an intermediary buffer for later parsing by
1729  * one of the decode functions.
1730  *
1731  * @param[in] ptr Char buffer where inbound header data is written
1732  * @param[in] size Multiply by nmemb to get the length of ptr.
1733  * @param[in] nmemb Multiply by size to get the length of ptr.
1734  * @param[in] userdata rlm_rest_response_t to keep parsing state between calls.
1735  * @return length of data processed, or 0 on error.
1736  */
1737 static size_t rest_response_body(void *ptr, size_t size, size_t nmemb, void *userdata)
1738 {
1739         rlm_rest_response_t *ctx = userdata;
1740         REQUEST *request = ctx->request; /* Used by RDEBUG */
1741
1742         char const *p = ptr, *q;
1743         char *tmp;
1744
1745         size_t const t = (size * nmemb);
1746
1747         if (t == 0) return 0;
1748
1749         /*
1750          *  Any post processing of headers should go here...
1751          */
1752         if (ctx->state == WRITE_STATE_PARSE_HEADERS) {
1753                 ctx->state = WRITE_STATE_PARSE_CONTENT;
1754         }
1755
1756         switch (ctx->type) {
1757         case HTTP_BODY_UNSUPPORTED:
1758         case HTTP_BODY_UNAVAILABLE:
1759         case HTTP_BODY_INVALID:
1760                 while ((q = memchr(p, '\n', t - (p - (char *)ptr)))) {
1761                         REDEBUG("%.*s", (int) (q - p), p);
1762                         p = q + 1;
1763                 }
1764
1765                 if (*p != '\0') {
1766                         REDEBUG("%.*s", (int)(t - (p - (char *)ptr)), p);
1767                 }
1768
1769                 return t;
1770
1771         case HTTP_BODY_NONE:
1772                 while ((q = memchr(p, '\n', t - (p - (char *)ptr)))) {
1773                         RDEBUG3("%.*s", (int) (q - p), p);
1774                         p = q + 1;
1775                 }
1776
1777                 if (*p != '\0') {
1778                         RDEBUG3("%.*s", (int)(t - (p - (char *)ptr)), p);
1779                 }
1780
1781                 return t;
1782
1783         default:
1784                 if (t > (ctx->alloc - ctx->used)) {
1785                         ctx->alloc += ((t + 1) > REST_BODY_INIT) ? t + 1 : REST_BODY_INIT;
1786
1787                         tmp = ctx->buffer;
1788
1789                         ctx->buffer = rad_malloc(ctx->alloc);
1790
1791                         /* If data has been written previously */
1792                         if (tmp) {
1793                                 strlcpy(ctx->buffer, tmp, (ctx->used + 1));
1794                                 free(tmp);
1795                         }
1796                 }
1797                 strlcpy(ctx->buffer + ctx->used, p, t + 1);
1798                 ctx->used += t;
1799
1800                 break;
1801         }
1802
1803         return t;
1804 }
1805
1806 /** Print out the response text as error lines
1807  *
1808  * @param request The Current request.
1809  * @param handle rlm_rest_handle_t used to execute the previous request.
1810  */
1811 void rest_response_error(REQUEST *request, rlm_rest_handle_t *handle)
1812 {
1813         char const *p, *q;
1814         size_t len;
1815
1816         len = rest_get_handle_data(&p, handle);
1817         if (len == 0) {
1818                 RERROR("Server returned no data");
1819                 return;
1820         }
1821
1822         RERROR("Server returned:");
1823         while ((q = strchr(p, '\n'))) {
1824                 RERROR("%.*s", (int) (q - p), p);
1825                 p = q + 1;
1826         }
1827         if (*p != '\0') RERROR("%s", p);
1828 }
1829
1830 /** (Re-)Initialises the data in a rlm_rest_response_t.
1831  *
1832  * This resets the values of the a rlm_rest_response_t to their defaults.
1833  * Must be called between encoding sessions.
1834  *
1835  * @see rest_response_body
1836  * @see rest_response_header
1837  *
1838  * @param[in] request Current request.
1839  * @param[in] ctx data to initialise.
1840  * @param[in] type Default http_body_type to use when decoding raw data, may be
1841  * overwritten by rest_response_header.
1842  */
1843 static void rest_response_init(REQUEST *request, rlm_rest_response_t *ctx, http_body_type_t type)
1844 {
1845         ctx->request = request;
1846         ctx->type = type;
1847         ctx->state = WRITE_STATE_INIT;
1848         ctx->alloc = 0;
1849         ctx->used = 0;
1850         ctx->buffer = NULL;
1851 }
1852
1853 /** Extracts pointer to buffer containing response data
1854  *
1855  * @param[out] out Where to write the pointer to the buffer.
1856  * @param[in] handle used for the last request.
1857  * @return > 0 if data is available.
1858  */
1859 size_t rest_get_handle_data(char const **out, rlm_rest_handle_t *handle)
1860 {
1861         rlm_rest_curl_context_t *ctx = handle->ctx;
1862
1863         rad_assert(ctx->response.buffer || (!ctx->response.buffer && !ctx->response.used));
1864
1865         *out = ctx->response.buffer;
1866         return ctx->response.used;
1867 }
1868
1869 /** Configures body specific curlopts.
1870  *
1871  * Configures libcurl handle to use either chunked mode, where the request
1872  * data will be sent using multiple HTTP requests, or contiguous mode where
1873  * the request data will be sent in a single HTTP request.
1874  *
1875  * @param[in] instance configuration data.
1876  * @param[in] section configuration data.
1877  * @param[in] request Current request.
1878  * @param[in] handle rlm_rest_handle_t to configure.
1879  * @param[in] func to pass to libcurl for chunked.
1880  *            transfers (NULL if not using chunked mode).
1881  * @return 0 on success -1 on error.
1882  */
1883 static int rest_request_config_body(UNUSED rlm_rest_t *instance, rlm_rest_section_t *section,
1884                                     REQUEST *request, rlm_rest_handle_t *handle, rest_read_t func)
1885 {
1886         rlm_rest_curl_context_t *ctx = handle->ctx;
1887         CURL                    *candle = handle->handle;
1888
1889         CURLcode ret = CURLE_OK;
1890         char const *option = "unknown";
1891
1892         ssize_t len;
1893
1894         /*
1895          *  We were provided with no read function, assume this means
1896          *  no body should be sent.
1897          */
1898         if (!func) {
1899                 SET_OPTION(CURLOPT_POSTFIELDSIZE, 0);
1900                 return 0;
1901         }
1902
1903         /*
1904          *  Chunked transfer encoding means the body will be sent in
1905          *  multiple parts.
1906          */
1907         if (section->chunk > 0) {
1908                 SET_OPTION(CURLOPT_READDATA, &ctx->request);
1909                 SET_OPTION(CURLOPT_READFUNCTION, func);
1910
1911                 return 0;
1912         }
1913
1914         /*
1915          *  If were not doing chunked encoding then we read the entire
1916          *  body into a buffer, and send it in one go.
1917          */
1918         len = rest_request_encode_wrapper(&ctx->body, func, REST_BODY_MAX_LEN, &ctx->request);
1919         if (len <= 0) {
1920                 REDEBUG("Failed creating HTTP body content");
1921                 return -1;
1922         }
1923
1924         SET_OPTION(CURLOPT_POSTFIELDS, ctx->body);
1925         SET_OPTION(CURLOPT_POSTFIELDSIZE, len);
1926
1927         return 0;
1928
1929 error:
1930         REDEBUG("Failed setting curl option %s: %s (%i)", option, curl_easy_strerror(ret), ret);
1931
1932         return -1;
1933 }
1934
1935 /** Configures request curlopts.
1936  *
1937  * Configures libcurl handle setting various curlopts for things like local
1938  * client time, Content-Type, and other FreeRADIUS custom headers.
1939  *
1940  * Current FreeRADIUS custom headers are:
1941  *  - X-FreeRADIUS-Section      The module section being processed.
1942  *  - X-FreeRADIUS-Server       The current virtual server the REQUEST is
1943  *                              passing through.
1944  *
1945  * Sets up callbacks for all response processing (buffers and body data).
1946  *
1947  * @param[in] instance configuration data.
1948  * @param[in] section configuration data.
1949  * @param[in] handle to configure.
1950  * @param[in] request Current request.
1951  * @param[in] method to use (HTTP verbs PUT, POST, DELETE etc...).
1952  * @param[in] type Content-Type for request encoding, also sets the default for decoding.
1953  * @param[in] username to use for HTTP authentication, may be NULL in which case configured defaults will be used.
1954  * @param[in] password to use for HTTP authentication, may be NULL in which case configured defaults will be used.
1955  * @param[in] uri buffer containing the expanded URI to send the request to.
1956  * @return 0 on success (all opts configured) -1 on error.
1957  */
1958 int rest_request_config(rlm_rest_t *instance, rlm_rest_section_t *section,
1959                         REQUEST *request, void *handle, http_method_t method,
1960                         http_body_type_t type,
1961                         char const *uri, char const *username, char const *password)
1962 {
1963         rlm_rest_handle_t       *randle = handle;
1964         rlm_rest_curl_context_t *ctx = randle->ctx;
1965         CURL                    *candle = randle->handle;
1966
1967         http_auth_type_t        auth = section->auth;
1968
1969         CURLcode        ret = CURLE_OK;
1970         char const      *option = "unknown";
1971         char const      *content_type;
1972
1973         VALUE_PAIR      *header;
1974         vp_cursor_t     headers;
1975
1976         char buffer[512];
1977
1978         rad_assert(candle);
1979         rad_assert((!username && !password) || (username && password));
1980
1981         buffer[(sizeof(buffer) - 1)] = '\0';
1982
1983         /*
1984          *      Setup any header options and generic headers.
1985          */
1986         SET_OPTION(CURLOPT_URL, uri);
1987         SET_OPTION(CURLOPT_NOSIGNAL, 1);
1988         SET_OPTION(CURLOPT_USERAGENT, "FreeRADIUS " RADIUSD_VERSION_STRING);
1989
1990         content_type = fr_int2str(http_content_type_table, type, section->body_str);
1991         snprintf(buffer, sizeof(buffer), "Content-Type: %s", content_type);
1992         ctx->headers = curl_slist_append(ctx->headers, buffer);
1993         if (!ctx->headers) goto error_header;
1994
1995         SET_OPTION(CURLOPT_CONNECTTIMEOUT_MS, instance->connect_timeout);
1996         SET_OPTION(CURLOPT_TIMEOUT_MS, section->timeout);
1997
1998 #ifdef CURLOPT_PROTOCOLS
1999         SET_OPTION(CURLOPT_PROTOCOLS, (CURLPROTO_HTTP | CURLPROTO_HTTPS));
2000 #endif
2001
2002         /*
2003          *      FreeRADIUS custom headers
2004          */
2005         RDEBUG3("Adding custom headers:");
2006         RINDENT();
2007         snprintf(buffer, sizeof(buffer), "X-FreeRADIUS-Section: %s", section->name);
2008         RDEBUG3("%s", buffer);
2009         ctx->headers = curl_slist_append(ctx->headers, buffer);
2010         if (!ctx->headers) goto error_header;
2011
2012         snprintf(buffer, sizeof(buffer), "X-FreeRADIUS-Server: %s", request->server);
2013         RDEBUG3("%s", buffer);
2014         ctx->headers = curl_slist_append(ctx->headers, buffer);
2015         if (!ctx->headers) goto error_header;
2016
2017         fr_cursor_init(&headers, &request->config);
2018         while (fr_cursor_next_by_num(&headers, PW_REST_HTTP_HEADER, 0, TAG_ANY)) {
2019                 header = fr_cursor_remove(&headers);
2020                 if (!strchr(header->vp_strvalue, ':')) {
2021                         RWDEBUG("Invalid HTTP header \"%s\" must be in format '<attribute>: <value>'.  Skipping...",
2022                                 header->vp_strvalue);
2023                         talloc_free(header);
2024                         continue;
2025                 }
2026                 RDEBUG3("%s", header->vp_strvalue);
2027                 ctx->headers = curl_slist_append(ctx->headers, header->vp_strvalue);
2028                 talloc_free(header);
2029         }
2030         REXDENT();
2031
2032         /*
2033          *      Configure HTTP verb (GET, POST, PUT, PATCH, DELETE, other...)
2034          */
2035         switch (method) {
2036         case HTTP_METHOD_GET:
2037                 SET_OPTION(CURLOPT_HTTPGET, 1L);
2038                 break;
2039
2040         case HTTP_METHOD_POST:
2041                 SET_OPTION(CURLOPT_POST, 1L);
2042                 break;
2043
2044         case HTTP_METHOD_PUT:
2045                 /*
2046                  *      Do not set CURLOPT_PUT, this will cause libcurl
2047                  *      to ignore CURLOPT_POSTFIELDs and attempt to read
2048                  *      whatever was set with CURLOPT_READDATA, which by
2049                  *      default is stdin.
2050                  *
2051                  *      This is many cases will cause the server to block,
2052                  *      indefinitely.
2053                  */
2054                 SET_OPTION(CURLOPT_CUSTOMREQUEST, "PUT");
2055                 break;
2056
2057         case HTTP_METHOD_PATCH:
2058                 SET_OPTION(CURLOPT_CUSTOMREQUEST, "PATCH");
2059                 break;
2060
2061         case HTTP_METHOD_DELETE:
2062                 SET_OPTION(CURLOPT_CUSTOMREQUEST, "DELETE");
2063                 break;
2064
2065         case HTTP_METHOD_CUSTOM:
2066                 SET_OPTION(CURLOPT_CUSTOMREQUEST, section->method_str);
2067                 break;
2068
2069         default:
2070                 rad_assert(0);
2071                 break;
2072         };
2073
2074         /*
2075          *      Set user based authentication parameters
2076          */
2077         if (auth) {
2078                 if ((auth >= HTTP_AUTH_BASIC) &&
2079                     (auth <= HTTP_AUTH_ANY_SAFE)) {
2080                         SET_OPTION(CURLOPT_HTTPAUTH, http_curl_auth[auth]);
2081
2082                         if (username) {
2083                                 SET_OPTION(CURLOPT_USERNAME, username);
2084                         } else if (section->username) {
2085                                 if (radius_xlat(buffer, sizeof(buffer), request, section->username, NULL, NULL) < 0) {
2086                                         option = STRINGIFY(CURLOPT_USERNAME);
2087                                         goto error;
2088                                 }
2089                                 SET_OPTION(CURLOPT_USERNAME, buffer);
2090                         }
2091
2092                         if (password) {
2093                                 SET_OPTION(CURLOPT_PASSWORD, password);
2094                         } else if (section->password) {
2095                                 if (radius_xlat(buffer, sizeof(buffer), request, section->password, NULL, NULL) < 0) {
2096                                         option = STRINGIFY(CURLOPT_PASSWORD);
2097                                         goto error;
2098                                 }
2099                                 SET_OPTION(CURLOPT_PASSWORD, buffer);
2100                         }
2101 #ifdef CURLOPT_TLSAUTH_USERNAME
2102                 } else if (auth == HTTP_AUTH_TLS_SRP) {
2103                         SET_OPTION(CURLOPT_TLSAUTH_TYPE, http_curl_auth[auth]);
2104
2105                         if (username) {
2106                                 SET_OPTION(CURLOPT_TLSAUTH_USERNAME, username);
2107                         } else if (section->username) {
2108                                 if (radius_xlat(buffer, sizeof(buffer), request, section->username, NULL, NULL) < 0) {
2109                                         option = STRINGIFY(CURLOPT_TLSAUTH_USERNAME);
2110                                         goto error;
2111                                 }
2112                                 SET_OPTION(CURLOPT_TLSAUTH_USERNAME, buffer);
2113                         }
2114
2115                         if (password) {
2116                                 SET_OPTION(CURLOPT_TLSAUTH_PASSWORD, password);
2117                         } else if (section->password) {
2118                                 if (radius_xlat(buffer, sizeof(buffer), request, section->password, NULL, NULL) < 0) {
2119                                         option = STRINGIFY(CURLOPT_TLSAUTH_PASSWORD);
2120                                         goto error;
2121                                 }
2122                                 SET_OPTION(CURLOPT_TLSAUTH_PASSWORD, buffer);
2123                         }
2124 #endif
2125                 }
2126         }
2127
2128         /*
2129          *      Set SSL/TLS authentication parameters
2130          */
2131         if (section->tls_certificate_file) {
2132                 SET_OPTION(CURLOPT_SSLCERT, section->tls_certificate_file);
2133         }
2134
2135         if (section->tls_private_key_file) {
2136                 SET_OPTION(CURLOPT_SSLKEY, section->tls_private_key_file);
2137         }
2138
2139         if (section->tls_private_key_password) {
2140                 SET_OPTION(CURLOPT_KEYPASSWD, section->tls_private_key_password);
2141         }
2142
2143         if (section->tls_ca_file) {
2144                 SET_OPTION(CURLOPT_ISSUERCERT, section->tls_ca_file);
2145         }
2146
2147         if (section->tls_ca_path) {
2148                 SET_OPTION(CURLOPT_CAPATH, section->tls_ca_path);
2149         }
2150
2151         if (section->tls_random_file) {
2152                 SET_OPTION(CURLOPT_RANDOM_FILE, section->tls_random_file);
2153         }
2154
2155         SET_OPTION(CURLOPT_SSL_VERIFYPEER, (section->tls_check_cert == true) ? 1 : 0);
2156         SET_OPTION(CURLOPT_SSL_VERIFYHOST, (section->tls_check_cert_cn == true) ? 2 : 0);
2157
2158         /*
2159          *      Tell CURL how to get HTTP body content, and how to process incoming data.
2160          */
2161         rest_response_init(request, &ctx->response, type);
2162
2163         SET_OPTION(CURLOPT_HEADERFUNCTION, rest_response_header);
2164         SET_OPTION(CURLOPT_HEADERDATA, &ctx->response);
2165         SET_OPTION(CURLOPT_WRITEFUNCTION, rest_response_body);
2166         SET_OPTION(CURLOPT_WRITEDATA, &ctx->response);
2167
2168         /*
2169          *  Force parsing the body text as a particular encoding.
2170          */
2171         ctx->response.force_to = section->force_to;
2172
2173         switch (method) {
2174         case HTTP_METHOD_GET:
2175         case HTTP_METHOD_DELETE:
2176                 RDEBUG3("Using a HTTP method which does not require a body.  Forcing request body type to \"none\"");
2177                 goto finish;
2178
2179         case HTTP_METHOD_POST:
2180         case HTTP_METHOD_PUT:
2181         case HTTP_METHOD_PATCH:
2182         case HTTP_METHOD_CUSTOM:
2183                 if (section->chunk > 0) {
2184                         ctx->request.chunk = section->chunk;
2185
2186                         ctx->headers = curl_slist_append(ctx->headers, "Expect:");
2187                         if (!ctx->headers) goto error_header;
2188
2189                         ctx->headers = curl_slist_append(ctx->headers, "Transfer-Encoding: chunked");
2190                         if (!ctx->headers) goto error_header;
2191                 }
2192
2193                 RDEBUG3("Request body content-type will be \"%s\"",
2194                         fr_int2str(http_content_type_table, type, section->body_str));
2195                 break;
2196
2197         default:
2198                 rad_assert(0);
2199         };
2200
2201         /*
2202          *  Setup encoder specific options
2203          */
2204         switch (type) {
2205         case HTTP_BODY_NONE:
2206                 if (rest_request_config_body(instance, section, request, handle,
2207                                              NULL) < 0) {
2208                         return -1;
2209                 }
2210
2211                 break;
2212
2213         case HTTP_BODY_CUSTOM_XLAT:
2214         {
2215                 rest_custom_data_t *data;
2216                 char *expanded = NULL;
2217
2218                 if (radius_axlat(&expanded, request, section->data, NULL, NULL) < 0) {
2219                         return -1;
2220                 }
2221
2222                 data = talloc_zero(request, rest_custom_data_t);
2223                 data->p = expanded;
2224
2225                 /* Use the encoder specific pointer to store the data we need to encode */
2226                 ctx->request.encoder = data;
2227                 if (rest_request_config_body(instance, section, request, handle,
2228                                              rest_encode_custom) < 0) {
2229                         TALLOC_FREE(ctx->request.encoder);
2230                         return -1;
2231                 }
2232
2233                 break;
2234         }
2235
2236         case HTTP_BODY_CUSTOM_LITERAL:
2237         {
2238                 rest_custom_data_t *data;
2239
2240                 data = talloc_zero(request, rest_custom_data_t);
2241                 data->p = section->data;
2242
2243                 /* Use the encoder specific pointer to store the data we need to encode */
2244                 ctx->request.encoder = data;
2245                 if (rest_request_config_body(instance, section, request, handle,
2246                                              rest_encode_custom) < 0) {
2247                         TALLOC_FREE(ctx->request.encoder);
2248                         return -1;
2249                 }
2250         }
2251                 break;
2252
2253 #ifdef HAVE_JSON
2254         case HTTP_BODY_JSON:
2255                 rest_request_init(request, &ctx->request, true);
2256
2257                 if (rest_request_config_body(instance, section, request, handle,
2258                                              rest_encode_json) < 0) {
2259                         return -1;
2260                 }
2261
2262                 break;
2263 #endif
2264
2265         case HTTP_BODY_POST:
2266                 rest_request_init(request, &ctx->request, false);
2267
2268                 if (rest_request_config_body(instance, section, request, handle,
2269                                              rest_encode_post) < 0) {
2270                         return -1;
2271                 }
2272
2273                 break;
2274
2275         default:
2276                 rad_assert(0);
2277         }
2278
2279
2280 finish:
2281         SET_OPTION(CURLOPT_HTTPHEADER, ctx->headers);
2282
2283         return 0;
2284
2285 error:
2286         REDEBUG("Failed setting curl option %s: %s (%i)", option, curl_easy_strerror(ret), ret);
2287         return -1;
2288
2289 error_header:
2290         REDEBUG("Failed creating header");
2291         REXDENT();
2292         return -1;
2293 }
2294
2295 /** Sends a REST (HTTP) request.
2296  *
2297  * Send the actual REST request to the server. The response will be handled by
2298  * the numerous callbacks configured in rest_request_config.
2299  *
2300  * @param[in] instance configuration data.
2301  * @param[in] section configuration data.
2302  * @param[in] request Current request.
2303  * @param[in] handle to use.
2304  * @return 0 on success or -1 on error.
2305  */
2306 int rest_request_perform(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
2307                          REQUEST *request, void *handle)
2308 {
2309         rlm_rest_handle_t       *randle = handle;
2310         CURL                    *candle = randle->handle;
2311         CURLcode                ret;
2312
2313         ret = curl_easy_perform(candle);
2314         if (ret != CURLE_OK) {
2315                 REDEBUG("Request failed: %i - %s", ret, curl_easy_strerror(ret));
2316
2317                 return -1;
2318         }
2319
2320         return 0;
2321 }
2322
2323 /** Sends the response to the correct decode function.
2324  *
2325  * Uses the Content-Type information written in rest_response_header to
2326  * determine the correct decode function to use. The decode function will
2327  * then convert the raw received data into VALUE_PAIRs.
2328  *
2329  * @param[in] instance configuration data.
2330  * @param[in] section configuration data.
2331  * @param[in] request Current request.
2332  * @param[in] handle to use.
2333  * @return 0 on success or -1 on error.
2334  */
2335 int rest_response_decode(rlm_rest_t *instance, rlm_rest_section_t *section, REQUEST *request, void *handle)
2336 {
2337         rlm_rest_handle_t       *randle = handle;
2338         rlm_rest_curl_context_t *ctx = randle->ctx;
2339
2340         int ret = -1;   /* -Wsometimes-uninitialized */
2341
2342         if (!ctx->response.buffer) {
2343                 RDEBUG2("Skipping attribute processing, no valid body data received");
2344                 return 0;
2345         }
2346
2347         switch (ctx->response.type) {
2348         case HTTP_BODY_NONE:
2349                 return 0;
2350
2351         case HTTP_BODY_PLAIN:
2352                 ret = rest_decode_plain(instance, section, request, handle, ctx->response.buffer, ctx->response.used);
2353                 break;
2354
2355         case HTTP_BODY_POST:
2356                 ret = rest_decode_post(instance, section, request, handle, ctx->response.buffer, ctx->response.used);
2357                 break;
2358
2359 #ifdef HAVE_JSON
2360         case HTTP_BODY_JSON:
2361                 ret = rest_decode_json(instance, section, request, handle, ctx->response.buffer, ctx->response.used);
2362                 break;
2363 #endif
2364
2365         case HTTP_BODY_UNSUPPORTED:
2366         case HTTP_BODY_UNAVAILABLE:
2367         case HTTP_BODY_INVALID:
2368                 return -1;
2369
2370         default:
2371                 rad_assert(0);
2372         }
2373
2374         return ret;
2375 }
2376
2377 /** Cleans up after a REST request.
2378  *
2379  * Resets all options associated with a CURL handle, and frees any headers
2380  * associated with it.
2381  *
2382  * Calls rest_read_ctx_free and rest_response_free to free any memory used by
2383  * context data.
2384  *
2385  * @param[in] instance configuration data.
2386  * @param[in] section configuration data.
2387  * @param[in] handle to cleanup.
2388  */
2389 void rest_request_cleanup(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section, void *handle)
2390 {
2391         rlm_rest_handle_t       *randle = handle;
2392         rlm_rest_curl_context_t *ctx = randle->ctx;
2393         CURL                    *candle = randle->handle;
2394
2395         /*
2396          *  Clear any previously configured options
2397          */
2398         curl_easy_reset(candle);
2399
2400         /*
2401          *  Free header list
2402          */
2403         if (ctx->headers != NULL) {
2404                 curl_slist_free_all(ctx->headers);
2405                 ctx->headers = NULL;
2406         }
2407
2408         /*
2409          *  Free body data (only used if chunking is disabled)
2410          */
2411         if (ctx->body != NULL) {
2412                 free(ctx->body);
2413                 ctx->body = NULL;
2414         }
2415
2416         /*
2417          *  Free response data
2418          */
2419         if (ctx->response.buffer) {
2420                 free(ctx->response.buffer);
2421                 ctx->response.buffer = NULL;
2422         }
2423
2424         TALLOC_FREE(ctx->request.encoder);
2425         TALLOC_FREE(ctx->response.decoder);
2426 }
2427
2428 /** URL encodes a string.
2429  *
2430  * Encode special chars as per RFC 3986 section 4.
2431  *
2432  * @param[in] request Current request.
2433  * @param[out] out Where to write escaped string.
2434  * @param[in] outlen Size of out buffer.
2435  * @param[in] raw string to be urlencoded.
2436  * @param[in] arg pointer, gives context for escaping.
2437  * @return length of data written to out (excluding NULL).
2438  */
2439 size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *raw, UNUSED void *arg)
2440 {
2441         char *escaped;
2442
2443         escaped = curl_escape(raw, strlen(raw));
2444         strlcpy(out, escaped, outlen);
2445         curl_free(escaped);
2446
2447         return strlen(out);
2448 }
2449
2450 /** Builds URI; performs XLAT expansions and encoding.
2451  *
2452  * Splits the URI into "http://example.org" and "/%{xlat}/query/?bar=foo"
2453  * Both components are expanded, but values expanded for the second component
2454  * are also url encoded.
2455  *
2456  * @param[out] out Where to write the pointer to the new buffer containing the escaped URI.
2457  * @param[in] instance configuration data.
2458  * @param[in] uri configuration data.
2459  * @param[in] request Current request
2460  * @return length of data written to buffer (excluding NULL) or < 0 if an error
2461  *      occurred.
2462  */
2463 ssize_t rest_uri_build(char **out, UNUSED rlm_rest_t *instance, REQUEST *request, char const *uri)
2464 {
2465         char const      *p;
2466         char            *path_exp = NULL;
2467
2468         char            *scheme;
2469         char const      *path;
2470
2471         ssize_t         len;
2472
2473         p = uri;
2474
2475         /*
2476          *  All URLs must contain at least <scheme>://<server>/
2477          */
2478         p = strchr(p, ':');
2479         if (!p || (*++p != '/') || (*++p != '/')) {
2480                 malformed:
2481                 REDEBUG("Error URI is malformed, can't find start of path");
2482                 return -1;
2483         }
2484         p = strchr(p + 1, '/');
2485         if (!p) {
2486                 goto malformed;
2487         }
2488
2489         len = (p - uri);
2490
2491         /*
2492          *  Allocate a temporary buffer to hold the first part of the URI
2493          */
2494         scheme = talloc_array(request, char, len + 1);
2495         strlcpy(scheme, uri, len + 1);
2496
2497         path = (uri + len);
2498
2499         len = radius_axlat(out, request, scheme, NULL, NULL);
2500         talloc_free(scheme);
2501         if (len < 0) {
2502                 TALLOC_FREE(*out);
2503
2504                 return 0;
2505         }
2506
2507         len = radius_axlat(&path_exp, request, path, rest_uri_escape, NULL);
2508         if (len < 0) {
2509                 TALLOC_FREE(*out);
2510
2511                 return 0;
2512         }
2513
2514         MEM(*out = talloc_strdup_append(*out, path_exp));
2515         talloc_free(path_exp);
2516
2517         return talloc_array_length(*out) - 1;   /* array_length includes \0 */
2518 }
2519
2520 /** Unescapes the host portion of a URI string
2521  *
2522  * This is required because the xlat functions which operate on the input string
2523  * cannot distinguish between host and path components.
2524  *
2525  * @param[out] out Where to write the pointer to the new buffer containing the escaped URI.
2526  * @param[in] instance configuration data.
2527  * @param[in] request Current request
2528  * @param[in] handle to use.
2529  * @param[in] uri configuration data.
2530  * @return length of data written to buffer (excluding NULL) or < 0 if an error
2531  *      occurred.
2532  */
2533 ssize_t rest_uri_host_unescape(char **out, UNUSED rlm_rest_t *instance, REQUEST *request,
2534                                void *handle, char const *uri)
2535 {
2536         rlm_rest_handle_t       *randle = handle;
2537         CURL                    *candle = randle->handle;
2538
2539         char const              *p, *q;
2540
2541         char                    *scheme;
2542
2543         ssize_t                 len;
2544
2545         p = uri;
2546
2547         /*
2548          *  All URLs must contain at least <scheme>://<server>/
2549          */
2550         p = strchr(p, ':');
2551         if (!p || (*++p != '/') || (*++p != '/')) {
2552                 malformed:
2553                 REDEBUG("Error URI is malformed, can't find start of path");
2554                 return -1;
2555         }
2556         p = strchr(p + 1, '/');
2557         if (!p) {
2558                 goto malformed;
2559         }
2560
2561         len = (p - uri);
2562
2563         /*
2564          *  Unescape any special sequences in the first part of the URI
2565          */
2566         scheme = curl_easy_unescape(candle, uri, len, NULL);
2567         if (!scheme) {
2568                 REDEBUG("Error unescaping host");
2569                 return -1;
2570         }
2571
2572         /*
2573          *  URIs can't contain spaces, so anything after the space must
2574          *  be something else.
2575          */
2576         q = strchr(p, ' ');
2577         *out = q ? talloc_typed_asprintf(request, "%s%.*s", scheme, (int)(q - p), p) :
2578                    talloc_typed_asprintf(request, "%s%s", scheme, p);
2579
2580         MEM(*out);
2581         curl_free(scheme);
2582
2583         return talloc_array_length(*out) - 1;   /* array_length includes \0 */
2584 }