add recv_coa
[freeradius.git] / src / modules / rlm_rest / rest.h
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 Function prototypes and datatypes for the REST (HTTP) transport.
21  * @file rest.h
22  *
23  * @copyright 2012-2014  Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
24  */
25
26 RCSIDH(other_h, "$Id$")
27
28 #include <freeradius-devel/connection.h>
29 #include "config.h"
30
31 #define CURL_NO_OLDIES 1
32 #include <curl/curl.h>
33
34 #ifdef HAVE_JSON
35 #  if defined(HAVE_JSONMC_JSON_H)
36 #    include <json-c/json.h>
37 #  elif defined(HAVE_JSON_JSON_H)
38 #    include <json/json.h>
39 #  endif
40 #endif
41
42 #define REST_URI_MAX_LEN                2048
43 #define REST_BODY_MAX_LEN               8192
44 #define REST_BODY_INIT                  1024
45 #define REST_BODY_MAX_ATTRS             256
46
47 typedef enum {
48         HTTP_METHOD_UNKNOWN = 0,
49         HTTP_METHOD_GET,
50         HTTP_METHOD_POST,
51         HTTP_METHOD_PUT,
52         HTTP_METHOD_PATCH,
53         HTTP_METHOD_DELETE,
54         HTTP_METHOD_CUSTOM              //!< Must always come last, should not be in method table
55 } http_method_t;
56
57 typedef enum {
58         HTTP_BODY_UNKNOWN = 0,
59         HTTP_BODY_UNSUPPORTED,
60         HTTP_BODY_UNAVAILABLE,
61         HTTP_BODY_INVALID,
62         HTTP_BODY_NONE,
63         HTTP_BODY_CUSTOM_XLAT,
64         HTTP_BODY_CUSTOM_LITERAL,
65         HTTP_BODY_POST,
66         HTTP_BODY_JSON,
67         HTTP_BODY_XML,
68         HTTP_BODY_YAML,
69         HTTP_BODY_HTML,
70         HTTP_BODY_PLAIN,
71         HTTP_BODY_NUM_ENTRIES
72 } http_body_type_t;
73
74 typedef enum {
75         HTTP_AUTH_UNKNOWN = 0,
76         HTTP_AUTH_NONE,
77         HTTP_AUTH_TLS_SRP,
78         HTTP_AUTH_BASIC,
79         HTTP_AUTH_DIGEST,
80         HTTP_AUTH_DIGEST_IE,
81         HTTP_AUTH_GSSNEGOTIATE,
82         HTTP_AUTH_NTLM,
83         HTTP_AUTH_NTLM_WB,
84         HTTP_AUTH_ANY,
85         HTTP_AUTH_ANY_SAFE,
86         HTTP_AUTH_NUM_ENTRIES
87 } http_auth_type_t;
88
89 /*
90  *      Must be updated (in rest.c) if additional values are added to
91  *      http_body_type_t
92  */
93 extern const http_body_type_t http_body_type_supported[HTTP_BODY_NUM_ENTRIES];
94
95 extern const unsigned long http_curl_auth[HTTP_AUTH_NUM_ENTRIES];
96
97 extern const FR_NAME_NUMBER http_auth_table[];
98
99 extern const FR_NAME_NUMBER http_method_table[];
100
101 extern const FR_NAME_NUMBER http_body_type_table[];
102
103 extern const FR_NAME_NUMBER http_content_type_table[];
104
105 /*
106  *      Structure for section configuration
107  */
108 typedef struct rlm_rest_section_t {
109         char const              *name;          //!< Section name.
110         char const              *uri;           //!< URI to send HTTP request to.
111
112         char const              *method_str;    //!< The string version of the HTTP method.
113         http_method_t           method;         //!< What HTTP method should be used, GET, POST etc...
114
115         char const              *body_str;      //!< The string version of the encoding/content type.
116         http_body_type_t        body;           //!< What encoding type should be used.
117
118         char const              *force_to_str;  //!< Force decoding with this decoder.
119         http_body_type_t        force_to;       //!< Override the Content-Type header in the response
120                                                 //!< to force decoding as a particular type.
121
122         char const              *data;          //!< Custom body data (optional).
123
124         char const              *auth_str;      //!< The string version of the Auth-Type.
125         http_auth_type_t        auth;           //!< HTTP auth type.
126         bool                    require_auth;   //!< Whether HTTP-Auth is required or not.
127         char const              *username;      //!< Username used for HTTP-Auth
128         char const              *password;      //!< Password used for HTTP-Auth
129
130         char const              *tls_certificate_file;
131         char const              *tls_private_key_file;
132         char const              *tls_private_key_password;
133         char const              *tls_ca_file;
134         char const              *tls_ca_path;
135         char const              *tls_random_file;
136         bool                    tls_check_cert;
137         bool                    tls_check_cert_cn;
138
139         struct timeval          timeout_tv;     //!< Timeout timeval.
140         long                    timeout;        //!< Timeout in ms.
141         uint32_t                chunk;          //!< Max chunk-size (mainly for testing the encoders)
142 } rlm_rest_section_t;
143
144 /*
145  *      Structure for module configuration
146  */
147 typedef struct rlm_rest_t {
148         char const              *xlat_name;     //!< Instance name.
149
150         char const              *connect_uri;   //!< URI we attempt to connect to, to pre-establish
151                                                 //!< TCP connections.
152
153         struct timeval          connect_timeout_tv;     //!< Connection timeout timeval.
154         long                    connect_timeout;        //!< Connection timeout ms.
155
156         fr_connection_pool_t    *pool;          //!< Pointer to the connection pool.
157
158         rlm_rest_section_t      authorize;      //!< Configuration specific to authorisation.
159         rlm_rest_section_t      authenticate;   //!< Configuration specific to authentication.
160         rlm_rest_section_t      accounting;     //!< Configuration specific to accounting.
161         rlm_rest_section_t      checksimul;     //!< Configuration specific to simultaneous session
162                                                 //!< checking.
163         rlm_rest_section_t      post_auth;      //!< Configuration specific to Post-auth
164 #ifdef WITH_COA
165         rlm_rest_section_t      recv_coa;               //!< Configuration specific to recv-coa
166 #endif
167 } rlm_rest_t;
168
169 /*
170  *      States for stream based attribute encoders
171  */
172 typedef enum {
173         READ_STATE_INIT = 0,
174         READ_STATE_ATTR_BEGIN,
175         READ_STATE_ATTR_CONT,
176         READ_STATE_ATTR_END,
177         READ_STATE_END,
178 } read_state_t;
179
180 /*
181  *      States for the response parser
182  */
183 typedef enum {
184         WRITE_STATE_INIT = 0,
185         WRITE_STATE_PARSE_HEADERS,
186         WRITE_STATE_PARSE_CONTENT,
187         WRITE_STATE_DISCARD,
188 } write_state_t;
189
190 /*
191  *      Outbound data context (passed to CURLOPT_READFUNCTION as CURLOPT_READDATA)
192  */
193 typedef struct rlm_rest_request_t {
194         rlm_rest_t              *instance;      //!< This instance of rlm_rest.
195         REQUEST                 *request;       //!< Current request.
196         read_state_t            state;          //!< Encoder state
197
198         vp_cursor_t             cursor;         //!< Cursor pointing to the start of the list to encode.
199
200         size_t                  chunk;          //!< Chunk size
201
202         void                    *encoder;       //!< Encoder specific data.
203 } rlm_rest_request_t;
204
205 /*
206  *      Curl inbound data context (passed to CURLOPT_WRITEFUNCTION and
207  *      CURLOPT_HEADERFUNCTION as CURLOPT_WRITEDATA and CURLOPT_HEADERDATA)
208  */
209 typedef struct rlm_rest_response_t {
210         rlm_rest_t              *instance;      //!< This instance of rlm_rest.
211         REQUEST                 *request;       //!< Current request.
212         write_state_t           state;          //!< Decoder state.
213
214         char                    *buffer;        //!< Raw incoming HTTP data.
215         size_t                  alloc;          //!< Space allocated for buffer.
216         size_t                  used;           //!< Space used in buffer.
217
218         int                     code;           //!< HTTP Status Code.
219         http_body_type_t        type;           //!< HTTP Content Type.
220         http_body_type_t        force_to;       //!< Force decoding the body type as a particular encoding.
221
222         void                    *decoder;       //!< Decoder specific data.
223 } rlm_rest_response_t;
224
225 /*
226  *      Curl context data
227  */
228 typedef struct rlm_rest_curl_context_t {
229         struct curl_slist       *headers;       //!< Any HTTP headers which will be sent with the
230                                                 //!< request.
231
232         char                    *body;          //!< Pointer to the buffer which contains body data/
233                                                 //!< Only used when not performing chunked encoding.
234
235         rlm_rest_request_t      request;        //!< Request context data.
236         rlm_rest_response_t     response;       //!< Response context data.
237 } rlm_rest_curl_context_t;
238
239 /*
240  *      Connection API handle
241  */
242 typedef struct rlm_rest_handle_t {
243         void                    *handle;        //!< Real Handle.
244         rlm_rest_curl_context_t *ctx;           //!< Context.
245 } rlm_rest_handle_t;
246
247 /*
248  *      Function prototype for rest_read_wrapper. Matches CURL's
249  *      CURLOPT_READFUNCTION prototype.
250  */
251 typedef size_t (*rest_read_t)(void *ptr, size_t size, size_t nmemb,
252                               void *userdata);
253
254 /*
255  *      Connection API callbacks
256  */
257 int rest_init(rlm_rest_t *instance);
258
259 void rest_cleanup(void);
260
261 void *mod_conn_create(TALLOC_CTX *ctx, void *instance);
262
263 int mod_conn_alive(void *instance, void *handle);
264
265 /*
266  *      Request processing API
267  */
268 int rest_request_config(rlm_rest_t *instance,
269                         rlm_rest_section_t *section, REQUEST *request,
270                         void *handle, http_method_t method,
271                         http_body_type_t type, char const *uri,
272                         char const *username, char const *password) CC_HINT(nonnull (1,2,3,4,7));
273
274 int rest_request_perform(rlm_rest_t *instance,
275                          rlm_rest_section_t *section, REQUEST *request,
276                          void *handle);
277
278 int rest_response_decode(rlm_rest_t *instance,
279                         UNUSED rlm_rest_section_t *section, REQUEST *request,
280                         void *handle);
281
282 void rest_response_error(REQUEST *request, rlm_rest_handle_t *handle);
283
284 void rest_request_cleanup(rlm_rest_t *instance, rlm_rest_section_t *section,
285                           void *handle);
286
287 #define rest_get_handle_code(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->response.code)
288
289 #define rest_get_handle_type(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->response.type)
290
291 size_t rest_get_handle_data(char const **out, rlm_rest_handle_t *handle);
292
293 /*
294  *      Helper functions
295  */
296 size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *raw, UNUSED void *arg);
297 ssize_t rest_uri_build(char **out, rlm_rest_t *instance, REQUEST *request, char const *uri);
298 ssize_t rest_uri_host_unescape(char **out, UNUSED rlm_rest_t *instance, REQUEST *request,
299                                void *handle, char const *uri);