summaryrefslogtreecommitdiffstats
path: root/src/modules/rlm_rest/rest.h
blob: cc0a0be92a26375dafd63a8b17ace01693820ec0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/*
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

/**
 * $Id$
 *
 * @brief Function prototypes and datatypes for the REST (HTTP) transport.
 * @file rest.h
 *
 * @copyright 2012-2014  Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
 */

RCSIDH(other_h, "$Id$")

#include <freeradius-devel/connection.h>
#include "config.h"

#define CURL_NO_OLDIES 1
#include <curl/curl.h>

#ifdef HAVE_WDOCUMENTATION
DIAG_OFF(documentation)
#endif

#ifdef HAVE_JSON
#  if defined(HAVE_JSONMC_JSON_H)
#    include <json-c/json.h>
#  elif defined(HAVE_JSON_JSON_H)
#    include <json/json.h>
#  endif
#endif

#ifdef HAVE_WDOCUMENTATION
DIAG_ON(documentation)
#endif

#define REST_URI_MAX_LEN		2048
#define REST_BODY_MAX_LEN		8192
#define REST_BODY_INIT			1024
#define REST_BODY_MAX_ATTRS		256

typedef enum {
	HTTP_METHOD_UNKNOWN = 0,
	HTTP_METHOD_GET,
	HTTP_METHOD_POST,
	HTTP_METHOD_PUT,
	HTTP_METHOD_PATCH,
	HTTP_METHOD_DELETE,
	HTTP_METHOD_CUSTOM		//!< Must always come last, should not be in method table
} http_method_t;

typedef enum {
	HTTP_BODY_UNKNOWN = 0,
	HTTP_BODY_UNSUPPORTED,
	HTTP_BODY_UNAVAILABLE,
	HTTP_BODY_INVALID,
	HTTP_BODY_NONE,
	HTTP_BODY_CUSTOM_XLAT,
	HTTP_BODY_CUSTOM_LITERAL,
	HTTP_BODY_POST,
	HTTP_BODY_JSON,
	HTTP_BODY_XML,
	HTTP_BODY_YAML,
	HTTP_BODY_HTML,
	HTTP_BODY_PLAIN,
	HTTP_BODY_NUM_ENTRIES
} http_body_type_t;

typedef enum {
	HTTP_AUTH_UNKNOWN = 0,
	HTTP_AUTH_NONE,
	HTTP_AUTH_TLS_SRP,
	HTTP_AUTH_BASIC,
	HTTP_AUTH_DIGEST,
	HTTP_AUTH_DIGEST_IE,
	HTTP_AUTH_GSSNEGOTIATE,
	HTTP_AUTH_NTLM,
	HTTP_AUTH_NTLM_WB,
	HTTP_AUTH_ANY,
	HTTP_AUTH_ANY_SAFE,
	HTTP_AUTH_NUM_ENTRIES
} http_auth_type_t;

/*
 *	Must be updated (in rest.c) if additional values are added to
 *	http_body_type_t
 */
extern const http_body_type_t http_body_type_supported[HTTP_BODY_NUM_ENTRIES];

extern const unsigned long http_curl_auth[HTTP_AUTH_NUM_ENTRIES];

extern const FR_NAME_NUMBER http_auth_table[];

extern const FR_NAME_NUMBER http_method_table[];

extern const FR_NAME_NUMBER http_body_type_table[];

extern const FR_NAME_NUMBER http_content_type_table[];

extern const FR_NAME_NUMBER http_negotiation_table[];

/*
 *	Structure for section configuration
 */
typedef struct rlm_rest_section_t {
	char const		*name;		//!< Section name.
	char const		*uri;		//!< URI to send HTTP request to.

	char const		*method_str;	//!< The string version of the HTTP method.
	http_method_t		method;		//!< What HTTP method should be used, GET, POST etc...

	char const		*body_str;	//!< The string version of the encoding/content type.
	http_body_type_t	body;		//!< What encoding type should be used.

	bool			attr_num;	//!< If true, the the attribute number is supplied for each attribute.
	bool			raw_value;	//!< If true, enumerated attributes are provided as a numeric value

	char const		*force_to_str;	//!< Force decoding with this decoder.
	http_body_type_t	force_to;	//!< Override the Content-Type header in the response
						//!< to force decoding as a particular type.

	char const		*data;		//!< Custom body data (optional).

	char const		*auth_str;	//!< The string version of the Auth-Type.
	http_auth_type_t	auth;		//!< HTTP auth type.
	bool			require_auth;	//!< Whether HTTP-Auth is required or not.
	char const		*username;	//!< Username used for HTTP-Auth
	char const		*password;	//!< Password used for HTTP-Auth

	char const		*tls_certificate_file;
	char const		*tls_private_key_file;
	char const		*tls_private_key_password;
	char const		*tls_ca_file;
	char const		*tls_ca_info_file;
	char const		*tls_ca_path;
	char const		*tls_random_file;
	bool			tls_check_cert;
	bool			tls_check_cert_cn;

	bool			body_encode;	//!< Should the body data be URI encoded.  Only applies
						//!< to xlats.

	struct timeval		timeout_tv;	//!< Timeout timeval.
	long			timeout;	//!< Timeout in ms.
	uint32_t		chunk;		//!< Max chunk-size (mainly for testing the encoders)
} rlm_rest_section_t;

/*
 *	Structure for module configuration
 */
