The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_ftp.c
Go to the documentation of this file.
1/*
2 * This program is 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 (at
5 * 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: afc8e1af85a698cca4b213f8f983326ecd80a642 $
19 * @file rlm_ftp.c
20 * @brief Fetch objects from FTP endpoints
21 *
22 * @copyright 2025 NetworkRADIUS SARL (legal@networkradius.com)
23 */
24RCSID("$Id: afc8e1af85a698cca4b213f8f983326ecd80a642 $")
25
26#include <freeradius-devel/curl/base.h>
27#include <freeradius-devel/curl/xlat.h>
28#include <freeradius-devel/server/base.h>
29
30#include <freeradius-devel/util/atexit.h>
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/util/uri.h>
33#include <freeradius-devel/unlang/xlat_func.h>
34
35#define FTP_BODY_ALLOC_CHUNK 1024
36
37typedef struct {
38 fr_curl_conn_config_t conn_config; //!< Configuration of slab allocated connection handles.
39 size_t max_resp_size; //!< Maximum size of incoming data.
40 bool binary; //!< Do we expect binary data - and so output octets.
41} rlm_ftp_t;
42
45
46typedef struct {
47 rlm_ftp_t const *inst; //!< Instance of rlm_ftp.
48 ftp_slab_list_t *slab; //!< Slab list for connection handles.
49 fr_curl_handle_t *mhandle; //!< Thread specific multi handle. Serves as the dispatch
50 //!< and coralling structure for FTP requests.
52
53typedef struct {
54 fr_curl_io_request_t *handle; //!< curl easy handle servicing our request.
56
57/*
58 * States for the response
59 */
65
66/*
67 * Curl inbound data context (passed to CURLOPT_WRITEFUNCTION as CURLOPT_WRITEDATA)
68 */
69typedef struct {
70 rlm_ftp_t const *instance; //!< This instance of rlm_ftp.
71
72 request_t *request; //!< Current request.
73 write_state_t state; //!< Decoder state.
74
75 char *buffer; //!< Raw incoming FTP data.
76 size_t alloc; //!< Space allocated for buffer.
77 size_t used; //!< Space used in buffer.
79
80/*
81 * Curl context data
82 */
83typedef struct {
84 rlm_ftp_response_t response; //!< Response context data.
86
87static int ftp_uri_part_escape(fr_value_box_t *vb, void *uctx);
88
89static fr_uri_part_t const ftp_uri_parts[] = {
90 { .name = "scheme", .safe_for = CURL_URI_SAFE_FOR, .terminals = &FR_SBUFF_TERMS(L(":")), .part_adv = { [':'] = 1 }, .extra_skip = 2 },
91 { .name = "host", .safe_for = CURL_URI_SAFE_FOR, .terminals = &FR_SBUFF_TERMS(L(":"), L("/")), .part_adv = { [':'] = 1, ['/'] = 2 }, .func = ftp_uri_part_escape },
92 { .name = "port", .safe_for = CURL_URI_SAFE_FOR, .terminals = &FR_SBUFF_TERMS(L("/")), .part_adv = { ['/'] = 1 } },
93 { .name = "method", .safe_for = CURL_URI_SAFE_FOR, .func = ftp_uri_part_escape },
95};
96
97static const conf_parser_t module_config[] = {
98 { FR_CONF_OFFSET_TYPE_FLAGS("max_resp_size", FR_TYPE_SIZE, 0, rlm_ftp_t, max_resp_size), .dflt = "16k" },
99 { FR_CONF_OFFSET("binary", rlm_ftp_t, binary), .dflt = "no" },
100
101 { FR_CONF_OFFSET_SUBSECTION("connection", 0, rlm_ftp_t, conn_config, fr_curl_conn_config) },
102
104};
105
106extern global_lib_autoinst_t const * const rlm_ftp_lib[];
111
112/** URL escape a single box forming part of a URL
113 *
114 * @param[in] vb to escape
115 * @param[in] uctx UNUSED context containing CURL handle
116 * @return
117 * - 0 on success
118 * - -1 on failure
119 */
120static int ftp_uri_part_escape(fr_value_box_t *vb, UNUSED void *uctx)
121{
122 char *escaped;
123 size_t len;
124
125 escaped = curl_easy_escape(fr_curl_tmp_handle(), vb->vb_strvalue, vb->vb_length);
126 if (!escaped) return -1;
127
128 len = strlen(escaped);
129
130 /*
131 * Returned string the same length - nothing changed
132 */
133 if (len != vb->vb_length) {
134 MEM(fr_value_box_bstrndup(vb, vb, NULL, escaped, len, false) >= 0);
135 }
136
137 curl_free(escaped);
138
139 return 0;
140}
141
142static xlat_action_t ftp_get_xlat_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx,
143 UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
144{
145 rlm_ftp_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_ftp_t);
146 rlm_ftp_xlat_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, rlm_ftp_xlat_rctx_t);
147 fr_curl_io_request_t *handle = talloc_get_type_abort(rctx->handle, fr_curl_io_request_t);
148 rlm_ftp_curl_context_t *curl_ctx = talloc_get_type_abort(handle->uctx, rlm_ftp_curl_context_t);
150
151 switch (curl_ctx->response.state) {
152 case WRITE_STATE_INIT:
154 xa = XLAT_ACTION_FAIL;
155 goto finish;
156
158 break;
159 }
160
161 if (curl_ctx->response.used > 0) {
162 fr_value_box_t *vb;
163
164 MEM(vb = fr_value_box_alloc_null(ctx));
165 if (inst->binary) {
166 fr_value_box_memdup(vb, vb, NULL, (uint8_t *)curl_ctx->response.buffer, curl_ctx->response.used, true);
167 } else {
168 fr_value_box_bstrndup(vb, vb, NULL, curl_ctx->response.buffer, curl_ctx->response.used, true);
169 }
171 }
172
173finish:
174 ftp_slab_release(handle);
175 talloc_free(rctx);
176
177 return xa;
178}
179
180static void ftp_io_xlat_signal(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_signal_t action)
181{
182 rlm_ftp_thread_t *t = talloc_get_type_abort(xctx->mctx->thread, rlm_ftp_thread_t);
183 rlm_ftp_xlat_rctx_t *our_rctx = talloc_get_type_abort(xctx->rctx, rlm_ftp_xlat_rctx_t);
184 fr_curl_io_request_t *randle = talloc_get_type_abort(our_rctx->handle, fr_curl_io_request_t);
185 CURLMcode ret;
186
187 RDEBUG2("Forcefully cancelling pending FTP request");
188
189 ret = curl_multi_remove_handle(t->mhandle->mandle, randle->candle); /* Gracefully terminate the request */
190 if (ret != CURLM_OK) {
191 RERROR("Failed removing curl handle from multi-handle: %s (%i)", curl_multi_strerror(ret), ret);
192 /* Not much we can do */
193 }
194 t->mhandle->transfers--;
195
196 ftp_slab_release(randle);
197}
198
199
200static size_t ftp_response_body(void *in, size_t size, size_t nmemb, void *userdata)
201{
202 rlm_ftp_response_t *ctx = userdata;
203 request_t *request = ctx->request; /* Used by RDEBUG */
204
205 char const *start = in, *end = start + (size * nmemb);
206 char *out;
207 size_t needed, chunk_len, total;
208
209 /*
210 * Get how much data we're being asked to write now, and the total amount of data we've written.
211 */
212 chunk_len = (size_t) (end - start);
213 total = ctx->used + chunk_len;
214
215 if (!chunk_len) return 0; /* Nothing to process */
216
217 /*
218 * We had previously decided to discard the writes, just tell curl "yes, we wrote it all".
219 */
220 if (ctx->state == WRITE_STATE_DISCARD) return chunk_len;
221
222 /*
223 * We're being asked to write too much data, free the buffer and discard all of the data.
224 */
225 if (total > ctx->instance->max_resp_size) {
226 REDEBUG("Incoming data (%zu bytes) exceeds max_body_in (%zu bytes). Forcing discard",
227 total, ctx->instance->max_resp_size);
229 TALLOC_FREE(ctx->buffer);
230 ctx->alloc = 0;
231 ctx->used = 0;
232 return chunk_len;
233 }
234
235 /*
236 * If there's no buffer, then we can't have used any part of the buffer.
237 */
238 fr_assert(ctx->buffer || !ctx->used);
239
240 /*
241 * Ensure that there's enough room in the buffer for all of the data that we need to write.
242 */
243 needed = ROUND_UP(total, FTP_BODY_ALLOC_CHUNK);
244 if (needed > ctx->alloc) {
245 MEM(ctx->buffer = talloc_bstr_realloc(NULL, ctx->buffer, needed));
246 ctx->alloc = needed;
247 }
248
249 out = ctx->buffer + ctx->used;
250 memcpy(out, start, chunk_len);
251 ctx->used = total;
252 ctx->buffer[ctx->used] = '\0';
253
254 return chunk_len;
255}
256
257
259 { .required = true, .safe_for = CURL_URI_SAFE_FOR, .type = FR_TYPE_STRING, .will_escape = true }, /* URL */
261};
262
263/** Simple xlat to read data from an FTP URI
264 *
265 * Example:
266@verbatim
267%ftp.get('ftp://example.com/file.txt')
268@endverbatim
269 *
270 * @ingroup xlat_functions
271 */
273 xlat_ctx_t const *xctx, request_t *request,
274 fr_value_box_list_t *in)
275{
276 rlm_ftp_thread_t *t = talloc_get_type_abort(xctx->mctx->thread, rlm_ftp_thread_t);
277 fr_curl_io_request_t *randle = NULL;
278 int ret;
279 fr_value_box_t *uri_vb;
280 rlm_ftp_curl_context_t *curl_ctx;
282
283 XLAT_ARGS(in, &uri_vb);
284
285 MEM(rctx = talloc(request, rlm_ftp_xlat_rctx_t));
286
287 /*
288 * Handle URI component escaping
289 */
290 if (fr_uri_escape_list(&uri_vb->vb_group, ftp_uri_parts, NULL) < 0) {
291 RPEDEBUG("Failed escaping URI");
292 error:
293 return XLAT_ACTION_FAIL;
294 }
295
297 uri_vb, &uri_vb->vb_group, FR_TYPE_STRING,
299 SIZE_MAX) < 0) {
300 REDEBUG("Concatenating URI");
301 goto error;
302 }
303
304 /*
305 * We get a connection from the pool here as the CURL object
306 * is needed to use curl_easy_escape() for escaping
307 */
308 randle = rctx->handle = ftp_slab_reserve(t->slab);
309 if (!randle) return XLAT_ACTION_FAIL;
310
311 randle->request = request; /* Populate the request pointer for escape callbacks */
312 curl_ctx = talloc_get_type_abort(randle->uctx, rlm_ftp_curl_context_t);
313 curl_ctx->response.request = request;
314
315 RDEBUG2("Sending FTP GET to \"%pV\"", uri_vb);
316
317 /*
318 * Configure various CURL options, and initialise the read/write
319 * context data.
320 */
321 FR_CURL_REQUEST_SET_OPTION(CURLOPT_URL, uri_vb->vb_strvalue);
322#if CURL_AT_LEAST_VERSION(7,85,0)
323 FR_CURL_REQUEST_SET_OPTION(CURLOPT_PROTOCOLS_STR, "ftp");
324#else
325 FR_CURL_REQUEST_SET_OPTION(CURLOPT_PROTOCOLS, CURLPROTO_FTP);
326#endif
327 FR_CURL_REQUEST_SET_OPTION(CURLOPT_WRITEFUNCTION, ftp_response_body);
328 FR_CURL_REQUEST_SET_OPTION(CURLOPT_WRITEDATA, &curl_ctx->response);
329
330 /*
331 * Send the CURL request
332 */
333 ret = fr_curl_io_request_enqueue(t->mhandle, request, randle);
334 if (ret < 0) {
335 ftp_slab_release(randle);
336 goto error;
337 }
338
340}
341
342/** Cleans up after a FTP request.
343 *
344 * Resets all options associated with a CURL handle, and frees any headers
345 * associated with it.
346 *
347 * Calls ftp_read_ctx_free and ftp_response_free to free any memory used by
348 * context data.
349 *
350 * @param[in] randle to cleanup.
351 * @param[in] uctx unused.
352 */
353static int _ftp_request_cleanup(fr_curl_io_request_t *randle, UNUSED void *uctx)
354{
355 rlm_ftp_curl_context_t *ctx = talloc_get_type_abort(randle->uctx, rlm_ftp_curl_context_t);
356 CURL *candle = randle->candle;
357
358 /*
359 * Clear any previously configured options
360 */
361 curl_easy_reset(candle);
362
363#ifndef NDEBUG
364 {
365 CURLcode ret;
366 /*
367 * With curl 7.61 when a request in cancelled we get a result
368 * with a NULL (invalid) pointer to private data. This lets
369 * us know that the request was returned to the slab.
370 */
371 ret = curl_easy_setopt(candle, CURLOPT_PRIVATE, (void *)0xdeadc341);
372 if (unlikely(ret != CURLE_OK)) {
373 ERROR("Failed to set private data on curl easy handle %p: %s",
374 candle, curl_easy_strerror(ret));
375 }
376 }
377#endif
378
379 /*
380 * Free response data
381 */
382 TALLOC_FREE(ctx->response.buffer);
383 ctx->response.alloc = 0;
384 ctx->response.used = 0;
385
386 randle->request = NULL;
387 return 0;
388}
389
391{
392 curl_easy_cleanup(randle->candle);
393 return 0;
394}
395
396static int ftp_conn_alloc(fr_curl_io_request_t *randle, void *uctx)
397{
398 rlm_ftp_t const *inst = talloc_get_type_abort(uctx, rlm_ftp_t);
399 rlm_ftp_curl_context_t *curl_ctx = NULL;
400
401 randle->candle = curl_easy_init();
402 if (unlikely(!randle->candle)) {
403 fr_strerror_printf("Unable to initialise CURL handle");
404 return -1;
405 }
406
407 MEM(curl_ctx = talloc_zero(randle, rlm_ftp_curl_context_t));
408 curl_ctx->response.instance = inst;
409
410 randle->uctx = curl_ctx;
411 talloc_set_destructor(randle, _mod_conn_free);
412
413 ftp_slab_element_set_destructor(randle, _ftp_request_cleanup, NULL);
414
415 return 0;
416}
417
418/** Create a thread specific multihandle
419 *
420 * Easy handles representing requests are added to the curl multihandle
421 * with the multihandle used for mux/demux.
422 *
423 * @param[in] mctx Thread instantiation data.
424 * @return
425 * - 0 on success.
426 * - -1 on failure.
427 */
429{
430 rlm_ftp_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_ftp_t);
431 rlm_ftp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_ftp_thread_t);
432 fr_curl_handle_t *mhandle;
433
434 t->inst = inst;
435
436 if (!(t->slab = ftp_slab_list_alloc(t, mctx->el, &inst->conn_config.reuse,
437 ftp_conn_alloc, NULL, inst, false, false))) {
438 ERROR("Connection handle pool instantiation failed");
439 return -1;
440 }
441
442 mhandle = fr_curl_io_init(t, mctx->el, false);
443 if (!mhandle) return -1;
444
445 t->mhandle = mhandle;
446
447 return 0;
448}
449
450/** Cleanup all outstanding requests associated with this thread
451 *
452 * Destroys all curl easy handles, and then the multihandle associated
453 * with this thread.
454 *
455 * @param[in] mctx data to destroy.
456 * @return 0
457 */
459{
460 rlm_ftp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_ftp_thread_t);
461
462 talloc_free(t->mhandle); /* Ensure this is shutdown before the pool */
463 talloc_free(t->slab);
464
465 return 0;
466}
467
468static int mod_bootstrap(module_inst_ctx_t const *mctx)
469{
470 xlat_t *xlat;
471 rlm_ftp_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_ftp_t);
472
473 if (unlikely(!(xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "get", ftp_get_xlat,
474 inst->binary ? FR_TYPE_OCTETS : FR_TYPE_STRING)))) return -1;
476
477 return 0;
478}
479
480static int mod_instantiate(module_inst_ctx_t const *mctx)
481{
482 rlm_ftp_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_ftp_t);
483
484 inst->conn_config.reuse.num_children = 1;
485 inst->conn_config.reuse.child_pool_size = sizeof(rlm_ftp_curl_context_t);
486
487 return 0;
488}
489
490/*
491 * The module name should be the only globally exported symbol.
492 * That is, everything else should be 'static'.
493 *
494 * If the module needs to temporarily modify it's instantiation
495 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
496 * The server will then take care of ensuring that the module
497 * is single-threaded.
498 */
499extern module_rlm_t rlm_ftp;
501 .common = {
502 .magic = MODULE_MAGIC_INIT,
503 .name = "ftp",
504 .inst_size = sizeof(rlm_ftp_t),
505 .thread_inst_size = sizeof(rlm_ftp_thread_t),
506 .config = module_config,
507 .bootstrap = mod_bootstrap,
508 .instantiate = mod_instantiate,
509 .thread_instantiate = mod_thread_instantiate,
510 .thread_detach = mod_thread_detach
511 },
512 .method_group = {
513 .bindings = (module_method_binding_t[]){
515 }
516 }
517};
#define RCSID(id)
Definition build.h:506
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:228
#define unlikely(_x)
Definition build.h:402
#define UNUSED
Definition build.h:336
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:657
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:280
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
Definition cf_parse.h:309
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:238
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:594
fr_curl_handle_t * fr_curl_io_init(TALLOC_CTX *ctx, fr_event_list_t *el, bool multiplex)
#define FR_CURL_REQUEST_SET_OPTION(_x, _y)
Definition base.h:67
uint64_t transfers
How many transfers are current in progress.
Definition base.h:94
CURLM * mandle
The multi handle.
Definition base.h:95
request_t * request
Current request.
Definition base.h:104
void * uctx
Private data for the module using the API.
Definition base.h:105
int fr_curl_io_request_enqueue(fr_curl_handle_t *mhandle, request_t *request, fr_curl_io_request_t *creq)
Sends a request using libcurl.
Definition io.c:478
CURL * candle
Request specific handle.
Definition base.h:102
Uctx data for timer and I/O functions.
Definition base.h:91
Structure representing an individual request being passed to curl for processing.
Definition base.h:101
#define CURL_URI_SAFE_FOR
safe for value suitable for all users of the curl library
Definition xlat.h:36
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition dcursor.h:435
#define MEM(x)
Definition debug.h:46
#define ERROR(fmt,...)
Definition dhcpclient.c:40
static fr_slen_t in
Definition dict.h:882
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
#define GLOBAL_LIB_TERMINATOR
Definition global_lib.h:51
Structure to define how to initialise libraries with global configuration.
Definition global_lib.h:38
static xlat_action_t ftp_get_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Simple xlat to read data from an FTP URI.
Definition rlm_ftp.c:272
talloc_free(hp)
global_lib_autoinst_t fr_curl_autoinst
Definition base.c:396
CURL * fr_curl_tmp_handle(void)
Return a thread local curl easy handle.
Definition base.c:276
conf_parser_t fr_curl_conn_config[]
Definition base.c:97
#define RERROR(fmt,...)
Definition log.h:310
#define RPEDEBUG(fmt,...)
Definition log.h:388
#define ROUND_UP(_num, _mul)
Round up - Works in all cases, but is slower.
Definition math.h:206
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_OCTETS
Raw octets.
unsigned char uint8_t
unsigned long int size_t
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
fr_event_list_t * el
Event list to register any IO handlers and timers against.
Definition module_ctx.h:68
void * thread
Thread instance data.
Definition module_ctx.h:67
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:64
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
Temporary structure to hold arguments for thread_instantiation calls.
Definition module_ctx.h:63
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Definition module_rlm.c:247
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RDEBUG2(fmt,...)
static int ftp_uri_part_escape(fr_value_box_t *vb, void *uctx)
static int _ftp_request_cleanup(fr_curl_io_request_t *randle, UNUSED void *uctx)
Cleans up after a FTP request.
Definition rlm_ftp.c:353
size_t used
Space used in buffer.
Definition rlm_ftp.c:77
static fr_uri_part_t const ftp_uri_parts[]
Definition rlm_ftp.c:89
fr_curl_handle_t * mhandle
Thread specific multi handle.
Definition rlm_ftp.c:49
static size_t ftp_response_body(void *in, size_t size, size_t nmemb, void *userdata)
Definition rlm_ftp.c:200
static void ftp_io_xlat_signal(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_signal_t action)
Definition rlm_ftp.c:180
bool binary
Do we expect binary data - and so output octets.
Definition rlm_ftp.c:40
request_t * request
Current request.
Definition rlm_ftp.c:72
fr_curl_io_request_t * handle
curl easy handle servicing our request.
Definition rlm_ftp.c:54
static int ftp_conn_alloc(fr_curl_io_request_t *randle, void *uctx)
Definition rlm_ftp.c:396
write_state_t state
Decoder state.
Definition rlm_ftp.c:73
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_ftp.c:468
size_t max_resp_size
Maximum size of incoming data.
Definition rlm_ftp.c:39
size_t alloc
Space allocated for buffer.
Definition rlm_ftp.c:76
static xlat_arg_parser_t const ftp_get_xlat_args[]
Definition rlm_ftp.c:258
global_lib_autoinst_t const *const rlm_ftp_lib[]
Definition rlm_ftp.c:107
char * buffer
Raw incoming FTP data.
Definition rlm_ftp.c:75
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Create a thread specific multihandle.
Definition rlm_ftp.c:428
fr_curl_conn_config_t conn_config
Configuration of slab allocated connection handles.
Definition rlm_ftp.c:38
rlm_ftp_t const * instance
This instance of rlm_ftp.
Definition rlm_ftp.c:70
rlm_ftp_t const * inst
Instance of rlm_ftp.
Definition rlm_ftp.c:47
write_state_t
Definition rlm_ftp.c:60
@ WRITE_STATE_INIT
Definition rlm_ftp.c:61
@ WRITE_STATE_DISCARD
Definition rlm_ftp.c:63
@ WRITE_STATE_POPULATED
Definition rlm_ftp.c:62
module_rlm_t rlm_ftp
Definition rlm_ftp.c:500
static const conf_parser_t module_config[]
Definition rlm_ftp.c:97
rlm_ftp_response_t response
Response context data.
Definition rlm_ftp.c:84
static int _mod_conn_free(fr_curl_io_request_t *randle)
Definition rlm_ftp.c:390
#define FTP_BODY_ALLOC_CHUNK
Definition rlm_ftp.c:35
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Cleanup all outstanding requests associated with this thread.
Definition rlm_ftp.c:458
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_ftp.c:480
ftp_slab_list_t * slab
Slab list for connection handles.
Definition rlm_ftp.c:48
static xlat_action_t ftp_get_xlat_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
Definition rlm_ftp.c:142
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition sbuff.h:190
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:293
void * boot
Data allocated during the boostrap phase.
Definition module.h:296
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:152
Named methods exported by a module.
Definition module.h:174
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
#define FR_SLAB_FUNCS(_name, _type)
Define type specific wrapper functions for slabs and slab elements.
Definition slab.h:124
#define FR_SLAB_TYPES(_name, _type)
Define type specific wrapper structs for slabs and slab elements.
Definition slab.h:75
eap_aka_sim_process_conf_t * inst
char * talloc_bstr_realloc(TALLOC_CTX *ctx, char *in, size_t inlen)
Trim a bstr (char) buffer.
Definition talloc.c:681
xlat_action_t unlang_xlat_yield(request_t *request, xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition xlat.c:543
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:383
unsigned int required
Argument must be present, and non-empty.
Definition xlat.h:146
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:170
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumed by an xlat function.
Definition xlat.h:145
int fr_uri_escape_list(fr_value_box_list_t *uri, fr_uri_part_t const *uri_parts, void *uctx)
Parse a list of value boxes representing a URI.
Definition uri.c:140
#define XLAT_URI_PART_TERMINATOR
Definition uri.h:66
char const * name
Name of this part of the URI.
Definition uri.h:47
Definition for a single part of a URI.
Definition uri.h:46
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition value.c:4823
int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Copy a buffer to a fr_value_box_t.
Definition value.c:5064
int fr_value_box_list_concat_in_place(TALLOC_CTX *ctx, fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type, fr_value_box_list_action_t proc_action, bool flatten, size_t max_size)
Concatenate a list of value boxes.
Definition value.c:6585
@ FR_VALUE_BOX_LIST_FREE
Definition value.h:238
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:655
static size_t char ** out
Definition value.h:1030
void * rctx
Resume context.
Definition xlat_ctx.h:54
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition xlat_ctx.h:52
An xlat calling ctx.
Definition xlat_ctx.h:49
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:363