The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_smtp.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: 6cfd79a6bc24f0a3dcf105023be31afad24689c2 $
19 * @file rlm_smtp.c
20 * @brief smtp server authentication.
21 *
22 * @copyright 2020 The FreeRADIUS server project
23 * @copyright 2020 Network RADIUS SAS (legal@networkradius.com)
24 */
25RCSID("$Id: 6cfd79a6bc24f0a3dcf105023be31afad24689c2 $")
26
27#include <freeradius-devel/curl/base.h>
28#include <freeradius-devel/server/base.h>
29#include <freeradius-devel/server/cf_priv.h>
30#include <freeradius-devel/server/global_lib.h>
31#include <freeradius-devel/server/module_rlm.h>
32#include <freeradius-devel/server/tmpl_dcursor.h>
33#include <freeradius-devel/util/slab.h>
34#include <freeradius-devel/util/token.h>
35
36#include <freeradius-devel/unlang/call_env.h>
37#include <freeradius-devel/unlang/xlat_func.h>
38
40
43 { .out = &dict_freeradius, .proto = "freeradius"},
44 { NULL }
45};
46
49
52 { .out = &attr_smtp_header, .name = "SMTP-Mail-Header", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
53 { .out = &attr_smtp_body, .name = "SMTP-Mail-Body", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
54 { NULL },
55};
56
57extern global_lib_autoinst_t const * const rlm_smtp_lib[];
62
63/** Call environment for sending emails.
64*/
65typedef struct {
66 fr_value_box_t username; //!< User to authenticate as when sending emails.
67 tmpl_t *username_tmpl; //!< The tmpl used to produce the above.
68 fr_value_box_t password; //!< Password for authenticated mails.
69 fr_value_box_list_t *sender_address; //!< The address(es) used to generate the From: header
70 fr_value_box_list_t *recipient_addrs; //!< The address(es) used as recipients. Overrides elements in to, cc and bcc
71 fr_value_box_list_t *to_addrs; //!< The address(es) used for the To: header.
72 fr_value_box_list_t *cc_addrs; //!< The address(es) used for the Cc: header.
73 fr_value_box_list_t *bcc_addrs; //!< The address(es) used for the Bcc: header.
74 fr_value_box_list_t *attachments; //!< List of files to attach.
75 fr_value_box_list_t headers; //!< Entries to add to email header.
77
78/** Call environment for SMTP authentication
79 */
80typedef struct {
81 fr_value_box_t username; //!< Value to use for user name
82 tmpl_t *username_tmpl; //!< tmpl expanded to populate username
83 fr_value_box_t password; //!< Value to use for password
84 tmpl_t *password_tmpl; //!< tmpl expanded to populate password
86
87/** Call environment for sending simple emails using an xlat.
88*/
89typedef struct {
90 fr_value_box_t username; //!< User to authenticate as when sending emails.
91 tmpl_t *username_tmpl; //!< The tmpl used to produce the above.
92 fr_value_box_t password; //!< Password for authenticated mails.
93 fr_value_box_list_t *sender_address; //!< The address(es) used to generate the From: header
94 fr_value_box_list_t headers; //!< Entries to add to email header.
96
97static int smtp_header_section_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, tmpl_rules_t const *t_rules,
98 CONF_ITEM *ci, call_env_ctx_t const *cec, call_env_parser_t const *rule);
99
112
113typedef struct {
114 char const *uri; //!< URI of smtp server
115 char const *template_dir; //!< The directory that contains all email attachments
116 char const *envelope_address; //!< The address used to send the message
117
118 fr_time_delta_t timeout; //!< Timeout for connection and server response
119 fr_curl_tls_t tls; //!< Used for handled all tls specific curl components
120
122
123 fr_curl_conn_config_t conn_config; //!< Reusable CURL handle config
124} rlm_smtp_t;
125
126/*
127 * A mapping of configuration file names to internal variables.
128 */
129static const conf_parser_t module_config[] = {
130 { FR_CONF_OFFSET("uri", rlm_smtp_t, uri) },
131 { FR_CONF_OFFSET("template_directory", rlm_smtp_t, template_dir) },
132 { FR_CONF_OFFSET("envelope_address", rlm_smtp_t, envelope_address) },
133 { FR_CONF_OFFSET("timeout", rlm_smtp_t, timeout) },
134 { FR_CONF_OFFSET("set_date", rlm_smtp_t, set_date), .dflt = "yes" },
135 { FR_CONF_OFFSET_SUBSECTION("tls", 0, rlm_smtp_t, tls, fr_curl_tls_config) },//!<loading the tls values
136 { FR_CONF_OFFSET_SUBSECTION("connection", 0, rlm_smtp_t, conn_config, fr_curl_conn_config) },
138};
139
140/*
141 * Two types of SMTP connections are used:
142 * - persistent - where the connection can be left established as the same
143 * authentication is used for all mails sent.
144 * - onetime - where the connection is torn down after each use, since
145 * different authentication is needed each time.
146 *
147 * Memory for the handles for each is stored in slabs.
148 */
149
152
153typedef struct {
154 fr_curl_handle_t *mhandle; //!< Thread specific multi handle. Serves as the dispatch and
155 ///< coralling structure for smtp requests
156 smtp_slab_list_t *slab_persist; //!< Slab list for persistent connections.
157 smtp_slab_list_t *slab_onetime; //!< Slab list for onetime use connections.
159
160/*
161 * Holds the context for parsing the email elements
162 */
163typedef struct {
169
170 struct curl_slist *recipients;
171 struct curl_slist *header;
172 struct curl_slist *body_header;
173
175 char time_str[60];
176 curl_mime *mime;
178
179/*
180 * Adds every element associated with a dict_attr to a curl_slist
181 */
182static int da_to_slist(fr_mail_ctx_t *uctx, struct curl_slist **out, const fr_dict_attr_t *dict_attr)
183{
184 request_t *request = ((fr_mail_ctx_t *)uctx)->request;
185 fr_pair_t *vp;
186 int elems_added = 0;
187
188 /* Iterate over the VP and add the string value to the curl_slist */
189 vp = fr_pair_dcursor_by_da_init(&uctx->cursor, &uctx->request->request_pairs, dict_attr);
190
191 while (vp) {
192 *out = curl_slist_append(*out, vp->vp_strvalue);
193 vp = fr_dcursor_next(&uctx->cursor);
194 elems_added++;
195 }
196
197 if (!elems_added) RDEBUG3("There were no %s elements found", dict_attr->name);
198
199 return elems_added;
200}
201
202/** Transform an array of value box lists to entries in a CURL slist
203 *
204 */
205static int value_box_list_to_slist(struct curl_slist **out, fr_value_box_list_t const *lists)
206{
207 fr_value_box_list_t const *list = lists;
208 fr_value_box_t *vb = NULL;
209 int count = 0;
210 size_t i, list_count = talloc_array_length(lists);
211
212 for (i = 0; i < list_count; i++) {
213 while ((vb = fr_value_box_list_next(list, vb))) {
214 *out = curl_slist_append(*out, vb->vb_strvalue);
215 count ++;
216 }
217 list++;
218 }
219
220 return count;
221}
222
223/** Converts an array of value box lists to a curl_slist with a prefix
224 *
225 * @param uctx Mail context.
226 * @param out CURL slist to write to.
227 * @param lists Array of value box lists to copy.
228 * @param prefix to prepend to the output slist
229 * @return
230 * - 1 on success
231 * - 0 if no slist entry was created
232 * - -1 on failure
233 */
234static int value_box_list_to_header(fr_mail_ctx_t *uctx, struct curl_slist **out, fr_value_box_list_t const *lists,
235 const char *prefix)
236{
237 request_t *request = uctx->request;
238 fr_sbuff_t sbuff;
239 fr_sbuff_uctx_talloc_t sbuff_ctx;
240 bool added = false;
241 fr_value_box_t *vb = NULL;
242 fr_value_box_list_t const *list = lists;
243 size_t i, list_count = talloc_array_length(lists);
244
245 fr_sbuff_init_talloc(uctx, &sbuff, &sbuff_ctx, 256, SIZE_MAX);
246 (void) fr_sbuff_in_strcpy(&sbuff, prefix);
247
248 for (i = 0; i < list_count; i++) {
249 while ((vb = fr_value_box_list_next(list, vb))) {
250 /* If there are already values added, add the comma separator */
251 if (added) {
252 if (unlikely(fr_sbuff_in_strcpy(&sbuff, ", ") < 0)) {
253 error:
254 talloc_free(fr_sbuff_buff(&sbuff));
255 return -1;
256 }
257 }
258
259 if ((vb->type != FR_TYPE_STRING) && (fr_value_box_cast_in_place(vb, vb, FR_TYPE_STRING, NULL) < 0)) {
260 RERROR("Failed casting %pV to string", vb);
261 goto error;
262 }
263
264 if (unlikely(fr_sbuff_in_strcpy(&sbuff, vb->vb_strvalue) < 0)) goto error;
265 added = true;
266 }
267 list++;
268 }
269
270 if (!added) {
271 RDEBUG2("No values to add to \"%s\" header", prefix);
272 talloc_free(fr_sbuff_buff(&sbuff));
273 return 0;
274 }
275
276 /* Add the generated buffer the the curl_slist */
277 *out = curl_slist_append(*out, fr_sbuff_buff(&sbuff));
278 talloc_free(fr_sbuff_buff(&sbuff));
279 return 1;
280}
281
282/*
283 * Takes a string value and adds it as a file path to upload as an attachment
284 */
285static int str_to_attachments(fr_mail_ctx_t *uctx, curl_mime *mime, char const * str, size_t len,
286 fr_sbuff_t *path_buffer, fr_sbuff_marker_t *m)
287{
288 request_t *request = uctx->request;
289 curl_mimepart *part;
290
291 /* Move to the end of the template directory filepath */
292 fr_sbuff_set(path_buffer, m);
293
294 /* Check to see if the file attachment is valid, skip it if not */
295 RDEBUG2("Trying to set attachment: %s", str);
296
297 if (*str == '/') {
298 RDEBUG2("File attachments cannot be an absolute path");
299 return 0;
300 }
301
302 if (strncmp(str, "..", 2) == 0) {
303 RDEBUG2("Cannot access values outside of template_directory");
304 return 0;
305 }
306
307 /* Copy the filename into the buffer */
308 if (fr_sbuff_in_bstrncpy(path_buffer, str, len) < 0) {
309 RDEBUG2("Cannot copy filename");
310 return 0;
311 }
312
313 /* Add the file attachment as a mime encoded part */
314 part = curl_mime_addpart(mime);
315 curl_mime_encoder(part, "base64");
316 if (curl_mime_filedata(part, path_buffer->buff) != CURLE_OK) {
317 REDEBUG2("Cannot add file attachment");
318 return 0;
319 }
320
321 return 1;
322}
323
324/** Generate the `From:` header
325 *
326 * Defaults to using `sender_address` values, falls back to `envelope_address`
327 */
328static int generate_from_header(fr_mail_ctx_t *uctx, struct curl_slist **out, rlm_smtp_t const *inst,
329 rlm_smtp_env_t const *call_env)
330{
331 fr_sbuff_t sbuff;
332 fr_sbuff_uctx_talloc_t sbuff_ctx;
333
334 if (call_env->sender_address) return value_box_list_to_header(uctx, &uctx->header, call_env->sender_address, "From: ");
335
336 /* Initialize the buffer for the recipients. Used for FROM */
337 fr_sbuff_init_talloc(uctx, &sbuff, &sbuff_ctx, 256, SIZE_MAX);
338
339 /* Add the preposition for the header element */
340 (void) fr_sbuff_in_strcpy(&sbuff, "From: ");
341
342 /* Copy the envelope address as the From: source */
343 if (unlikely(fr_sbuff_in_bstrncpy(&sbuff, inst->envelope_address,
344 strlen(inst->envelope_address)) < 0)) {
345 talloc_free(fr_sbuff_buff(&sbuff));
346 return -1;
347 }
348
349 *out = curl_slist_append(*out, sbuff.buff);
350
351 /* Free the buffer used to generate the FROM header */
352 talloc_free(fr_sbuff_buff(&sbuff));
353
354 return 0;
355}
356
357/*
358 * Generates a curl_slist of recipients
359 */
360static int recipients_source(fr_mail_ctx_t *uctx, rlm_smtp_env_t const *call_env)
361{
362 request_t *request = uctx->request;
363 int recipients_set = 0;
364
365 /*
366 * Try to load the recipients into the envelope recipients if they are set
367 */
368 if(call_env->recipient_addrs) {
369 recipients_set += value_box_list_to_slist(&uctx->recipients, call_env->recipient_addrs);
370 }
371
372 /*
373 * If any recipients were found, ignore to cc and bcc, return the amount added.
374 **/
375 if (recipients_set) {
376 RDEBUG2("Recipients were generated from \"SMTP-Recipients\" and/or recipients in the config");
377 return recipients_set;
378 }
379 RDEBUG2("No addresses were found in \"SMTP-Recipients\"");
380
381 /*
382 * Try to load the to: addresses into the envelope recipients if they are set
383 */
384 if (call_env->to_addrs) recipients_set += value_box_list_to_slist(&uctx->recipients, call_env->to_addrs);
385
386 /*
387 * Try to load the cc: addresses into the envelope recipients if they are set
388 */
389 if (call_env->cc_addrs) recipients_set += value_box_list_to_slist(&uctx->recipients, call_env->cc_addrs);
390
391 /*
392 * Try to load the bcc: addresses into the envelope recipients if they are set
393 */
394 if (call_env->bcc_addrs) recipients_set += value_box_list_to_slist(&uctx->recipients, call_env->bcc_addrs);
395
396 RDEBUG2("%d recipients set", recipients_set);
397 return recipients_set;
398}
399
400/*
401 * Generates a curl_slist of header elements header elements
402 */
403static int header_source(fr_mail_ctx_t *uctx, rlm_smtp_t const *inst, rlm_smtp_env_t const *call_env)
404{
405 fr_sbuff_t time_out;
406 request_t *request = uctx->request;
407 fr_value_box_t *vb = NULL;
408
409 /*
410 * Load in all of the header elements supplied in the config
411 */
412 if (fr_value_box_list_initialised(&call_env->headers)) {
413 while ((vb = fr_value_box_list_next(&call_env->headers, vb))) {
414 RDEBUG2("Adding header \"%pV\"", vb);
415 uctx->header = curl_slist_append(uctx->header, vb->vb_strvalue);
416 }
417 }
418
419 /* Add the From: line */
420 if (unlikely(generate_from_header(uctx, &uctx->header, inst, call_env) < 0)) {
421 RDEBUG2("From: header could not be added");
422 return -1;
423 }
424
425 /* Add the TO: line if there is one provided in the request by SMTP-TO */
426 value_box_list_to_header(uctx, &uctx->header, call_env->to_addrs, "To: ");
427
428 /* Add the CC: line if there is one provided in the request by SMTP-CC */
429 value_box_list_to_header(uctx, &uctx->header, call_env->cc_addrs, "Cc: ");
430
431 /* Add all the generic header elements in the request */
432 da_to_slist(uctx, &uctx->header, attr_smtp_header);
433
434 /* If no header elements could be found, there is an error */
435 if (!uctx->header) {
436 RDEBUG2("Header elements could not be added");
437 return -1;
438 }
439
440 /* Set the DATE: to the time that the request was received */
441 if (inst->set_date) {
442 time_out = FR_SBUFF_OUT(uctx->time_str, sizeof(uctx->time_str));
443 fr_time_strftime_local(&time_out, fr_time(), "DATE: %a, %d %b %Y %T %z, (%Z) \r\n");
444 uctx->header = curl_slist_append(uctx->header, uctx->time_str);
445 }
446
447 RDEBUG2("Finished generating the curl_slist for the header elements");
448 return 0;
449}
450
451/*
452 * Add the Body elements to the email
453 */
454static size_t body_source(char *ptr, size_t size, size_t nmemb, void *mail_ctx)
455{
456 fr_mail_ctx_t *uctx = mail_ctx;
458 request_t *request = uctx->request;
459 fr_pair_t *vp;
460
461 fr_dbuff_init(&out, (uint8_t *)ptr, (size * nmemb)); /* Wrap the output buffer so we can track our position easily */
462
464 if (!vp) {
465 RWARN("vp could not be found for the body element");
466 return 0;
467 }
468
469 /*
470 * Copy the vp into the email. If it cannot all be
471 * loaded, return the amount of memory that was loaded
472 * and get called again.
473 */
474 if (fr_dbuff_in_memcpy_partial(&out, &uctx->vp_in, SIZE_MAX) < fr_dbuff_remaining(&uctx->vp_in)) {
475 RDEBUG3("%zu bytes used (partial copy)", fr_dbuff_used(&out));
476 return fr_dbuff_used(&out);
477 }
478
479 /*
480 * Once this value pair is fully copied, prepare for the next element
481 */
483 if (vp) {
484 fr_dbuff_init(&uctx->vp_in, (uint8_t const *)vp->vp_strvalue, vp->vp_length);
485
486 }
487
488 RDEBUG3("%zu bytes used (full copy)", fr_dbuff_used(&out));
489 return fr_dbuff_used(&out);
490}
491
492/*
493 * Initialize all the body elements to be uploaded later
494 */
495static int body_init(fr_mail_ctx_t *uctx, curl_mime *mime)
496{
497 fr_pair_t *vp;
498 request_t *request = uctx->request;
499
500 curl_mimepart *part;
501 curl_mime *mime_body;
502
503 int body_elements = 0;
504
505 /* Initialize a second mime to apply special conditions to the body elements */
506 MEM(mime_body = curl_mime_init(uctx->randle->candle));
507
508 /* initialize the cursor used by the body_source function*/
509 vp = fr_pair_dcursor_by_da_init(&uctx->body_cursor, &uctx->request->request_pairs, attr_smtp_body);
510 fr_dbuff_init(&uctx->vp_in, (uint8_t const *)vp->vp_strvalue, vp->vp_length);
511
512 /* Add a mime part to mime_body for every body element */
513 while (vp) {
514 body_elements++;
515 MEM(part = curl_mime_addpart(mime_body));
516
517 curl_mime_encoder(part, "8bit");
518 curl_mime_data_cb(part, vp->vp_length, body_source, NULL, NULL, uctx);
519
521 }
522 RDEBUG2("initialized %d body element part(s)", body_elements);
523
524 /* Re-initialize the cursor for use when uploading the data to curl */
525 fr_pair_dcursor_by_da_init(&uctx->body_cursor, &uctx->request->request_pairs, attr_smtp_body);
526
527 /*
528 * Add body_mime as a subpart of the mime request with a local content-disposition
529 */
530 MEM(part = curl_mime_addpart(mime));
531 curl_mime_subparts(part, mime_body);
532 MEM(curl_mime_type(part, "multipart/mixed") == CURLE_OK);
533 uctx->body_header = curl_slist_append(NULL, "Content-Disposition: inline"); /* Initialize the body_header curl_slist */
534 curl_mime_headers(part, uctx->body_header, 1);
535
536 return body_elements;
537}
538
539/*
540 * Adds every SMTP_Attachments file to the email as a MIME part
541 */
542static int attachments_source(fr_mail_ctx_t *uctx, curl_mime *mime, rlm_smtp_t const *inst, rlm_smtp_env_t const *call_env)
543{
544 int attachments_set = 0;
545 fr_sbuff_uctx_talloc_t sbuff_ctx;
546 fr_sbuff_t path_buffer;
548 fr_value_box_t *vb = NULL;
549 fr_value_box_list_t const *list = call_env->attachments;
550 size_t i, list_count = talloc_array_length(call_env->attachments);
551
552
553 /* Make sure that a template directory is provided */
554 if (!inst->template_dir) return 0;
555
556 /* Initialize the buffer to write the file path */
557 fr_sbuff_init_talloc(uctx, &path_buffer, &sbuff_ctx, talloc_array_length(inst->template_dir) + 128, SIZE_MAX);
558
559 /* Write the initial path to the buffer */
560 fr_sbuff_in_bstrcpy_buffer(&path_buffer, inst->template_dir);
561
562 /* Make sure the template_directory path ends in a "/" */
563 if (inst->template_dir[talloc_array_length(inst->template_dir) - 2] != '/'){
564 (void) fr_sbuff_in_char(&path_buffer, '/');
565 }
566
567 /* Mark the buffer so we only re-write after the template_dir component */
568 fr_sbuff_marker(&m, &path_buffer);
569
570 /* Add the attachments to the email */
571 for (i = 0; i < list_count; i++) {
572 while ((vb = fr_value_box_list_next(list, vb))) {
573 attachments_set += str_to_attachments(uctx, mime, vb->vb_strvalue, vb->vb_length, &path_buffer, &m);
574 }
575 list++;
576 }
577
578 /* Check for any file attachments */
579 talloc_free(path_buffer.buff);
580 return attachments_set;
581}
582
583static void smtp_io_module_signal(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
584{
585 fr_curl_io_request_t *randle = talloc_get_type_abort(mctx->rctx, fr_curl_io_request_t);
586 rlm_smtp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_smtp_thread_t);
587 CURLMcode ret;
588
589 RDEBUG2("Forcefully cancelling pending SMTP request");
590
591 ret = curl_multi_remove_handle(t->mhandle->mandle, randle->candle); /* Gracefully terminate the request */
592 if (ret != CURLM_OK) {
593 RERROR("Failed removing curl handle from multi-handle: %s (%i)", curl_multi_strerror(ret), ret);
594 /* Not much we can do */
595 }
596 t->mhandle->transfers--;
597 smtp_slab_release(randle);
598}
599
600/** Callback to process response of SMTP server
601 *
602 * It checks if the response was CURLE_OK
603 * If it was, it tries to extract the certificate attributes
604 * If the response was not OK, we REJECT the request
605 * When responding to requests initiated by mod_authenticate this is simply
606 * a check on the username and password.
607 * When responding to requests initiated by mod_mail this indicates
608 * the mail has been queued.
609 */
611{
613 fr_curl_io_request_t *randle = talloc_get_type_abort(mctx->rctx, fr_curl_io_request_t);
614 fr_curl_tls_t const *tls = &inst->tls;
615 long curl_out;
616 long curl_out_valid;
617
618 curl_out_valid = curl_easy_getinfo(randle->candle, CURLINFO_SSL_VERIFYRESULT, &curl_out);
619
620 if (curl_out_valid == CURLE_OK){
621 RDEBUG2("server certificate %s verified", curl_out ? "was" : "not");
622 } else {
623 RDEBUG2("server certificate result not found");
624 }
625
626 if (randle->result != CURLE_OK) {
627 CURLcode result = randle->result;
628 smtp_slab_release(randle);
629
630 switch (result) {
631 case CURLE_PEER_FAILED_VERIFICATION:
632 case CURLE_LOGIN_DENIED:
634
635 default:
637 }
638 }
639
640 if (tls->extract_cert_attrs) fr_curl_response_certinfo(request, randle);
641 smtp_slab_release(randle);
642
644}
645
646/*
647 * Checks that there is a User-Name and User-Password field in the request
648 * As well as all of the required SMTP elements
649 * Sets the: username, password
650 * SMTP server URI
651 * timeout information
652 * TLS information
653 * Sender and recipient information
654 * Email header and body
655 * File attachments
656 *
657 * Then it queues the request and yields until a response is given
658 * When it responds, smtp_io_module_resume is called.
659 */
660static unlang_action_t CC_HINT(nonnull) mod_mail(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
661{
663 rlm_smtp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_smtp_thread_t);
664 rlm_smtp_env_t *call_env = talloc_get_type_abort(mctx->env_data, rlm_smtp_env_t);
665 fr_curl_io_request_t *randle = NULL;
666 fr_mail_ctx_t *mail_ctx;
668 fr_pair_t const *smtp_body;
669
670 /* Elements provided by the request */
671 smtp_body = fr_pair_find_by_da(&request->request_pairs, NULL, attr_smtp_body);
672
673 /* Make sure all of the essential email components are present and possible*/
674 if (!smtp_body) {
675 RERROR("Attribute \"smtp-body\" is required for smtp");
677 }
678
679 if (!call_env->sender_address && !inst->envelope_address) {
680 RERROR("At least one of \"sender_address\" or \"envelope_address\" in the config, or \"SMTP-Sender-Address\" in the request is needed");
681 error:
682 if (randle) smtp_slab_release(randle);
683 RETURN_UNLANG_RCODE(rcode);
684 }
685
686 /*
687 * If the username is defined and is not static data
688 * a onetime connection is used, otherwise a persistent one
689 * can be used.
690 */
691 randle = (call_env->username_tmpl &&
692 !tmpl_is_data(call_env->username_tmpl)) ? smtp_slab_reserve(t->slab_onetime) :
693 smtp_slab_reserve(t->slab_persist);
694 if (!randle) {
695 RDEBUG2("A handle could not be allocated for the request");
697 }
698
699 /* Initialize the uctx to perform the email */
700 mail_ctx = talloc_get_type_abort(randle->uctx, fr_mail_ctx_t);
701 *mail_ctx = (fr_mail_ctx_t) {
702 .request = request,
703 .randle = randle,
704 .mime = curl_mime_init(randle->candle),
705 .time = fr_time(), /* time the request was received. Used to set DATE: */
706 .recipients = NULL,
707 .header = NULL
708 };
709
710 FR_CURL_REQUEST_SET_OPTION(CURLOPT_UPLOAD, 1L);
711
712 /* Set the username and password if they have been provided */
713 if (call_env->username.vb_strvalue) {
714 FR_CURL_REQUEST_SET_OPTION(CURLOPT_USERNAME, call_env->username.vb_strvalue);
715
716 if (!call_env->password.vb_strvalue) goto skip_auth;
717
718 FR_CURL_REQUEST_SET_OPTION(CURLOPT_PASSWORD, call_env->password.vb_strvalue);
719 RDEBUG3("Username and password set");
720 }
721
722skip_auth:
723 /* Set the envelope mail from address */
724 FR_CURL_REQUEST_SET_OPTION(CURLOPT_MAIL_FROM,
725 (inst->envelope_address ? inst->envelope_address :
726 fr_value_box_list_head(call_env->sender_address)->vb_strvalue));
727
728 /* Set the recipients */
729 if (recipients_source(mail_ctx, call_env) <= 0) {
730 REDEBUG("At least one recipient is required to send an email");
731 goto error;
732 }
733 FR_CURL_REQUEST_SET_OPTION(CURLOPT_MAIL_RCPT, mail_ctx->recipients);
734
735 /* Set the header elements */
736 if (header_source(mail_ctx, inst, call_env) != 0) {
737 REDEBUG("The header slist could not be generated");
738 rcode = RLM_MODULE_FAIL;
739 goto error;
740 }
741
742 /*
743 * CURLOPT_HTTPHEADER is the option that they use for the header in the curl example
744 *
745 * https://curl.haxx.se/libcurl/c/smtp-mime.html
746 */
747 FR_CURL_REQUEST_SET_OPTION(CURLOPT_HTTPHEADER, mail_ctx->header);
748
749 /* Initialize the body elements to be uploaded */
750 if (body_init(mail_ctx, mail_ctx->mime) == 0) {
751 REDEBUG("The body could not be generated");
752 rcode = RLM_MODULE_FAIL;
753 goto error;
754 }
755
756 /* Initialize the attachments if there are any*/
757 if (attachments_source(mail_ctx, mail_ctx->mime, inst, call_env) == 0){
758 RDEBUG3("No files were attached to the email");
759 }
760
761 /* Add the mime encoded elements to the curl request */
762 FR_CURL_REQUEST_SET_OPTION(CURLOPT_MIMEPOST, mail_ctx->mime);
763
764 if (fr_curl_io_request_enqueue(t->mhandle, request, randle)) {
765 rcode = RLM_MODULE_FAIL;
766 goto error;
767 }
768
770}
771
772/*
773 * Sets the: username, password
774 * SMTP server URI
775 * timeout information
776 * and TLS information
777 *
778 * Then it queues the request and yields until a response is given
779 * When it responds, smtp_io_module_resume is called.
780 */
781static unlang_action_t CC_HINT(nonnull(1,2)) mod_authenticate(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
782{
783 rlm_smtp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_smtp_thread_t);
784 rlm_smtp_auth_env_t *env_data = talloc_get_type_abort(mctx->env_data, rlm_smtp_auth_env_t);
785 fr_curl_io_request_t *randle;
786
787 if (!env_data->username_tmpl) {
788 RDEBUG("No 'username' was set for authentication - failing the request");
790 }
791
792 if (!env_data->password_tmpl) {
793 RDEBUG("No 'username' was set for authentication - failing the request");
795 }
796
797 if (env_data->username.type != FR_TYPE_STRING || (env_data->username.vb_length == 0)) {
798 RWARN("\"%s\" is required for authentication", env_data->username_tmpl->name);
800 }
801
802 if (env_data->password.type != FR_TYPE_STRING || (env_data->password.vb_length == 0)) {
803 RWARN("\"%s\" is required for authentication", env_data->password_tmpl->name);
805 }
806
807 randle = smtp_slab_reserve(t->slab_onetime);
808 if (!randle) {
810 }
811
812 FR_CURL_REQUEST_SET_OPTION(CURLOPT_USERNAME, env_data->username.vb_strvalue);
813 FR_CURL_REQUEST_SET_OPTION(CURLOPT_PASSWORD, env_data->password.vb_strvalue);
814
815 if (fr_curl_io_request_enqueue(t->mhandle, request, randle) < 0) {
816 error:
817 smtp_slab_release(randle);
819 }
820
822}
823
825 { .required = true, .concat = true, .type = FR_TYPE_STRING }, /* To: */
826 { .required = true, .concat = true, .type = FR_TYPE_STRING }, /* Subject: */
827 { .concat = true, .type = FR_TYPE_STRING }, /* Body */
829};
830
832 xlat_ctx_t const *xctx,
833 request_t *request, UNUSED fr_value_box_list_t *in)
834{
835 fr_curl_io_request_t *randle = talloc_get_type_abort(xctx->rctx, fr_curl_io_request_t);
836 fr_value_box_t *vb;
837
838 if (randle->result != CURLE_OK) {
839 RPERROR("Sending mail failed: %s %i", curl_easy_strerror(randle->result), randle->result);
840 smtp_slab_release(randle);
841 return XLAT_ACTION_FAIL;
842 }
843
844 smtp_slab_release(randle);
845
846 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
847 vb->vb_bool = true;
849
850 return XLAT_ACTION_DONE;
851}
852
853static void smtp_xlat_signal(xlat_ctx_t const *xctx, request_t *request, fr_signal_t action)
854{
855 fr_curl_io_request_t *randle = talloc_get_type_abort(xctx->rctx, fr_curl_io_request_t);
856 rlm_smtp_thread_t *t = talloc_get_type_abort(xctx->mctx->thread, rlm_smtp_thread_t);
857
858 smtp_io_module_signal(MODULE_CTX(xctx->mctx->mi, t, NULL, randle), request, action);
859}
860
861/** Xlat to send simple emails
862 *
863 * Example:
864 @verbatim
865 %smtp.send('bob@example.com', 'Something happened', 'More details about what happened')
866 @endverbatim
867 *
868 * @ingroup xlat_functions
869 */
871 xlat_ctx_t const *xctx, request_t *request,
872 fr_value_box_list_t *in)
873{
875 rlm_smtp_thread_t *t = talloc_get_type_abort(xctx->mctx->thread, rlm_smtp_thread_t);
876 fr_value_box_t *to, *subject, *body;
877 rlm_smtp_xlat_env_t *call_env = talloc_get_type_abort(xctx->env_data, rlm_smtp_xlat_env_t);
878 fr_curl_io_request_t *randle = NULL;
879 fr_mail_ctx_t *mail_ctx;
880 fr_value_box_t *vb = NULL;
881 char const *sender;
882 char *header_string;
883 curl_mimepart *part;
884
885 XLAT_ARGS(in, &to, &subject, &body);
886
887 randle = (call_env->username_tmpl &&
888 !tmpl_is_data(call_env->username_tmpl)) ? smtp_slab_reserve(t->slab_onetime) :
889 smtp_slab_reserve(t->slab_persist);
890 if (!randle) {
891 RERROR("A handle could not be allocated for the request");
892 return XLAT_ACTION_FAIL;
893 }
894
895 mail_ctx = talloc_get_type_abort(randle->uctx, fr_mail_ctx_t);
896 *mail_ctx = (fr_mail_ctx_t) {
897 .request = request,
898 .randle = randle,
899 .mime = curl_mime_init(randle->candle),
900 .time = fr_time(),
901 };
902
903 FR_CURL_REQUEST_SET_OPTION(CURLOPT_UPLOAD, 1L);
904
905 /* Set the username and password if they have been provided */
906 if (call_env->username.vb_strvalue) {
907 FR_CURL_REQUEST_SET_OPTION(CURLOPT_USERNAME, call_env->username.vb_strvalue);
908
909 if (!call_env->password.vb_strvalue) goto skip_auth;
910
911 FR_CURL_REQUEST_SET_OPTION(CURLOPT_PASSWORD, call_env->password.vb_strvalue);
912 RDEBUG2("Username and password set");
913 }
914
915skip_auth:
916 sender = inst->envelope_address ? inst->envelope_address : fr_value_box_list_head(call_env->sender_address)->vb_strvalue;
917 FR_CURL_REQUEST_SET_OPTION(CURLOPT_MAIL_FROM, sender);
918 header_string = talloc_asprintf(call_env, "From: %s", sender);
919 mail_ctx->header = curl_slist_append(mail_ctx->header, header_string);
920
921 mail_ctx->recipients = curl_slist_append(mail_ctx->recipients, to->vb_strvalue);
922 FR_CURL_REQUEST_SET_OPTION(CURLOPT_MAIL_RCPT, mail_ctx->recipients);
923 header_string = talloc_asprintf(call_env, "To: %s", to->vb_strvalue);
924 mail_ctx->header = curl_slist_append(mail_ctx->header, header_string);
925
926 header_string = talloc_asprintf(call_env, "Subject: %s", subject->vb_strvalue);
927 mail_ctx->header = curl_slist_append(mail_ctx->header, header_string);
928
929 if (fr_value_box_list_initialised(&call_env->headers)) {
930 while ((vb = fr_value_box_list_next(&call_env->headers, vb))) {
931 RDEBUG2("Adding header \"%pV\"", vb);
932 mail_ctx->header = curl_slist_append(mail_ctx->header, vb->vb_strvalue);
933 }
934 }
935 FR_CURL_REQUEST_SET_OPTION(CURLOPT_HTTPHEADER, mail_ctx->header);
936
937 MEM(part = curl_mime_addpart(mail_ctx->mime));
938 if (curl_mime_encoder(part, "8bit") != CURLE_OK) {
939 RERROR("Failed setting mime encoder");
940 error:
941 if (randle) smtp_slab_release(randle);
942 return XLAT_ACTION_FAIL;
943 }
944
945 if (body && (body->type == FR_TYPE_STRING)) {
946 if (curl_mime_data(part, body->vb_strvalue, body->vb_length) != CURLE_OK) {
947 RERROR("Failed adding email body");
948 goto error;
949 }
950 } else {
951 curl_mime_data(part, "", 0);
952 }
953 FR_CURL_REQUEST_SET_OPTION(CURLOPT_MIMEPOST, mail_ctx->mime);
954
955 if (fr_curl_io_request_enqueue(t->mhandle, request, randle)) goto error;
956
958}
959
960static int mod_bootstrap(module_inst_ctx_t const *mctx)
961{
962 xlat_t *xlat;
963
964 xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "send", smtp_send_xlat, FR_TYPE_BOOL);
967
968 return 0;
969}
970
971static int mod_instantiate(module_inst_ctx_t const *mctx)
972{
973 rlm_smtp_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_smtp_t);
974
975 inst->conn_config.reuse.num_children = 1;
976 inst->conn_config.reuse.child_pool_size = sizeof(fr_mail_ctx_t);
977
978 return 0;
979}
980
981#define SMTP_COMMON_CLEANUP \
982 fr_mail_ctx_t *mail_ctx = talloc_get_type_abort(randle->uctx, fr_mail_ctx_t); \
983 if (mail_ctx->mime) curl_mime_free(mail_ctx->mime); \
984 if (mail_ctx->header) curl_slist_free_all(mail_ctx->header); \
985 if (mail_ctx->recipients) curl_slist_free_all(mail_ctx->recipients)
986
988{
990
991 if (randle->candle) curl_easy_cleanup(randle->candle);
992
993 return 0;
994}
995
997{
999
1000 if (randle->candle) curl_easy_reset(randle->candle);
1001
1002 return 0;
1003}
1004
1006{
1007 fr_mail_ctx_t *mail_ctx = NULL;
1008
1009 MEM(mail_ctx = talloc_zero(randle, fr_mail_ctx_t));
1010 randle->uctx = mail_ctx;
1011
1012 smtp_slab_element_set_destructor(randle, smtp_onetime_request_cleanup, NULL);
1013
1014 return 0;
1015}
1016
1018{
1019 if (mail_ctx->randle && mail_ctx->randle->candle) curl_easy_cleanup(mail_ctx->randle->candle);
1020
1021 return 0;
1022}
1023
1025{
1026 fr_mail_ctx_t *mail_ctx = NULL;
1027
1028 MEM(mail_ctx = talloc_zero(randle, fr_mail_ctx_t));
1029 mail_ctx->randle = randle;
1030 randle->uctx = mail_ctx;
1031 randle->candle = curl_easy_init();
1032 if (unlikely(!randle->candle)) {
1033 fr_strerror_printf("Unable to initialise CURL handle");
1034 return -1;
1035 }
1036 talloc_set_destructor(mail_ctx, smtp_mail_ctx_free);
1037
1038 smtp_slab_element_set_destructor(randle, smtp_persist_request_cleanup, NULL);
1039
1040 return 0;
1041}
1042
1044{
1045#if CURL_AT_LEAST_VERSION(7,45,0)
1046 FR_CURL_SET_OPTION(CURLOPT_DEFAULT_PROTOCOL, "smtp");
1047#endif
1048 FR_CURL_SET_OPTION(CURLOPT_URL, inst->uri);
1049#if CURL_AT_LEAST_VERSION(7,85,0)
1050 FR_CURL_SET_OPTION(CURLOPT_PROTOCOLS_STR, "smtp,smtps");
1051#else
1052 FR_CURL_SET_OPTION(CURLOPT_PROTOCOLS, CURLPROTO_SMTP | CURLPROTO_SMTPS);
1053#endif
1054 FR_CURL_SET_OPTION(CURLOPT_CONNECTTIMEOUT_MS, fr_time_delta_to_msec(inst->timeout));
1055 FR_CURL_SET_OPTION(CURLOPT_TIMEOUT_MS, fr_time_delta_to_msec(inst->timeout));
1056
1057 if (DEBUG_ENABLED3) FR_CURL_SET_OPTION(CURLOPT_VERBOSE, 1L);
1058
1059 if (fr_curl_easy_tls_init(randle, &inst->tls) != 0) goto error;
1060
1061 return 0;
1062error:
1063 return -1;
1064}
1065
1066static int smtp_onetime_conn_init(fr_curl_io_request_t *randle, void *uctx)
1067{
1068 rlm_smtp_t const *inst = talloc_get_type_abort(uctx, rlm_smtp_t);
1069 fr_mail_ctx_t *mail_ctx = talloc_get_type_abort(randle->uctx, fr_mail_ctx_t);
1070
1071 randle->candle = curl_easy_init();
1072 if (unlikely(!randle->candle)) {
1073 fr_strerror_printf("Unable to initialise CURL handle");
1074 return -1;
1075 }
1076
1077 memset(mail_ctx, 0, sizeof(fr_mail_ctx_t));
1078
1079 return smtp_conn_common_init(randle, inst);
1080}
1081
1082
1083static int smtp_persist_conn_init(fr_curl_io_request_t *randle, void *uctx)
1084{
1085 rlm_smtp_t const *inst = talloc_get_type_abort(uctx, rlm_smtp_t);
1086 fr_mail_ctx_t *mail_ctx = talloc_get_type_abort(randle->uctx, fr_mail_ctx_t);
1087
1088 memset(mail_ctx, 0, sizeof(fr_mail_ctx_t));
1089
1090 return smtp_conn_common_init(randle, inst);
1091}
1092
1093/*
1094 * Initialize a new thread with a curl instance
1095 */
1097{
1098 rlm_smtp_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_smtp_t);
1099 rlm_smtp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_smtp_thread_t);
1100 fr_curl_handle_t *mhandle;
1101
1102 if (!(t->slab_onetime = smtp_slab_list_alloc(t, mctx->el, &inst->conn_config.reuse,
1104 inst, false, false))) {
1105 ERROR("Connection handle pool instantiation failed");
1106 return -1;
1107 }
1108 if (!(t->slab_persist = smtp_slab_list_alloc(t, mctx->el, &inst->conn_config.reuse,
1110 inst, false, true))) {
1111 ERROR("Connection handle pool instantiation failed");
1112 return -1;
1113 }
1114
1115 mhandle = fr_curl_io_init(t, mctx->el, false);
1116 if (!mhandle) return -1;
1117
1118 t->mhandle = mhandle;
1119 return 0;
1120}
1121
1122/*
1123 * Close the thread and free the memory
1124 */
1126{
1127 rlm_smtp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_smtp_thread_t);
1128
1129 talloc_free(t->mhandle);
1132 return 0;
1133}
1134
1135/** Parse the header section into tmpls for producing email headers
1136 *
1137 */
1138static int smtp_header_section_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, tmpl_rules_t const *t_rules,
1139 CONF_ITEM *ci,
1140 UNUSED call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
1141{
1142 CONF_SECTION const *cs = cf_item_to_section(ci);
1143 CONF_ITEM const *item = NULL;
1144 CONF_PAIR const *cp;
1145 call_env_parsed_t *parsed_env;
1146 tmpl_t *parsed_tmpl;
1147 ssize_t slen;
1148
1149 while ((item = cf_item_next(cs, item))) {
1150 char *to_parse;
1151
1152 if (!cf_item_is_pair(item)) {
1153 cf_log_err(item, "Entry is not in \"header = value\" format");
1154 return -1;
1155 }
1156 cp = cf_item_to_pair(item);
1157
1158 MEM(parsed_env = call_env_parsed_add(ctx, out,
1160
1161 /*
1162 * Turn the conf pair `attr = value` to email header format
1163 */
1164 to_parse = talloc_asprintf(NULL, "%s: %s", cf_pair_attr(cp), cf_pair_value(cp));
1165
1166 slen = tmpl_afrom_substr(parsed_env, &parsed_tmpl,
1167 &FR_SBUFF_IN(to_parse, talloc_array_length(to_parse) - 1),
1169 t_rules);
1170 talloc_free(to_parse);
1171
1172 if (slen <= 0) {
1173 cf_canonicalize_error(cp, slen, "Failed parsing header", cf_pair_value(cp));
1174 error:
1175 call_env_parsed_free(out, parsed_env);
1176 return -1;
1177 }
1178
1179 if (tmpl_needs_resolving(parsed_tmpl) &&
1180 (tmpl_resolve(parsed_tmpl, &(tmpl_res_rules_t){ .dict_def = t_rules->attr.dict_def }) < 0)) {
1181 cf_log_perr(cp, "Failed resolving header");
1182 goto error;
1183 }
1184
1185 call_env_parsed_set_tmpl(parsed_env, parsed_tmpl);
1186 }
1187
1188 return 0;
1189}
1190
1193 .env = (call_env_parser_t[]) {
1195 .pair.dflt_quote = T_DOUBLE_QUOTED_STRING },
1199 .pair.dflt = "SMTP-Recipients[*]", .pair.dflt_quote = T_BARE_WORD },
1201 .pair.dflt = "SMTP-TO[*]", .pair.dflt_quote = T_BARE_WORD },
1203 .pair.dflt = "SMTP-CC[*]", .pair.dflt_quote = T_BARE_WORD },
1205 .pair.dflt = "SMTP-BCC[*]", .pair.dflt_quote = T_BARE_WORD },
1207 .pair.dflt = "SMTP-Attachments[*]", .pair.dflt_quote = T_BARE_WORD },
1209
1211 }
1212};
1213
1216 .env = (call_env_parser_t[]) {
1218 ((call_env_parser_t[]) {
1221 rlm_smtp_auth_env_t, username, username_tmpl), .pair.dflt = "User-Name", .pair.dflt_quote = T_BARE_WORD },
1224 rlm_smtp_auth_env_t, password, password_tmpl), .pair.dflt = "User-Password", .pair.dflt_quote = T_BARE_WORD },
1226 }))},
1228 }
1229};
1230
1231/*
1232 * The module name should be the only globally exported symbol.
1233 * That is, everything else should be 'static'.
1234 *
1235 * If the module needs to temporarily modify it's instantiation
1236 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
1237 * The server will then take care of ensuring that the module
1238 * is single-threaded.
1239 */
1240extern module_rlm_t rlm_smtp;
1242 .common = {
1243 .magic = MODULE_MAGIC_INIT,
1244 .name = "smtp",
1245 .inst_size = sizeof(rlm_smtp_t),
1246 .thread_inst_size = sizeof(rlm_smtp_thread_t),
1247 .config = module_config,
1248 .bootstrap = mod_bootstrap,
1249 .instantiate = mod_instantiate,
1250 .thread_instantiate = mod_thread_instantiate,
1251 .thread_detach = mod_thread_detach,
1252 },
1253 .method_group = {
1254 .bindings = (module_method_binding_t[]){
1255 { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate, .method_env = &auth_env },
1256 { .section = SECTION_NAME("mail", CF_IDENT_ANY), .method = mod_mail, .method_env = &method_env },
1257
1259 }
1260 }
1261};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
#define RCSID(id)
Definition build.h:485
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
void call_env_parsed_free(call_env_parsed_head_t *parsed, call_env_parsed_t *ptr)
Remove a call_env_parsed_t from the list of parsed call envs.
Definition call_env.c:775
call_env_parsed_t * call_env_parsed_add(TALLOC_CTX *ctx, call_env_parsed_head_t *head, call_env_parser_t const *rule)
Allocate a new call_env_parsed_t structure and add it to the list of parsed call envs.
Definition call_env.c:688
void call_env_parsed_set_tmpl(call_env_parsed_t *parsed, tmpl_t const *tmpl)
Assign a tmpl to a call_env_parsed_t.
Definition call_env.c:717
#define CALL_ENV_TERMINATOR
Definition call_env.h:236
#define FR_CALL_ENV_PARSE_OFFSET(_name, _cast_type, _flags, _struct, _field, _parse_field)
Specify a call_env_parser_t which writes out runtime results and the result of the parsing phase to t...
Definition call_env.h:365
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
Definition call_env.h:240
call_env_parser_t const * env
Parsing rules for call method env.
Definition call_env.h:247
#define FR_CALL_ENV_SUBSECTION(_name, _name2, _flags, _subcs)
Specify a call_env_parser_t which defines a nested subsection.
Definition call_env.h:402
@ CALL_ENV_FLAG_CONCAT
If the tmpl produced multiple boxes they should be concatenated.
Definition call_env.h:76
@ CALL_ENV_FLAG_SUBSECTION
This is a subsection.
Definition call_env.h:87
@ CALL_ENV_FLAG_SECRET
The value is a secret, and should not be logged.
Definition call_env.h:91
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
Definition call_env.h:75
@ CALL_ENV_FLAG_PARSE_MISSING
If this subsection is missing, still parse it.
Definition call_env.h:88
@ CALL_ENV_FLAG_BARE_WORD_ATTRIBUTE
bare words are treated as an attribute, but strings may be xlats.
Definition call_env.h:92
@ CALL_ENV_FLAG_NULLABLE
Tmpl expansions are allowed to produce no output.
Definition call_env.h:80
#define FR_CALL_ENV_SUBSECTION_FUNC(_name, _name2, _flags, _func)
Specify a call_env_parser_t which parses a subsection using a callback function.
Definition call_env.h:412
#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field)
Specify a call_env_parser_t which writes out runtime results to the specified field.
Definition call_env.h:340
Per method call config.
Definition call_env.h:180
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:660
#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:283
#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:312
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:597
Common header for all CONF_* types.
Definition cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:631
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:683
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
Definition cf_util.c:1625
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:663
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1581
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1565
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:286
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
Definition cf_util.h:364
#define cf_item_next(_parent, _curr)
Definition cf_util.h:92
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:293
#define CF_IDENT_ANY
Definition cf_util.h:78
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
CURLcode result
Result of executing the request.
Definition base.h:103
#define FR_CURL_SET_OPTION(_x, _y)
Definition base.h:45
uint64_t transfers
How many transfers are current in progress.
Definition base.h:94
bool extract_cert_attrs
Definition base.h:119
CURLM * mandle
The multi handle.
Definition base.h:95
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:480
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 fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:767
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
Definition dbuff.h:354
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
Definition dbuff.h:743
#define fr_dbuff_in_memcpy_partial(_out, _in, _inlen)
Copy at most _inlen bytes into the dbuff.
Definition dbuff.h:1438
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:290
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:408
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:339
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:287
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:300
static fr_slen_t in
Definition dict.h:861
Specifies an attribute which must be present for the module to function.
Definition dict.h:286
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:299
#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 smtp_send_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Xlat to send simple emails.
Definition rlm_smtp.c:870
int fr_curl_response_certinfo(request_t *request, fr_curl_io_request_t *randle)
Definition base.c:170
int fr_curl_easy_tls_init(fr_curl_io_request_t *randle, fr_curl_tls_t const *conf)
Definition base.c:139
global_lib_autoinst_t fr_curl_autoinst
Definition base.c:387
conf_parser_t fr_curl_conn_config[]
Definition base.c:97
conf_parser_t fr_curl_tls_config[]
Definition base.c:68
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RWARN(fmt,...)
Definition log.h:297
#define RERROR(fmt,...)
Definition log.h:298
#define RPERROR(fmt,...)
Definition log.h:302
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
Definition log.h:259
#define REDEBUG2(fmt,...)
Definition log.h:372
talloc_free(reap)
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
Definition lst.c:122
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_BOOL
A truth value.
long int ssize_t
unsigned char uint8_t
void * env_data
Per call environment data.
Definition module_ctx.h:44
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
void * rctx
Resume ctx that a module previously set.
Definition module_ctx.h:45
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
#define MODULE_CTX(_mi, _thread, _env_data, _rctx)
Wrapper to create a module_ctx_t as a compound literal.
Definition module_ctx.h:128
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
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
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:700
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define RDEBUG(fmt,...)
Definition radclient.h:53
#define RETURN_UNLANG_INVALID
Definition rcode.h:62
#define RETURN_UNLANG_RCODE(_rcode)
Definition rcode.h:57
#define RETURN_UNLANG_FAIL
Definition rcode.h:59
#define RETURN_UNLANG_REJECT
Definition rcode.h:58
#define RETURN_UNLANG_OK
Definition rcode.h:60
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition rcode.h:47
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:44
username
static const call_env_method_t auth_env
Definition rlm_smtp.c:1214
struct curl_slist * recipients
Definition rlm_smtp.c:170
static int header_source(fr_mail_ctx_t *uctx, rlm_smtp_t const *inst, rlm_smtp_env_t const *call_env)
Definition rlm_smtp.c:403
fr_value_box_list_t headers
Entries to add to email header.
Definition rlm_smtp.c:94
fr_time_t time
Definition rlm_smtp.c:174
fr_value_box_list_t * bcc_addrs
The address(es) used for the Bcc: header.
Definition rlm_smtp.c:73
global_lib_autoinst_t const *const rlm_smtp_lib[]
Definition rlm_smtp.c:58
static unlang_action_t smtp_io_module_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Callback to process response of SMTP server.
Definition rlm_smtp.c:610
static int generate_from_header(fr_mail_ctx_t *uctx, struct curl_slist **out, rlm_smtp_t const *inst, rlm_smtp_env_t const *call_env)
Generate the From: header.
Definition rlm_smtp.c:328
static int value_box_list_to_slist(struct curl_slist **out, fr_value_box_list_t const *lists)
Transform an array of value box lists to entries in a CURL slist.
Definition rlm_smtp.c:205
static int smtp_persist_conn_alloc(fr_curl_io_request_t *randle, UNUSED void *uctx)
Definition rlm_smtp.c:1024
static const call_env_method_t smtp_call_env_xlat
Definition rlm_smtp.c:100
static int value_box_list_to_header(fr_mail_ctx_t *uctx, struct curl_slist **out, fr_value_box_list_t const *lists, const char *prefix)
Converts an array of value box lists to a curl_slist with a prefix.
Definition rlm_smtp.c:234
fr_value_box_t username
Value to use for user name.
Definition rlm_smtp.c:81
static int attachments_source(fr_mail_ctx_t *uctx, curl_mime *mime, rlm_smtp_t const *inst, rlm_smtp_env_t const *call_env)
Definition rlm_smtp.c:542
static void smtp_xlat_signal(xlat_ctx_t const *xctx, request_t *request, fr_signal_t action)
Definition rlm_smtp.c:853
static int smtp_persist_conn_init(fr_curl_io_request_t *randle, void *uctx)
Definition rlm_smtp.c:1083
fr_dcursor_t cursor
Definition rlm_smtp.c:166
smtp_slab_list_t * slab_persist
Slab list for persistent connections.
Definition rlm_smtp.c:156
static int smtp_conn_common_init(fr_curl_io_request_t *randle, rlm_smtp_t const *inst)
Definition rlm_smtp.c:1043
fr_curl_io_request_t * randle
Definition rlm_smtp.c:165
static fr_dict_attr_t const * attr_smtp_body
Definition rlm_smtp.c:48
static const call_env_method_t method_env
Definition rlm_smtp.c:1191
static int smtp_onetime_request_cleanup(fr_curl_io_request_t *randle, UNUSED void *uctx)
Definition rlm_smtp.c:987
static fr_dict_t const * dict_freeradius
Definition rlm_smtp.c:39
fr_value_box_t password
Password for authenticated mails.
Definition rlm_smtp.c:92
fr_dict_attr_autoload_t rlm_smtp_dict_attr[]
Definition rlm_smtp.c:51
fr_time_delta_t timeout
Timeout for connection and server response.
Definition rlm_smtp.c:118
static int recipients_source(fr_mail_ctx_t *uctx, rlm_smtp_env_t const *call_env)
Definition rlm_smtp.c:360
fr_dict_autoload_t rlm_smtp_dict[]
Definition rlm_smtp.c:42
fr_curl_conn_config_t conn_config
Reusable CURL handle config.
Definition rlm_smtp.c:123
tmpl_t * username_tmpl
tmpl expanded to populate username
Definition rlm_smtp.c:82
static void smtp_io_module_signal(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
Definition rlm_smtp.c:583
char const * uri
URI of smtp server.
Definition rlm_smtp.c:114
fr_value_box_t username
User to authenticate as when sending emails.
Definition rlm_smtp.c:66
fr_dbuff_t vp_in
Definition rlm_smtp.c:168
fr_value_box_t password
Value to use for password.
Definition rlm_smtp.c:83
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_smtp.c:960
struct curl_slist * header
Definition rlm_smtp.c:171
tmpl_t * password_tmpl
tmpl expanded to populate password
Definition rlm_smtp.c:84
static int smtp_header_section_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, call_env_ctx_t const *cec, call_env_parser_t const *rule)
static fr_dict_attr_t const * attr_smtp_header
Definition rlm_smtp.c:47
fr_dcursor_t body_cursor
Definition rlm_smtp.c:167
static int smtp_persist_request_cleanup(fr_curl_io_request_t *randle, UNUSED void *uctx)
Definition rlm_smtp.c:996
curl_mime * mime
Definition rlm_smtp.c:176
fr_value_box_list_t * cc_addrs
The address(es) used for the Cc: header.
Definition rlm_smtp.c:72
fr_value_box_list_t * to_addrs
The address(es) used for the To: header.
Definition rlm_smtp.c:71
#define SMTP_COMMON_CLEANUP
Definition rlm_smtp.c:981
request_t * request
Definition rlm_smtp.c:164
static int body_init(fr_mail_ctx_t *uctx, curl_mime *mime)
Definition rlm_smtp.c:495
fr_value_box_list_t headers
Entries to add to email header.
Definition rlm_smtp.c:75
module_rlm_t rlm_smtp
Definition rlm_smtp.c:1241
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Definition rlm_smtp.c:1096
struct curl_slist * body_header
Definition rlm_smtp.c:172
static unlang_action_t mod_authenticate(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_smtp.c:781
bool set_date
Definition rlm_smtp.c:121
static unlang_action_t mod_mail(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_smtp.c:660
static int smtp_onetime_conn_alloc(fr_curl_io_request_t *randle, UNUSED void *uctx)
Definition rlm_smtp.c:1005
fr_value_box_list_t * sender_address
The address(es) used to generate the From: header.
Definition rlm_smtp.c:93
fr_value_box_t password
Password for authenticated mails.
Definition rlm_smtp.c:68
char const * envelope_address
The address used to send the message.
Definition rlm_smtp.c:116
static int str_to_attachments(fr_mail_ctx_t *uctx, curl_mime *mime, char const *str, size_t len, fr_sbuff_t *path_buffer, fr_sbuff_marker_t *m)
Definition rlm_smtp.c:285
fr_value_box_list_t * recipient_addrs
The address(es) used as recipients. Overrides elements in to, cc and bcc.
Definition rlm_smtp.c:70
tmpl_t * username_tmpl
The tmpl used to produce the above.
Definition rlm_smtp.c:91
static int smtp_onetime_conn_init(fr_curl_io_request_t *randle, void *uctx)
Definition rlm_smtp.c:1066
char time_str[60]
Definition rlm_smtp.c:175
tmpl_t * username_tmpl
The tmpl used to produce the above.
Definition rlm_smtp.c:67
static size_t body_source(char *ptr, size_t size, size_t nmemb, void *mail_ctx)
Definition rlm_smtp.c:454
static xlat_arg_parser_t const smtp_xlat_args[]
Definition rlm_smtp.c:824
char const * template_dir
The directory that contains all email attachments.
Definition rlm_smtp.c:115
fr_value_box_t username
User to authenticate as when sending emails.
Definition rlm_smtp.c:90
fr_curl_tls_t tls
Used for handled all tls specific curl components.
Definition rlm_smtp.c:119
static int da_to_slist(fr_mail_ctx_t *uctx, struct curl_slist **out, const fr_dict_attr_t *dict_attr)
Definition rlm_smtp.c:182
static const conf_parser_t module_config[]
Definition rlm_smtp.c:129
static int smtp_mail_ctx_free(fr_mail_ctx_t *mail_ctx)
Definition rlm_smtp.c:1017
fr_value_box_list_t * attachments
List of files to attach.
Definition rlm_smtp.c:74
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Definition rlm_smtp.c:1125
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_smtp.c:971
fr_curl_handle_t * mhandle
Thread specific multi handle.
Definition rlm_smtp.c:154
smtp_slab_list_t * slab_onetime
Slab list for onetime use connections.
Definition rlm_smtp.c:157
static xlat_action_t smtp_send_xlat_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
Definition rlm_smtp.c:831
fr_value_box_list_t * sender_address
The address(es) used to generate the From: header.
Definition rlm_smtp.c:69
Call environment for SMTP authentication.
Definition rlm_smtp.c:80
Call environment for sending emails.
Definition rlm_smtp.c:65
Call environment for sending simple emails using an xlat.
Definition rlm_smtp.c:89
ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1459
ssize_t fr_sbuff_in_bstrncpy(fr_sbuff_t *sbuff, char const *str, size_t len)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1483
ssize_t fr_sbuff_in_bstrcpy_buffer(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1503
#define fr_sbuff_set(_dst, _src)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_buff(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_in_char(_sbuff,...)
Talloc sbuff extension structure.
Definition sbuff.h:139
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:40
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:291
void * boot
Data allocated during the boostrap phase.
Definition module.h:294
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:152
Named methods exported by a module.
Definition module.h:174
int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules))
Attempt to resolve functions and attributes in xlats and attribute references.
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
#define tmpl_is_data(vpt)
Definition tmpl.h:206
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:335
#define tmpl_needs_resolving(vpt)
Definition tmpl.h:223
Similar to tmpl_rules_t, but used to specify parameters that may change during subsequent resolution ...
Definition tmpl.h:364
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:332
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:120
#define FR_SLAB_TYPES(_name, _type)
Define type specific wrapper structs for slabs and slab elements.
Definition slab.h:72
return count
Definition module.c:155
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition module.c:431
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:273
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
#define talloc_get_type_abort_const
Definition talloc.h:287
size_t fr_time_strftime_local(fr_sbuff_t *out, fr_time_t time, char const *fmt)
Copy a time string (local timezone) to an sbuff.
Definition time.c:503
static int64_t fr_time_delta_to_msec(fr_time_delta_t delta)
Definition time.h:637
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
@ T_BARE_WORD
Definition token.h:120
@ T_DOUBLE_QUOTED_STRING
Definition token.h:121
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:548
uint8_t required
Argument must be present, and non-empty.
Definition xlat.h:146
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:383
#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 consumend by an xlat function.
Definition xlat.h:145
#define fr_pair_dcursor_by_da_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
Definition pair.h:624
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
fr_sbuff_parse_rules_t const * value_parse_rules_quoted[T_TOKEN_LAST]
Parse rules for quoted strings.
Definition value.c:612
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
Definition value.c:3976
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:643
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1023
void * rctx
Resume context.
Definition xlat_ctx.h:54
void * env_data
Expanded call env data.
Definition xlat_ctx.h:53
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
void xlat_func_call_env_set(xlat_t *x, call_env_method_t const *env_method)
Register call environment of an xlat.
Definition xlat_func.c:389