typedef struct rlm_rest_t {
	char const		*xlat_name;	//!< Instance name.

	char const		*connect_uri;	//!< URI we attempt to connect to, to pre-establish
						//!< TCP connections.

	struct timeval		connect_timeout_tv;	//!< Connection timeout timeval.
	long			connect_timeout;	//!< Connection timeout ms.

	char const		*http_negotiation_str;	//!< The string version of the http_negotiation
	long			http_negotiation;	//!< The HTTP protocol version to use

	fr_connection_pool_t	*pool;		//!< Pointer to the connection pool.

	rlm_rest_section_t	authorize;	//!< Configuration specific to authorisation.
	rlm_rest_section_t	authenticate;	//!< Configuration specific to authentication.
	rlm_rest_section_t	preacct;	//!< Configuration specific to preacct.
	rlm_rest_section_t	accounting;	//!< Configuration specific to accounting.
	rlm_rest_section_t	checksimul;	//!< Configuration specific to simultaneous session
						//!< checking.
	rlm_rest_section_t	post_auth;	//!< Configuration specific to Post-auth

	rlm_rest_section_t	pre_proxy;	//!< Configuration specific to pre_proxy
	rlm_rest_section_t	post_proxy;	//!< Configuration specific to post_proxy

	rlm_rest_section_t	xlat;		//!< Configuration specific to xlats

#ifdef WITH_COA
	rlm_rest_section_t	recv_coa;		//!< Configuration specific to recv-coa
#endif
} rlm_rest_t;

/*
 *	States for stream based attribute encoders
 */
typedef enum {
	READ_STATE_INIT	= 0,
	READ_STATE_ATTR_BEGIN,
	READ_STATE_ATTR_CONT,
	READ_STATE_ATTR_END,
	READ_STATE_END,
} read_state_t;

/*
 *	States for the response parser
 */
typedef enum {
	WRITE_STATE_INIT = 0,
	WRITE_STATE_PARSE_HEADERS,
	WRITE_STATE_PARSE_CONTENT,
	WRITE_STATE_DISCARD,
} write_state_t;

/*
 *	Outbound data context (passed to CURLOPT_READFUNCTION as CURLOPT_READDATA)
 */
typedef struct rlm_rest_request_t {
	rlm_rest_t		*instance;	//!< This instance of rlm_rest.
	REQUEST			*request;	//!< Current request.
	read_state_t		state;		//!< Encoder state

	vp_cursor_t		cursor;		//!< Cursor pointing to the start of the list to encode.

	size_t			chunk;		//!< Chunk size

	rlm_rest_section_t *section;	//!< Configuration data

	void			*encoder;	//!< Encoder specific data.
} rlm_rest_request_t;

/*
 *	Curl inbound data context (passed to CURLOPT_WRITEFUNCTION and
 *	CURLOPT_HEADERFUNCTION as CURLOPT_WRITEDATA and CURLOPT_HEADERDATA)
 */
typedef struct rlm_rest_response_t {
	rlm_rest_t		*instance;	//!< This instance of rlm_rest.
	REQUEST			*request;	//!< Current request.
	write_state_t		state;		//!< Decoder state.

	char 			*buffer;	//!< Raw incoming HTTP data.
	size_t		 	alloc;		//!< Space allocated for buffer.
	size_t		 	used;		//!< Space used in buffer.

	int		 	code;		//!< HTTP Status Code.
	http_body_type_t	type;		//!< HTTP Content Type.
	http_body_type_t	force_to;	//!< Force decoding the body type as a particular encoding.

	void			*decoder;	//!< Decoder specific data.
} rlm_rest_response_t;

/*
 *	Curl context data
 */
typedef struct rlm_rest_curl_context_t {
	struct curl_slist	*headers;	//!< Any HTTP headers which will be sent with the
						//!< request.

	char			*body;		//!< Pointer to the buffer which contains body data/
						//!< Only used when not performing chunked encoding.

	rlm_rest_request_t	request;	//!< Request context data.
	rlm_rest_response_t	response;	//!< Response context data.
} rlm_rest_curl_context_t;

/*
 *	Connection API handle
 */
typedef struct rlm_rest_handle_t {
	void			*handle;	//!< Real Handle.
	rlm_rest_curl_context_t	*ctx;		//!< Context.
} rlm_rest_handle_t;

/*
 *	Function prototype for rest_read_wrapper. Matches CURL's
 *	CURLOPT_READFUNCTION prototype.
 */
typedef size_t (*rest_read_t)(void *ptr, size_t size, size_t nmemb,
			      void *userdata);

/*
 *	Connection API callbacks
 */
int rest_init(rlm_rest_t *instance);

void rest_cleanup(void);

void *mod_conn_create(TALLOC_CTX *ctx, void *instance);

int mod_conn_alive(void *instance, void *handle);

/*
 *	Request processing API
 */
int rest_request_config(rlm_rest_t *instance,
			rlm_rest_section_t *section, REQUEST *request,
			void *handle, http_method_t method,
			http_body_type_t type, char const *uri,
			char const *username, char const *password) CC_HINT(nonnull (1,2,3,4,7));

int rest_request_perform(rlm_rest_t *instance,
			 rlm_rest_section_t *section, REQUEST *request,
			 void *handle);

int rest_response_decode(rlm_rest_t *instance,
			UNUSED rlm_rest_section_t *section, REQUEST *request,
			void *handle);

void rest_response_error(REQUEST *request, rlm_rest_handle_t *handle);

void rest_request_cleanup(rlm_rest_t *instance, rlm_rest_section_t *section,
			  void *handle);

#define rest_get_handle_code(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->response.code)

#define rest_get_handle_type(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->response.type)

size_t rest_get_handle_data(char const **out, rlm_rest_handle_t *handle);

/*
 *	Helper functions
 */
size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *raw, UNUSED void *arg);
ssize_t rest_uri_build(char **out, rlm_rest_t *instance, REQUEST *request, char const *uri);
ssize_t rest_uri_host_unescape(char **out, UNUSED rlm_rest_t *instance, REQUEST *request,
			       void *handle, char const *uri);