The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_perl.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: 8d78fcca17dd0175a09908ad69825f6f9d7a72ed $
19 * @file rlm_perl.c
20 * @brief Translates requests between the server an a perl interpreter.
21 *
22 * @copyright 2002,2006 The FreeRADIUS server project
23 * @copyright 2002 Boian Jordanov (bjordanov@orbitel.bg)
24 */
25RCSID("$Id: 8d78fcca17dd0175a09908ad69825f6f9d7a72ed $")
26
27#define LOG_PREFIX "perl"
28
29#include <freeradius-devel/server/base.h>
30#include <freeradius-devel/server/module_rlm.h>
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/unlang/xlat_func.h>
33#include <freeradius-devel/unlang/xlat.h>
34#include <freeradius-devel/radius/radius.h>
35
37DIAG_OFF(compound-token-split-by-macro) /* Perl does horrible things with macros */
39
40#ifdef INADDR_ANY
41# undef INADDR_ANY
42#endif
43#include <EXTERN.h>
44#include <perl.h>
45#include <XSUB.h>
46#include <dlfcn.h>
47#include <semaphore.h>
48
49#if defined(__APPLE__) || defined(__FreeBSD__)
50extern char **environ;
51#endif
52
53#ifndef USE_ITHREADS
54# error perl must be compiled with USE_ITHREADS
55#endif
56
57typedef struct {
58 bool request; //!< Should the request list be replaced after module call
59 bool reply; //!< Should the reply list be replaced after module call
60 bool control; //!< Should the control list be replaced after module call
61 bool session; //!< Should the session list be replaced after module call
63
64typedef struct {
65 char const *function_name; //!< Name of the function being called
66 char *name1; //!< Section name1 where this is called
67 char *name2; //!< Section name2 where this is called
68 fr_rb_node_t node; //!< Node in tree of function calls.
70
71typedef struct {
74
75/*
76 * Define a structure for our module configuration.
77 *
78 * These variables do not need to be in a structure, but it's
79 * a lot cleaner to do so, and a pointer to the structure can
80 * be used as the instance handle.
81 */
82typedef struct {
83 /* Name of the perl module */
84 char const *module;
85
86 fr_rb_tree_t funcs; //!< Tree of function calls found by call_env parser.
87 bool funcs_init; //!< Has the tree been initialised.
88 char const *func_detach; //!< Function to run when mod_detach is run.
89 char const *perl_flags;
90 PerlInterpreter *perl;
93 HV *rad_perlconf_hv; //!< holds "config" items (perl %RAD_PERLCONF hash).
94
96
97typedef struct {
98 PerlInterpreter *perl; //!< Thread specific perl interpreter.
100
101static void *perl_dlhandle; //!< To allow us to load perl's symbols into the global symbol table.
102
104 { FR_CONF_OFFSET("request", rlm_perl_replace_t, request) },
105 { FR_CONF_OFFSET("reply", rlm_perl_replace_t, reply) },
106 { FR_CONF_OFFSET("control", rlm_perl_replace_t, control) },
107 { FR_CONF_OFFSET("session", rlm_perl_replace_t, session) },
109};
110
111/*
112 * A mapping of configuration file names to internal variables.
113 */
114static const conf_parser_t module_config[] = {
116
117 { FR_CONF_OFFSET("func_detach", rlm_perl_t, func_detach), .data = NULL, .dflt = "detach", .quote = T_INVALID },
118
119 { FR_CONF_OFFSET("perl_flags", rlm_perl_t, perl_flags) },
120
121 { FR_CONF_OFFSET_SUBSECTION("replace", 0, rlm_perl_t, replace, replace_config) },
122
124};
125
126/** How to compare two Perl function calls
127 *
128 */
129static int8_t perl_func_def_cmp(void const *one, void const *two)
130{
131 perl_func_def_t const *a = one, *b = two;
132 int ret;
133
134 ret = strcmp(a->name1, b->name1);
135 if (ret != 0) return CMP(ret, 0);
136 if (!a->name2 && !b->name2) return 0;
137 if (!a->name2 || !b->name2) return a->name2 ? 1 : -1;
138 ret = strcmp(a->name2, b->name2);
139 return CMP(ret, 0);
140}
141
142/*
143 * man perlembed
144 */
145EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);
146
147static _Thread_local request_t *rlm_perl_request;
148
149# define dl_librefs "DynaLoader::dl_librefs"
150# define dl_modules "DynaLoader::dl_modules"
151static void rlm_perl_clear_handles(pTHX)
152{
153 AV *librefs = get_av(dl_librefs, false);
154 if (librefs) {
155 av_clear(librefs);
156 }
157}
158
159static void **rlm_perl_get_handles(pTHX)
160{
161 I32 i;
162 AV *librefs = get_av(dl_librefs, false);
163 AV *modules = get_av(dl_modules, false);
164 void **handles;
165
166 if (!librefs) return NULL;
167
168 if (!(AvFILL(librefs) >= 0)) {
169 return NULL;
170 }
171
172 MEM(handles = talloc_array(NULL, void *, AvFILL(librefs) + 2));
173 for (i = 0; i <= AvFILL(librefs); i++) {
174 void *handle;
175 SV *handle_sv = *av_fetch(librefs, i, false);
176 if (!handle_sv) {
177 ERROR("Could not fetch $%s[%d]!", dl_librefs, (int)i);
178 continue;
179 }
180 handle = (void *)SvIV(handle_sv);
181
182 if (handle) handles[i] = handle;
183 }
184
185 av_clear(modules);
186 av_clear(librefs);
187
188 handles[i] = (void *)0;
189
190 return handles;
191}
192
193static void rlm_perl_close_handles(void **handles)
194{
195 int i;
196
197 if (!handles) {
198 return;
199 }
200
201 for (i = 0; handles[i]; i++) {
202 DEBUG("Close %p", handles[i]);
203 dlclose(handles[i]);
204 }
205
206 talloc_free(handles);
207}
208
209/*
210 * This is wrapper for fr_log
211 * Now users can call radiusd::log(level,msg) which is the same
212 * as calling fr_log from C code.
213 */
214static XS(XS_radiusd_log)
215{
216 dXSARGS;
217 if (items !=2)
218 croak("Usage: radiusd::log(level, message)");
219 {
220 int level;
221 char *msg;
222
223 level = (int) SvIV(ST(0));
224 msg = (char *) SvPV(ST(1), PL_na);
225
226 /*
227 * Because 'msg' is a 'char *', we don't want '%s', etc.
228 * in it to give us printf-style vulnerabilities.
229 */
230 fr_log(&default_log, level, __FILE__, __LINE__, "rlm_perl: %s", msg);
231 }
232 XSRETURN_NO;
233}
234
235/*
236 * This is a wrapper for xlat_aeval
237 * Now users are able to get data that is accessible only via xlat
238 * e.g. %client(...)
239 * Call syntax is radiusd::xlat(string), string will be handled the
240 * same way it is described in EXPANSIONS section of man unlang
241 */
242static XS(XS_radiusd_xlat)
243{
244 dXSARGS;
245 char *in_str;
246 char *expanded;
247 ssize_t slen;
248 request_t *request;
249
250 if (items != 1) croak("Usage: radiusd::xlat(string)");
251
252 request = rlm_perl_request;
253
254 in_str = (char *) SvPV(ST(0), PL_na);
255
256 slen = xlat_aeval(request, &expanded, request, in_str, NULL, NULL);
257 if (slen < 0) {
258 REDEBUG("Error parsing xlat '%s'", in_str);
259 XSRETURN_UNDEF;
260 }
261
262 XST_mPV(0, expanded);
263 talloc_free(expanded);
264 XSRETURN(1);
265}
266
267static void xs_init(pTHX)
268{
269 char const *file = __FILE__;
270
271 /* DynaLoader is a special case */
272 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
273
274 newXS("radiusd::log",XS_radiusd_log, "rlm_perl");
275 newXS("radiusd::xlat",XS_radiusd_xlat, "rlm_perl");
276}
277
278/** Convert a list of value boxes to a Perl array for passing to subroutines
279 *
280 * The Perl array object should be created before calling this
281 * to populate it.
282 *
283 * @param[in,out] av Perl array object to append values to.
284 * @param[in] head of VB list.
285 * @return
286 * - 0 on success
287 * - -1 on failure
288 */
289static int perl_vblist_to_av(AV *av, fr_value_box_list_t *head) {
290 fr_value_box_t *vb = NULL;
291 SV *sv;
292
293 while ((vb = fr_value_box_list_next(head, vb))) {
294 switch (vb->type) {
295 case FR_TYPE_STRING:
296 sv = newSVpvn(vb->vb_strvalue, vb->vb_length);
297 break;
298
299 case FR_TYPE_OCTETS:
300 sv = newSVpvn((char const *)vb->vb_octets, vb->vb_length);
301 break;
302
303 case FR_TYPE_GROUP:
304 {
305 AV *sub_av;
306 sub_av = newAV();
307 perl_vblist_to_av(sub_av, &vb->vb_group);
308 sv = newRV_inc((SV *)sub_av);
309 }
310 break;
311 default:
312 {
313 char buffer[1024];
314 ssize_t slen;
315
316 slen = fr_value_box_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), vb, NULL);
317 if (slen < 0) return -1;
318 sv = newSVpvn(buffer, (size_t)slen);
319 }
320 break;
321 }
322 if (!sv) return -1;
323 if (vb->tainted) SvTAINT(sv);
324 av_push(av, sv);
325 }
326 return 0;
327}
328
329/** Parse a Perl SV and create value boxes, appending to a list
330 *
331 * For parsing values passed back from a Perl subroutine
332 *
333 * When hashes are returned, first the key is added as a value box then the value
334 *
335 * @param[in] ctx to allocate boxes in.
336 * @param[out] list to append value boxes to.
337 * @param[in] request being handled - only used for debug messages
338 * @param[in] sv to parse
339 * @return
340 * - 0 on success
341 * - -1 on failure
342 */
343static int perl_sv_to_vblist(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, SV *sv) {
344 fr_value_box_t *vb = NULL;
345 char *tmp;
346 STRLEN len;
347 AV *av;
348 HV *hv;
349 I32 sv_len, i;
350 int type;
351
352 type = SvTYPE(sv);
353
354 switch (type) {
355 case SVt_IV:
356 /* Integer or Reference */
357 if (SvROK(sv)) {
358 RDEBUG3("Reference returned");
359 if (perl_sv_to_vblist(ctx, list, request, SvRV(sv)) < 0) return -1;
360 break;
361 }
362 RDEBUG3("Integer returned");
363 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_INT32, NULL));
364 vb->vb_int32 = SvIV(sv);
365 break;
366
367 case SVt_NV:
368 /* Float */
369 RDEBUG3("Float returned");
370 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_FLOAT64, NULL));
371 vb->vb_float64 = SvNV(sv);
372 break;
373
374 case SVt_PV:
375 /* String */
376 RDEBUG3("String returned");
377 tmp = SvPVutf8(sv, len);
378 MEM(vb = fr_value_box_alloc_null(ctx));
379 if (fr_value_box_bstrndup(vb, vb, NULL, tmp, len, SvTAINTED(sv)) < 0) {
380 talloc_free(vb);
381 RPEDEBUG("Failed to allocate %ld for output", len);
382 return -1;
383 }
384 break;
385
386 case SVt_PVAV:
387 /* Array */
388 {
389 SV **av_sv;
390 RDEBUG3("Array returned");
391 av = (AV*)sv;
392 sv_len = av_len(av);
393 for (i = 0; i <= sv_len; i++) {
394 av_sv = av_fetch(av, i, 0);
395 if (SvOK(*av_sv)) {
396 if (perl_sv_to_vblist(ctx, list, request, *av_sv) < 0) return -1;
397 }
398 }
399 }
400 break;
401
402 case SVt_PVHV:
403 /* Hash */
404 {
405 SV *hv_sv;
406 RDEBUG3("Hash returned");
407 hv = (HV*)sv;
408 for (i = hv_iterinit(hv); i > 0; i--) {
409 hv_sv = hv_iternextsv(hv, &tmp, &sv_len);
410 /*
411 * Add key first
412 */
413 MEM(vb = fr_value_box_alloc_null(ctx));
414 if (fr_value_box_bstrndup(vb, vb, NULL, tmp, sv_len, SvTAINTED(hv_sv)) < 0) {
415 talloc_free(vb);
416 RPEDEBUG("Failed to allocate %d for output", sv_len);
417 return -1;
418 }
419 fr_value_box_list_insert_tail(list, vb);
420
421 /*
422 * Now process value
423 */
424 if (perl_sv_to_vblist(ctx, list, request, hv_sv) < 0) return -1;
425
426 }
427 /*
428 * Box has already been added to list - return
429 */
430 return 0;
431 }
432
433 case SVt_NULL:
434 break;
435
436 default:
437 RPEDEBUG("Perl returned unsupported data type %d", type);
438 return -1;
439
440 }
441
442 if (vb) {
443 vb->tainted = SvTAINTED(sv);
444 fr_value_box_list_insert_tail(list, vb);
445 }
446
447 return 0;
448}
449
451 { .required = true, .single = true, .type = FR_TYPE_STRING },
452 { .variadic = XLAT_ARG_VARIADIC_EMPTY_KEEP, .type = FR_TYPE_VOID },
454};
455
456/** Call perl code using an xlat
457 *
458 * @ingroup xlat_functions
459 */
460static xlat_action_t perl_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
461 xlat_ctx_t const *xctx,
462 request_t *request, fr_value_box_list_t *in)
463{
465 int count, i;
467 STRLEN n_a;
468 fr_value_box_t *func = fr_value_box_list_pop_head(in);
469 fr_value_box_t *child;
470 SV *sv;
471 AV *av;
472 fr_value_box_list_t list, sub_list;
473 fr_value_box_t *vb = NULL;
474
475 fr_value_box_list_init(&list);
476 fr_value_box_list_init(&sub_list);
477
478 {
479 dTHXa(t->perl);
480 PERL_SET_CONTEXT(t->perl);
481 }
482
483 {
484 ssize_t slen;
485 fr_sbuff_t *sbuff;
486
487 dSP;
488 ENTER;SAVETMPS;
489
490 PUSHMARK(SP);
491
492 FR_SBUFF_TALLOC_THREAD_LOCAL(&sbuff, 256, 16384);
493
495
496 fr_assert(arg->type == FR_TYPE_GROUP);
497 if (fr_value_box_list_empty(&arg->vb_group)) continue;
498
499 if (fr_value_box_list_num_elements(&arg->vb_group) == 1) {
500 child = fr_value_box_list_head(&arg->vb_group);
501
502 switch (child->type) {
503 case FR_TYPE_STRING:
504 if (child->vb_length == 0) continue;
505
506 RDEBUG3("Passing single value %pV", child);
507 sv = newSVpvn(child->vb_strvalue, child->vb_length);
508 break;
509
510 case FR_TYPE_GROUP:
511 RDEBUG3("Ignoring nested group");
512 continue;
513
514 default:
515 /*
516 * @todo - turn over integers as strings.
517 */
518 slen = fr_value_box_print(sbuff, child, NULL);
519 if (slen <= 0) {
520 RPEDEBUG("Failed printing sbuff");
521 continue;
522 }
523
524 RDEBUG3("Passing single value %pV", child);
525 sv = newSVpvn(fr_sbuff_start(sbuff), fr_sbuff_used(sbuff));
526 fr_sbuff_set_to_start(sbuff);
527 break;
528 }
529
530 if (child->tainted) SvTAINT(sv);
531 XPUSHs(sv_2mortal(sv));
532 continue;
533 }
534
535 /*
536 * Multiple child values - create array and pass reference
537 */
538 av = newAV();
539 perl_vblist_to_av(av, &arg->vb_group);
540 RDEBUG3("Passing list as array %pM", &arg->vb_group);
541 sv = newRV_inc((SV *)av);
542 XPUSHs(sv_2mortal(sv));
543 }
544
545 PUTBACK;
546
547 count = call_pv(func->vb_strvalue, G_ARRAY | G_EVAL);
548
549 SPAGAIN;
550 if (SvTRUE(ERRSV)) {
551 REDEBUG("Exit %s", SvPV(ERRSV,n_a));
552 (void)POPs;
553 goto cleanup;
554 }
555
556 /*
557 * As results are popped from a stack, they are in reverse
558 * sequence. Add to a temporary list and then prepend to
559 * main list.
560 */
561 for (i = 0; i < count; i++) {
562 sv = POPs;
563 if (perl_sv_to_vblist(ctx, &sub_list, request, sv) < 0) goto cleanup;
564 fr_value_box_list_move_head(&list, &sub_list);
565 }
566 ret = XLAT_ACTION_DONE;
567
568 /*
569 * Move the assembled list of boxes to the output
570 */
571 while ((vb = fr_value_box_list_pop_head(&list))) fr_dcursor_append(out, vb);
572
573 cleanup:
574 PUTBACK;
575 FREETMPS;
576 LEAVE;
577
578 }
579
580 return ret;
581}
582
583/*
584 * Parse a configuration section, and populate a HV.
585 * This function is recursively called (allows to have nested hashes.)
586 */
587static void perl_parse_config(CONF_SECTION *cs, int lvl, HV *rad_hv)
588{
589 int indent_section = (lvl + 1) * 4;
590 int indent_item = (lvl + 2) * 4;
591
592 if (!cs || !rad_hv) return;
593
594 DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
595
596 for (CONF_ITEM *ci = NULL; (ci = cf_item_next(cs, ci)); ) {
597 /*
598 * This is a section.
599 * Create a new HV, store it as a reference in current HV,
600 * Then recursively call perl_parse_config with this section and the new HV.
601 */
602 if (cf_item_is_section(ci)) {
603 CONF_SECTION *sub_cs = cf_item_to_section(ci);
604 char const *key = cf_section_name1(sub_cs); /* hash key */
605 HV *sub_hv;
606 SV *ref;
607
608 if (!key) continue;
609
610 if (hv_exists(rad_hv, key, strlen(key))) {
611 WARN("Ignoring duplicate config section '%s'", key);
612 continue;
613 }
614
615 sub_hv = newHV();
616 ref = newRV_inc((SV*) sub_hv);
617
618 (void)hv_store(rad_hv, key, strlen(key), ref, 0);
619
620 perl_parse_config(sub_cs, lvl + 1, sub_hv);
621 } else if (cf_item_is_pair(ci)){
622 CONF_PAIR *cp = cf_item_to_pair(ci);
623 char const *key = cf_pair_attr(cp); /* hash key */
624 char const *value = cf_pair_value(cp); /* hash value */
625
626 if (!key || !value) continue;
627
628 /*
629 * This is an item.
630 * Store item attr / value in current HV.
631 */
632 if (hv_exists(rad_hv, key, strlen(key))) {
633 WARN("Ignoring duplicate config item '%s'", key);
634 continue;
635 }
636
637 (void)hv_store(rad_hv, key, strlen(key), newSVpvn(value, strlen(value)), 0);
638
639 DEBUG("%*s%s = %s", indent_item, " ", key, value);
640 }
641 }
642
643 DEBUG("%*s}", indent_section, " ");
644}
645
646static void perl_store_vps(request_t *request, fr_pair_list_t *vps, HV *rad_hv,
647 const char *hash_name, bool dbg_print);
648
649static void perl_vp_to_svpvn_element(request_t *request, AV *av, fr_pair_t *vp,
650 int *i, const char *hash_name, bool dbg_print)
651{
652
653 SV *sv;
654
655 if (dbg_print) RDEBUG2("$%s{'%s'}[%i] = %pP", hash_name, vp->da->name, *i, vp);
656 switch (vp->vp_type) {
657 case FR_TYPE_STRING:
658 sv = newSVpvn(vp->vp_strvalue, vp->vp_length);
659 break;
660
661 case FR_TYPE_OCTETS:
662 sv = newSVpvn((char const *)vp->vp_octets, vp->vp_length);
663 break;
664
666 {
667 HV *hv;
668 hv = newHV();
669 perl_store_vps(request, &vp->vp_group, hv, vp->da->name, false);
670 sv = newRV_noinc((SV *)hv);
671 }
672 break;
673
674 default:
675 {
676 char buffer[1024];
677 ssize_t slen;
678
680 if (slen < 0) return;
681
682 sv = newSVpvn(buffer, (size_t)slen);
683 }
684 break;
685 }
686
687 if (!sv) return;
688 SvTAINT(sv);
689 av_push(av, sv);
690 (*i)++;
691}
692
693/*
694 * get the vps and put them in perl hash
695 * If one VP have multiple values it is added as array_ref
696 * Example for this is Vendor-Specific.Cisco.AVPair that holds multiple values.
697 * Which will be available as array_ref in $RAD_REQUEST{'Vendor-Specific.Cisco.AVPair'}
698 */
699static void perl_store_vps(request_t *request, fr_pair_list_t *vps, HV *rad_hv,
700 const char *hash_name, bool dbg_print)
701{
702 fr_pair_t *vp;
703 fr_dcursor_t cursor;
704
705 hv_undef(rad_hv);
706
707 RINDENT();
709 for (vp = fr_pair_dcursor_init(&cursor, vps);
710 vp;
711 vp = fr_dcursor_next(&cursor)) {
712 fr_pair_t *next;
713 char const *name;
714 name = vp->da->name;
715
716 /*
717 * We've sorted by type, then tag, so attributes of the
718 * same type/tag should follow on from each other.
719 */
720 if ((next = fr_dcursor_next_peek(&cursor)) && ATTRIBUTE_EQ(vp, next)) {
721 int i = 0;
722 AV *av;
723
724 av = newAV();
725 perl_vp_to_svpvn_element(request, av, vp, &i, hash_name, dbg_print);
726 do {
727 perl_vp_to_svpvn_element(request, av, next, &i, hash_name, dbg_print);
728 fr_dcursor_next(&cursor);
729 } while ((next = fr_dcursor_next_peek(&cursor)) && ATTRIBUTE_EQ(vp, next));
730 (void)hv_store(rad_hv, name, strlen(name), newRV_noinc((SV *)av), 0);
731
732 continue;
733 }
734
735 /*
736 * It's a normal single valued attribute
737 */
738 if (dbg_print) RDEBUG2("$%s{'%s'} = %pP'", hash_name, vp->da->name, vp);
739 switch (vp->vp_type) {
740 case FR_TYPE_STRING:
741 (void)hv_store(rad_hv, name, strlen(name), newSVpvn(vp->vp_strvalue, vp->vp_length), 0);
742 break;
743
744 case FR_TYPE_OCTETS:
745 (void)hv_store(rad_hv, name, strlen(name),
746 newSVpvn((char const *)vp->vp_octets, vp->vp_length), 0);
747 break;
748
750 {
751 HV *hv;
752 hv = newHV();
753 perl_store_vps(request, &vp->vp_group, hv, vp->da->name, false);
754 (void)hv_store(rad_hv, name, strlen(name), newRV_noinc((SV *)hv), 0);
755 }
756 break;
757
758 default:
759 {
760 char buffer[1024];
761 ssize_t slen;
762
764 (void)hv_store(rad_hv, name, strlen(name),
765 newSVpvn(buffer, (size_t)(slen)), 0);
766 }
767 break;
768 }
769 }
770 REXDENT();
771}
772
773static int get_hv_content(TALLOC_CTX *ctx, request_t *request, HV *my_hv, fr_pair_list_t *vps, const char *list_name,
774 fr_dict_attr_t const *parent, bool dbg_print);
775
776/*
777 *
778 * Verify that a Perl SV is a string and save it in FreeRadius
779 * Value Pair Format
780 *
781 */
782static int pairadd_sv(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vps, char *key, SV *sv,
783 const char *list_name, fr_dict_attr_t const *parent, bool dbg_print)
784{
785 char *val;
786 fr_pair_t *vp;
787 STRLEN len;
788 fr_dict_attr_t const *da;
789
790 if (!SvOK(sv)) return -1;
791
792 val = SvPV(sv, len);
793
794 da = fr_dict_attr_by_name(NULL, parent, key);
795 if (!da) {
796 REDEBUG("Ignoring unknown attribute '%s'", key);
797 return -1;
798 }
799 fr_assert(da != NULL);
800
801 vp = fr_pair_afrom_da(ctx, da);
802 if (!vp) {
803 fail:
805 RPEDEBUG("Failed to create pair %s.%s = %s", list_name, key, val);
806 return -1;
807 }
808
809 switch (vp->vp_type) {
810 case FR_TYPE_STRING:
811 fr_pair_value_bstrndup(vp, val, len, true);
812 break;
813
814 case FR_TYPE_OCTETS:
815 fr_pair_value_memdup(vp, (uint8_t const *)val, len, true);
816 break;
817
819 {
820 HV *hv;
821 if (!SvROK(sv) || (SvTYPE(SvRV(sv)) != SVt_PVHV)) {
822 RPEDEBUG("%s should be retuned as a hash", vp->da->name);
823 goto fail;
824 }
825 hv = (HV *)SvRV(sv);
826 if (get_hv_content(vp, request, hv, &vp->vp_group, list_name, da, false) < 0) goto fail;
827 if (vp->vp_type == FR_TYPE_STRUCT) fr_pair_list_sort(&vp->vp_group, fr_pair_cmp_by_da);
828 }
829 break;
830
831 default:
832 if (fr_pair_value_from_str(vp, val, len, NULL, false) < 0) goto fail;
833 }
834 fr_pair_append(vps, vp);
835
837
838 if (dbg_print) RDEBUG2("%s.%pP", list_name, vp);
839 return 0;
840}
841
842/*
843 * Gets the content from hashes
844 */
845static int get_hv_content(TALLOC_CTX *ctx, request_t *request, HV *my_hv, fr_pair_list_t *vps,
846 const char *list_name, fr_dict_attr_t const *parent, bool dbg_print)
847{
848 SV *res_sv, **av_sv;
849 AV *av;
850 char *key;
851 I32 key_len, len, i, j;
852 int ret = 0;
853
854 for (i = hv_iterinit(my_hv); i > 0; i--) {
855 res_sv = hv_iternextsv(my_hv,&key,&key_len);
856 if (SvROK(res_sv) && (SvTYPE(SvRV(res_sv)) == SVt_PVAV)) {
857 av = (AV*)SvRV(res_sv);
858 len = av_len(av);
859 for (j = 0; j <= len; j++) {
860 av_sv = av_fetch(av, j, 0);
861 if (pairadd_sv(ctx, request, vps, key, *av_sv, list_name, parent, dbg_print) < 0) continue;
862 ret++;
863 }
864 } else {
865 if (pairadd_sv(ctx, request, vps, key, res_sv, list_name, parent, dbg_print) < 0) continue;
866 ret++;
867 }
868 }
869
870 if (!fr_pair_list_empty(vps)) PAIR_LIST_VERIFY(vps);
871
872 return ret;
873}
874
875/*
876 * Call the function_name inside the module
877 * Store all vps in hashes %RAD_CONFIG %RAD_REPLY %RAD_REQUEST
878 *
879 */
880static unlang_action_t CC_HINT(nonnull) mod_perl(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
881{
882 rlm_perl_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_perl_t);
883 perl_call_env_t *func = talloc_get_type_abort(mctx->env_data, perl_call_env_t);
884 PerlInterpreter *interp = ((rlm_perl_thread_t *)talloc_get_type_abort(mctx->thread, rlm_perl_thread_t))->perl;
885 fr_pair_list_t vps;
886 int ret=0, count;
887 STRLEN n_a;
888
889 HV *rad_reply_hv;
890 HV *rad_config_hv;
891 HV *rad_request_hv;
892 HV *rad_state_hv;
893
894 /*
895 * call_env parsing will have established the function name to call.
896 */
898
899 {
900 dTHXa(interp);
901 PERL_SET_CONTEXT(interp);
902 }
903
904 {
905 dSP;
906
907 ENTER;
908 SAVETMPS;
909
910 rad_reply_hv = get_hv("RAD_REPLY", 1);
911 rad_config_hv = get_hv("RAD_CONFIG", 1);
912 rad_request_hv = get_hv("RAD_REQUEST", 1);
913 rad_state_hv = get_hv("RAD_STATE", 1);
914
915 perl_store_vps(request, &request->request_pairs, rad_request_hv, "RAD_REQUEST", true);
916 perl_store_vps(request, &request->reply_pairs, rad_reply_hv, "RAD_REPLY", true);
917 perl_store_vps(request, &request->control_pairs, rad_config_hv, "RAD_CONFIG", true);
918 perl_store_vps(request, &request->session_state_pairs, rad_state_hv, "RAD_STATE", true);
919
920 /*
921 * Store pointer to request structure globally so radiusd::xlat works
922 */
923 rlm_perl_request = request;
924
925 PUSHMARK(SP);
926 /*
927 * This way %RAD_xx can be pushed onto stack as sub parameters.
928 * XPUSHs( newRV_noinc((SV *)rad_request_hv) );
929 * XPUSHs( newRV_noinc((SV *)rad_reply_hv) );
930 * XPUSHs( newRV_noinc((SV *)rad_config_hv) );
931 * PUTBACK;
932 */
933
934 count = call_pv(func->func->function_name, G_SCALAR | G_EVAL | G_NOARGS);
935
936 rlm_perl_request = NULL;
937
938 SPAGAIN;
939
940 if (SvTRUE(ERRSV)) {
941 REDEBUG("perl_embed:: module = %s , func = %s exit status= %s\n",
942 inst->module, func->func->function_name, SvPV(ERRSV,n_a));
943 (void)POPs;
944 ret = RLM_MODULE_FAIL;
945 } else if (count == 1) {
946 ret = POPi;
947 if (ret >= 100 || ret < 0) {
948 ret = RLM_MODULE_FAIL;
949 }
950 }
951
952
953 PUTBACK;
954 FREETMPS;
955 LEAVE;
956
957 fr_pair_list_init(&vps);
958 if (inst->replace.request &&
959 (get_hv_content(request->request_ctx, request, rad_request_hv, &vps, "request",
960 fr_dict_root(request->proto_dict), true)) > 0) {
961 fr_pair_list_free(&request->request_pairs);
962 fr_pair_list_append(&request->request_pairs, &vps);
963 }
964
965 if (inst->replace.reply &&
966 (get_hv_content(request->reply_ctx, request, rad_reply_hv, &vps, "reply",
967 fr_dict_root(request->proto_dict), true)) > 0) {
968 fr_pair_list_free(&request->reply_pairs);
969 fr_pair_list_append(&request->reply_pairs, &vps);
970 }
971
972 if (inst->replace.control &&
973 (get_hv_content(request->control_ctx, request, rad_config_hv, &vps, "control",
974 fr_dict_root(request->proto_dict), true)) > 0) {
975 fr_pair_list_free(&request->control_pairs);
976 fr_pair_list_append(&request->control_pairs, &vps);
977 }
978
979 if (inst->replace.session &&
980 (get_hv_content(request->session_state_ctx, request, rad_state_hv, &vps, "session-state",
981 fr_dict_root(request->proto_dict), true)) > 0) {
982 fr_pair_list_free(&request->session_state_pairs);
983 fr_pair_list_append(&request->session_state_pairs, &vps);
984 }
985 }
986
988}
989
991DIAG_OFF(shadow)
992static void rlm_perl_interp_free(PerlInterpreter *perl)
993{
994 void **handles;
995
996 {
997 dTHXa(perl);
998 PERL_SET_CONTEXT(perl);
999 }
1000
1001 handles = rlm_perl_get_handles(aTHX);
1002 if (handles) rlm_perl_close_handles(handles);
1003
1004 PL_perl_destruct_level = 2;
1005
1006 PL_origenviron = environ;
1007
1008 /*
1009 * FIXME: This shouldn't happen
1010 *
1011 */
1012 while (PL_scopestack_ix > 1) LEAVE;
1013
1014 perl_destruct(perl);
1015 perl_free(perl);
1016}
1017DIAG_ON(shadow)
1019
1021{
1022 rlm_perl_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_perl_t);
1023 rlm_perl_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_perl_thread_t);
1024 PerlInterpreter *interp;
1025 UV clone_flags = 0;
1026
1027 PERL_SET_CONTEXT(inst->perl);
1028
1029 interp = perl_clone(inst->perl, clone_flags);
1030 {
1031 dTHXa(interp); /* Sets the current thread's interpreter */
1032 }
1033# if PERL_REVISION >= 5 && PERL_VERSION <8
1034 call_pv("CLONE", 0);
1035# endif
1036 ptr_table_free(PL_ptr_table);
1037 PL_ptr_table = NULL;
1038
1039 PERL_SET_CONTEXT(aTHX);
1041
1042 t->perl = interp; /* Store perl interp for easy freeing later */
1043
1044 return 0;
1045}
1046
1048{
1049 rlm_perl_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_perl_thread_t);
1050
1052
1053 return 0;
1054}
1055
1056/** Check if a given Perl subroutine exists
1057 *
1058 */
1059static bool perl_func_exists(char const *func)
1060{
1061 char *eval_str;
1062 SV *val;
1063
1064 /*
1065 * Perl's "can" method checks if the object contains a subroutine of the given name.
1066 * We expect referenced subroutines to be in the "main" namespace.
1067 */
1068 eval_str = talloc_asprintf(NULL, "(main->can('%s') ? 1 : 0)", func);
1069 val = eval_pv(eval_str, TRUE);
1070 talloc_free(eval_str);
1071 return SvIV(val) ? true : false;
1072}
1073
1074/*
1075 * Do any per-module initialization that is separate to each
1076 * configured instance of the module. e.g. set up connections
1077 * to external databases, read configuration files, set up
1078 * dictionary entries, etc.
1079 *
1080 * If configuration information is given in the config section
1081 * that must be referenced in later calls, store a handle to it
1082 * in *instance otherwise put a null pointer there.
1083 *
1084 * Setup a hashes which we will use later
1085 * parse a module and give it a chance to live
1086 *
1087 */
1088static int mod_instantiate(module_inst_ctx_t const *mctx)
1089{
1090 rlm_perl_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_perl_t);
1091 perl_func_def_t *func = NULL;
1093 CONF_PAIR *cp;
1094 char *pair_name;
1095
1096 CONF_SECTION *conf = mctx->mi->conf;
1097 AV *end_AV;
1098
1099 char const **embed_c; /* Stupid Perl and lack of const consistency */
1100 char **embed;
1101 int ret = 0, argc = 0;
1102 char arg[] = "0";
1103
1104 CONF_SECTION *cs;
1105
1106 /*
1107 * Setup the argument array we pass to the perl interpreter
1108 */
1109 MEM(embed_c = talloc_zero_array(inst, char const *, 4));
1110 memcpy(&embed, &embed_c, sizeof(embed));
1111 embed_c[0] = NULL;
1112 if (inst->perl_flags) {
1113 embed_c[1] = inst->perl_flags;
1114 embed_c[2] = inst->module;
1115 embed_c[3] = arg;
1116 argc = 4;
1117 } else {
1118 embed_c[1] = inst->module;
1119 embed_c[2] = arg;
1120 argc = 3;
1121 }
1122
1123 /*
1124 * Allocate a new perl interpreter to do the parsing
1125 */
1126 if ((inst->perl = perl_alloc()) == NULL) {
1127 ERROR("No memory for allocating new perl interpreter!");
1128 return -1;
1129 }
1130 perl_construct(inst->perl); /* ...and initialise it */
1131
1132 PL_perl_destruct_level = 2;
1133 {
1134 dTHXa(inst->perl);
1135 }
1136 PERL_SET_CONTEXT(inst->perl);
1137
1138#if PERL_REVISION >= 5 && PERL_VERSION >=8
1139 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
1140#endif
1141
1142 ret = perl_parse(inst->perl, xs_init, argc, embed, NULL);
1143
1144 end_AV = PL_endav;
1145 PL_endav = (AV *)NULL;
1146
1147 if (ret) {
1148 ERROR("Perl_parse failed: %s not found or has syntax errors", inst->module);
1149 return -1;
1150 }
1151
1152 /* parse perl configuration sub-section */
1153 cs = cf_section_find(conf, "config", NULL);
1154 if (cs) {
1155 inst->rad_perlconf_hv = get_hv("RAD_PERLCONF", 1);
1156 perl_parse_config(cs, 0, inst->rad_perlconf_hv);
1157 }
1158
1159 inst->perl_parsed = true;
1160 perl_run(inst->perl);
1161
1162 /*
1163 * The call_env parser has found all the places the module is called
1164 * Check for config options which set the subroutine name, falling back to
1165 * automatic subroutine names based on section name.
1166 */
1167 if (!inst->funcs_init) fr_rb_inline_init(&inst->funcs, perl_func_def_t, node, perl_func_def_cmp, NULL);
1168 func = fr_rb_iter_init_inorder(&iter, &inst->funcs);
1169 while (func) {
1170 /*
1171 * Check for func_<name1>_<name2> or func_<name1> config pairs.
1172 */
1173 if (func->name2) {
1174 pair_name = talloc_asprintf(func, "func_%s_%s", func->name1, func->name2);
1175 cp = cf_pair_find(mctx->mi->conf, pair_name);
1176 talloc_free(pair_name);
1177 if (cp) goto found_func;
1178 }
1179 pair_name = talloc_asprintf(func, "func_%s", func->name1);
1180 cp = cf_pair_find(conf, pair_name);
1181 talloc_free(pair_name);
1182 found_func:
1183 if (cp){
1184 func->function_name = cf_pair_value(cp);
1185 if (!perl_func_exists(func->function_name)) {
1186 cf_log_err(cp, "Perl subroutine %s does not exist", func->function_name);
1187 return -1;
1188 }
1189 /*
1190 * If no pair was found, then use <name1>_<name2> or <name1> as the function to call.
1191 */
1192 } else if (func->name2) {
1193 func->function_name = talloc_asprintf(func, "%s_%s", func->name1, func->name2);
1194 if (!perl_func_exists(func->function_name)) {
1196 goto name1_only;
1197 }
1198 } else {
1199 name1_only:
1200 func->function_name = func->name1;
1201 if (!perl_func_exists(func->function_name)) {
1202 cf_log_err(cp, "Perl subroutine %s does not exist", func->function_name);
1203 return -1;
1204 }
1205 }
1206
1207 func = fr_rb_iter_next_inorder(&iter);
1208 }
1209
1210 PL_endav = end_AV;
1211
1212 return 0;
1213}
1214
1215/*
1216 * Detach a instance give a chance to a module to make some internal setup ...
1217 */
1218DIAG_OFF(nested-externs)
1219static int mod_detach(module_detach_ctx_t const *mctx)
1220{
1221 rlm_perl_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_perl_t);
1222 int ret = 0, count = 0;
1223
1224
1225 if (inst->perl_parsed) {
1226 dTHXa(inst->perl);
1227 PERL_SET_CONTEXT(inst->perl);
1228 if (inst->rad_perlconf_hv != NULL) hv_undef(inst->rad_perlconf_hv);
1229
1230 if (inst->func_detach) {
1231 dSP; ENTER; SAVETMPS;
1232 PUSHMARK(SP);
1233
1234 count = call_pv(inst->func_detach, G_SCALAR | G_EVAL );
1235 SPAGAIN;
1236
1237 if (count == 1) {
1238 ret = POPi;
1239 if (ret >= 100 || ret < 0) {
1240 ret = RLM_MODULE_FAIL;
1241 }
1242 }
1243 PUTBACK;
1244 FREETMPS;
1245 LEAVE;
1246 }
1247 }
1248
1250
1251 return ret;
1252}
1253DIAG_ON(nested-externs)
1254
1255static int mod_bootstrap(module_inst_ctx_t const *mctx)
1256{
1257 xlat_t *xlat;
1258
1259 xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, NULL, perl_xlat, FR_TYPE_VOID);
1261
1262 return 0;
1263}
1264
1265static int mod_load(void)
1266{
1267 char const **embed_c; /* Stupid Perl and lack of const consistency */
1268 char **embed;
1269 char **envp = NULL;
1270 int argc = 0;
1271
1272#define LOAD_INFO(_fmt, ...) fr_log(LOG_DST, L_INFO, __FILE__, __LINE__, "rlm_perl - " _fmt, ## __VA_ARGS__)
1273#define LOAD_WARN(_fmt, ...) fr_log_perror(LOG_DST, L_WARN, __FILE__, __LINE__, \
1274 &(fr_log_perror_format_t){ \
1275 .first_prefix = "rlm_perl - ", \
1276 .subsq_prefix = "rlm_perl - ", \
1277 }, \
1278 _fmt, ## __VA_ARGS__)
1279
1280 LOAD_INFO("Perl version: %s", PERL_API_VERSION_STRING);
1281 dependency_version_number_add(NULL, "perl", PERL_API_VERSION_STRING);
1282
1283 /*
1284 * Load perl using RTLD_GLOBAL and dlopen.
1285 * This fixes issues where Perl C extensions
1286 * can't find the symbols they need.
1287 */
1288 perl_dlhandle = dl_open_by_sym("perl_construct", RTLD_NOW | RTLD_GLOBAL);
1289 if (!perl_dlhandle) LOAD_WARN("Failed loading libperl symbols into global symbol table");
1290
1291 /*
1292 * Setup the argument array we pass to the perl interpreter
1293 */
1294 MEM(embed_c = talloc_zero_array(NULL, char const *, 1));
1295 memcpy(&embed, &embed_c, sizeof(embed));
1296 embed_c[0] = NULL;
1297 argc = 1;
1298
1299 PERL_SYS_INIT3(&argc, &embed, &envp);
1300
1301 talloc_free(embed_c);
1302
1303 return 0;
1304}
1305
1306static void mod_unload(void)
1307{
1308 if (perl_dlhandle) dlclose(perl_dlhandle);
1309 PERL_SYS_TERM();
1310}
1311
1312/*
1313 * Restrict automatic Perl function names to lowercase characters, numbers and underscore
1314 * meaning that a module call in `recv Access-Request` will look for `recv_access_request`
1315 */
1316static void perl_func_name_safe(char *name) {
1317 char *p;
1318 size_t i;
1319
1320 p = name;
1321 for (i = 0; i < talloc_array_length(name); i++) {
1322 *p = tolower(*p);
1323 if (!strchr("abcdefghijklmnopqrstuvwxyz1234567890", *p)) *p = '_';
1324 p++;
1325 }
1326}
1327
1328static int perl_func_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, UNUSED tmpl_rules_t const *t_rules,
1329 UNUSED CONF_ITEM *ci, call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
1330{
1331 rlm_perl_t *inst = talloc_get_type_abort(cec->mi->data, rlm_perl_t);
1332 call_env_parsed_t *parsed;
1333 perl_func_def_t *func;
1334 void *found;
1335
1336 if (!inst->funcs_init) {
1338 inst->funcs_init = true;
1339 }
1340
1341 MEM(parsed = call_env_parsed_add(ctx, out,
1343 .name = "func",
1344 .flags = CALL_ENV_FLAG_PARSE_ONLY,
1345 .pair = {
1346 .parsed = {
1347 .offset = rule->pair.offset,
1349 }
1350 }
1351 }));
1352
1353 MEM(func = talloc_zero(inst, perl_func_def_t));
1354 func->name1 = talloc_strdup(func, cec->asked->name1);
1356 if (cec->asked->name2) {
1357 func->name2 = talloc_strdup(func, cec->asked->name2);
1359 }
1360 if (fr_rb_find_or_insert(&found, &inst->funcs, func) < 0) {
1361 talloc_free(func);
1362 return -1;
1363 }
1364
1365 /*
1366 * If the function call is already in the tree, use that entry.
1367 */
1368 if (found) {
1369 talloc_free(func);
1370 call_env_parsed_set_data(parsed, found);
1371 } else {
1372 call_env_parsed_set_data(parsed, func);
1373 }
1374 return 0;
1375}
1376
1384
1385/*
1386 * The module name should be the only globally exported symbol.
1387 * That is, everything else should be 'static'.
1388 *
1389 * If the module needs to temporarily modify it's instantiation
1390 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
1391 * The server will then take care of ensuring that the module
1392 * is single-threaded.
1393 */
1394extern module_rlm_t rlm_perl;
1396 .common = {
1397 .magic = MODULE_MAGIC_INIT,
1398 .name = "perl",
1399 .inst_size = sizeof(rlm_perl_t),
1400
1402 .onload = mod_load,
1403 .unload = mod_unload,
1404 .bootstrap = mod_bootstrap,
1406 .detach = mod_detach,
1407
1408 .thread_inst_size = sizeof(rlm_perl_thread_t),
1409 .thread_instantiate = mod_thread_instantiate,
1410 .thread_detach = mod_thread_detach,
1411 },
1412 .method_group = {
1413 .bindings = (module_method_binding_t[]){
1414 { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_perl, .method_env = &perl_method_env },
1416 }
1417 }
1418};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
log_entry msg
Definition acutest.h:794
#define RCSID(id)
Definition build.h:485
#define DIAG_UNKNOWN_PRAGMAS
Definition build.h:458
#define DIAG_ON(_x)
Definition build.h:460
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define UNUSED
Definition build.h:317
#define DIAG_OFF(_x)
Definition build.h:459
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:644
void call_env_parsed_set_data(call_env_parsed_t *parsed, void const *data)
Assign data to a call_env_parsed_t.
Definition call_env.c:701
#define CALL_ENV_TERMINATOR
Definition call_env.h:236
#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
section_name_t const * asked
The actual name1/name2 that resolved to a module_method_binding_t.
Definition call_env.h:232
@ CALL_ENV_FLAG_PARSE_ONLY
The result of parsing will not be evaluated at runtime.
Definition call_env.h:85
@ CALL_ENV_FLAG_PARSE_MISSING
If this subsection is missing, still parse it.
Definition call_env.h:88
@ CALL_ENV_PARSE_TYPE_VOID
Output of the parsing phase is undefined (a custom structure).
Definition call_env.h:62
module_instance_t const * mi
Module instance that the callenv is registered to.
Definition call_env.h:229
#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
Per method call config.
Definition call_env.h:180
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:658
void * data
Pointer to a static variable to write the parsed value to.
Definition cf_parse.h:609
#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:284
#define FR_CONF_OFFSET_FLAGS(_name, _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:272
#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:313
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:434
@ CONF_FLAG_FILE_INPUT
File matching value must exist, and must be readable.
Definition cf_parse.h:440
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:595
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
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1170
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1027
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:683
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition cf_util.c:1438
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:617
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:1593
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1577
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_item_next(_parent, _curr)
Definition cf_util.h:92
#define CF_IDENT_ANY
Definition cf_util.h:78
static int split(char **input, char **output, bool syntax_string)
Definition command.c:393
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:288
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:406
static void * fr_dcursor_next_peek(fr_dcursor_t *cursor)
Return the next iterator item without advancing the cursor.
Definition dcursor.h:303
#define MEM(x)
Definition debug.h:36
int dependency_version_number_add(CONF_SECTION *cs, char const *name, char const *version)
Add a library/server version pair to the main configuration.
Definition dependency.c:152
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3265
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2402
static fr_slen_t in
Definition dict.h:833
Test enumeration values.
Definition dict_test.h:92
void * dl_open_by_sym(char const *sym_name, int flags)
Utility function to dlopen the library containing a particular symbol.
Definition dl.c:186
#define RTLD_NOW
Definition dl.c:44
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
static xlat_action_t perl_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Call perl code using an xlat.
Definition rlm_perl.c:460
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:443
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define RINDENT()
Indent R* messages by one level.
Definition log.h:430
talloc_free(reap)
fr_log_t default_log
Definition log.c:288
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition log.c:580
#define ENTER(_x)
Definition machine.h:93
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_VOID
User data.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
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 * thread
Thread instance data.
Definition module_ctx.h:67
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 detach calls.
Definition module_ctx.h:56
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:243
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition pair.c:2937
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, UNUSED bool tainted)
Convert string value to native attribute value.
Definition pair.c:2591
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1347
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:285
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
Definition pair.c:2787
int8_t fr_pair_cmp_by_da(void const *a, void const *b)
Order attributes by their da, and tag.
Definition pair.c:1846
static const conf_parser_t config[]
Definition base.c:183
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define WARN(fmt,...)
Definition radclient.h:47
static bool cleanup
Definition radsniff.c:60
static rs_t * conf
Definition radsniff.c:53
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
Definition rb.c:824
int fr_rb_find_or_insert(void **found, fr_rb_tree_t *tree, void const *data)
Attempt to find current data in the tree, if it does not exist insert it.
Definition rb.c:598
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:850
#define fr_rb_inline_init(_tree, _type, _field, _data_cmp, _data_free)
Initialises a red black tree.
Definition rb.h:180
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:321
The main red black tree structure.
Definition rb.h:73
#define RETURN_MODULE_RCODE(_rcode)
Definition rcode.h:64
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:42
static int perl_sv_to_vblist(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, SV *sv)
Parse a Perl SV and create value boxes, appending to a list.
Definition rlm_perl.c:343
fr_rb_node_t node
Node in tree of function calls.
Definition rlm_perl.c:68
static int mod_detach(module_detach_ctx_t const *mctx)
Definition rlm_perl.c:1219
static int mod_load(void)
Definition rlm_perl.c:1265
PerlInterpreter * perl
Thread specific perl interpreter.
Definition rlm_perl.c:98
static bool perl_func_exists(char const *func)
Check if a given Perl subroutine exists.
Definition rlm_perl.c:1059
HV * rad_perlconf_hv
holds "config" items (perl RAD_PERLCONF hash).
Definition rlm_perl.c:93
rlm_perl_replace_t replace
Definition rlm_perl.c:92
static void perl_func_name_safe(char *name)
Definition rlm_perl.c:1316
static xlat_arg_parser_t const perl_xlat_args[]
Definition rlm_perl.c:450
char const * func_detach
Function to run when mod_detach is run.
Definition rlm_perl.c:88
char const * function_name
Name of the function being called.
Definition rlm_perl.c:65
static void ** rlm_perl_get_handles(pTHX)
Definition rlm_perl.c:159
bool perl_parsed
Definition rlm_perl.c:91
static const conf_parser_t replace_config[]
Definition rlm_perl.c:103
static XS(XS_radiusd_log)
Definition rlm_perl.c:214
EXTERN_C void boot_DynaLoader(pTHX_ CV *cv)
static void perl_parse_config(CONF_SECTION *cs, int lvl, HV *rad_hv)
Definition rlm_perl.c:587
char const * perl_flags
Definition rlm_perl.c:89
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_perl.c:1255
char * name1
Section name1 where this is called.
Definition rlm_perl.c:66
#define dl_modules
Definition rlm_perl.c:150
module_rlm_t rlm_perl
Definition rlm_perl.c:1395
static void rlm_perl_interp_free(PerlInterpreter *perl)
Definition rlm_perl.c:992
char const *fr_rb_tree_t funcs
Tree of function calls found by call_env parser.
Definition rlm_perl.c:86
static void mod_unload(void)
Definition rlm_perl.c:1306
static void xs_init(pTHX)
Definition rlm_perl.c:267
static int8_t perl_func_def_cmp(void const *one, void const *two)
How to compare two Perl function calls.
Definition rlm_perl.c:129
#define LOAD_WARN(_fmt,...)
static void rlm_perl_close_handles(void **handles)
Definition rlm_perl.c:193
static void perl_store_vps(request_t *request, fr_pair_list_t *vps, HV *rad_hv, const char *hash_name, bool dbg_print)
Definition rlm_perl.c:699
bool session
Should the session list be replaced after module call.
Definition rlm_perl.c:61
static int pairadd_sv(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vps, char *key, SV *sv, const char *list_name, fr_dict_attr_t const *parent, bool dbg_print)
Definition rlm_perl.c:782
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Definition rlm_perl.c:1020
PerlInterpreter * perl
Definition rlm_perl.c:90
static void perl_vp_to_svpvn_element(request_t *request, AV *av, fr_pair_t *vp, int *i, const char *hash_name, bool dbg_print)
Definition rlm_perl.c:649
char * name2
Section name2 where this is called.
Definition rlm_perl.c:67
#define dl_librefs
Definition rlm_perl.c:149
static unlang_action_t mod_perl(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_perl.c:880
static int perl_vblist_to_av(AV *av, fr_value_box_list_t *head)
Convert a list of value boxes to a Perl array for passing to subroutines.
Definition rlm_perl.c:289
static void * perl_dlhandle
To allow us to load perl's symbols into the global symbol table.
Definition rlm_perl.c:101
#define LOAD_INFO(_fmt,...)
static const conf_parser_t module_config[]
Definition rlm_perl.c:114
static int get_hv_content(TALLOC_CTX *ctx, request_t *request, HV *my_hv, fr_pair_list_t *vps, const char *list_name, fr_dict_attr_t const *parent, bool dbg_print)
Definition rlm_perl.c:845
static _Thread_local request_t * rlm_perl_request
Definition rlm_perl.c:147
static const call_env_method_t perl_method_env
Definition rlm_perl.c:1377
bool reply
Should the reply list be replaced after module call.
Definition rlm_perl.c:59
bool funcs_init
Has the tree been initialised.
Definition rlm_perl.c:87
bool control
Should the control list be replaced after module call.
Definition rlm_perl.c:60
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Definition rlm_perl.c:1047
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_perl.c:1088
perl_func_def_t * func
Definition rlm_perl.c:72
static void rlm_perl_clear_handles(pTHX)
Definition rlm_perl.c:151
bool request
Should the request list be replaced after module call.
Definition rlm_perl.c:58
static int perl_func_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, UNUSED tmpl_rules_t const *t_rules, UNUSED CONF_ITEM *ci, call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
Definition rlm_perl.c:1328
static char const * name
static int instantiate(module_inst_ctx_t const *mctx)
Definition rlm_rest.c:1313
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:40
char const * name2
Second section name. Usually a packet type like 'access-request', 'access-accept',...
Definition section.h:46
char const * name1
First section name. Usually a verb like 'recv', 'send', etc...
Definition section.h:45
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:330
size_t inst_size
Size of the module's instance data.
Definition module.h:204
void * data
Module's instance data.
Definition module.h:272
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:151
Named methods exported by a module.
Definition module.h:173
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:332
return count
Definition module.c:155
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define talloc_get_type_abort_const
Definition talloc.h:282
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:224
@ T_INVALID
Definition token.h:39
@ T_BARE_WORD
Definition token.h:120
bool required
Argument must be present, and non-empty.
Definition xlat.h:145
@ XLAT_ARG_VARIADIC_EMPTY_KEEP
Empty argument groups are left alone, and either passed through as empty groups or null boxes.
Definition xlat.h:136
static fr_slen_t head
Definition xlat.h:416
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:166
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
ssize_t xlat_aeval(TALLOC_CTX *ctx, char **out, request_t *request, char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx))
Definition xlat_eval.c:1716
Definition for a single argument consumend by an xlat function.
Definition xlat.h:144
#define ATTRIBUTE_EQ(_x, _y)
Definition pair.h:148
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
#define PAIR_VERIFY(_x)
Definition pair.h:191
void fr_pair_list_sort(fr_pair_list_t *list, fr_cmp_t cmp)
Sort a doubly linked list of fr_pair_ts using merge sort.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
ssize_t fr_pair_print_value_quoted(fr_sbuff_t *out, fr_pair_t const *vp, fr_token_t quote)
Print the value of an attribute to a string.
Definition pair_print.c:53
#define PAIR_LIST_VERIFY(_x)
Definition pair.h:194
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:591
static fr_slen_t parent
Definition pair.h:845
#define FR_TYPE_STRUCTURAL
Definition types.h:296
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition value.c:5487
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:4382
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:632
int nonnull(2, 5))
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:643
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:217
static size_t char ** out
Definition value.h:1012
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:362