The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 64b2292bf1634f7f9edc4fdacd1f3cd649184b36 $
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  */
25 RCSID("$Id: 64b2292bf1634f7f9edc4fdacd1f3cd649184b36 $")
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 
37 DIAG_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__)
50 extern char **environ;
51 #endif
52 
53 #ifndef USE_ITHREADS
54 # error perl must be compiled with USE_ITHREADS
55 #endif
56 
57 /*
58  * Define a structure for our module configuration.
59  *
60  * These variables do not need to be in a structure, but it's
61  * a lot cleaner to do so, and a pointer to the structure can
62  * be used as the instance handle.
63  */
64 typedef struct {
65  /* Name of the perl module */
66  char const *module;
67 
68  /* Name of the functions for each module method */
69  char const *func_authorize;
70  char const *func_authenticate;
71  char const *func_accounting;
72  char const *func_preacct;
73  char const *func_detach;
74  char const *func_post_auth;
75  char const *perl_flags;
76  PerlInterpreter *perl;
77  bool perl_parsed;
78  HV *rad_perlconf_hv; //!< holds "config" items (perl %RAD_PERLCONF hash).
79 
81 
82 typedef struct {
83  PerlInterpreter *perl; //!< Thread specific perl interpreter.
85 
86 static void *perl_dlhandle; //!< To allow us to load perl's symbols into the global symbol table.
87 
88 /*
89  * A mapping of configuration file names to internal variables.
90  */
91 #define RLM_PERL_CONF(_x) { FR_CONF_OFFSET("func_" STRINGIFY(_x), rlm_perl_t, func_##_x), \
92  .data = NULL, .dflt = STRINGIFY(_x), .quote = T_INVALID }
93 
94 static const conf_parser_t module_config[] = {
96 
97  RLM_PERL_CONF(authorize),
98  RLM_PERL_CONF(authenticate),
99  RLM_PERL_CONF(post_auth),
100  RLM_PERL_CONF(accounting),
101  RLM_PERL_CONF(preacct),
102  RLM_PERL_CONF(detach),
103 
104  { FR_CONF_OFFSET("perl_flags", rlm_perl_t, perl_flags) },
105 
107 };
108 
109 /*
110  * man perlembed
111  */
112 EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);
113 
114 static _Thread_local request_t *rlm_perl_request;
115 
116 # define dl_librefs "DynaLoader::dl_librefs"
117 # define dl_modules "DynaLoader::dl_modules"
118 static void rlm_perl_clear_handles(pTHX)
119 {
120  AV *librefs = get_av(dl_librefs, false);
121  if (librefs) {
122  av_clear(librefs);
123  }
124 }
125 
126 static void **rlm_perl_get_handles(pTHX)
127 {
128  I32 i;
129  AV *librefs = get_av(dl_librefs, false);
130  AV *modules = get_av(dl_modules, false);
131  void **handles;
132 
133  if (!librefs) return NULL;
134 
135  if (!(AvFILL(librefs) >= 0)) {
136  return NULL;
137  }
138 
139  MEM(handles = talloc_array(NULL, void *, AvFILL(librefs) + 2));
140  for (i = 0; i <= AvFILL(librefs); i++) {
141  void *handle;
142  SV *handle_sv = *av_fetch(librefs, i, false);
143  if (!handle_sv) {
144  ERROR("Could not fetch $%s[%d]!", dl_librefs, (int)i);
145  continue;
146  }
147  handle = (void *)SvIV(handle_sv);
148 
149  if (handle) handles[i] = handle;
150  }
151 
152  av_clear(modules);
153  av_clear(librefs);
154 
155  handles[i] = (void *)0;
156 
157  return handles;
158 }
159 
160 static void rlm_perl_close_handles(void **handles)
161 {
162  int i;
163 
164  if (!handles) {
165  return;
166  }
167 
168  for (i = 0; handles[i]; i++) {
169  DEBUG("Close %p", handles[i]);
170  dlclose(handles[i]);
171  }
172 
173  talloc_free(handles);
174 }
175 
176 /*
177  * This is wrapper for fr_log
178  * Now users can call radiusd::log(level,msg) which is the same
179  * as calling fr_log from C code.
180  */
181 static XS(XS_radiusd_log)
182 {
183  dXSARGS;
184  if (items !=2)
185  croak("Usage: radiusd::log(level, message)");
186  {
187  int level;
188  char *msg;
189 
190  level = (int) SvIV(ST(0));
191  msg = (char *) SvPV(ST(1), PL_na);
192 
193  /*
194  * Because 'msg' is a 'char *', we don't want '%s', etc.
195  * in it to give us printf-style vulnerabilities.
196  */
197  fr_log(&default_log, level, __FILE__, __LINE__, "rlm_perl: %s", msg);
198  }
199  XSRETURN_NO;
200 }
201 
202 /*
203  * This is a wrapper for xlat_aeval
204  * Now users are able to get data that is accessible only via xlat
205  * e.g. %client(...)
206  * Call syntax is radiusd::xlat(string), string will be handled the
207  * same way it is described in EXPANSIONS section of man unlang
208  */
209 static XS(XS_radiusd_xlat)
210 {
211  dXSARGS;
212  char *in_str;
213  char *expanded;
214  ssize_t slen;
215  request_t *request;
216 
217  if (items != 1) croak("Usage: radiusd::xlat(string)");
218 
219  request = rlm_perl_request;
220 
221  in_str = (char *) SvPV(ST(0), PL_na);
222 
223  slen = xlat_aeval(request, &expanded, request, in_str, NULL, NULL);
224  if (slen < 0) {
225  REDEBUG("Error parsing xlat '%s'", in_str);
226  XSRETURN_UNDEF;
227  }
228 
229  XST_mPV(0, expanded);
230  talloc_free(expanded);
231  XSRETURN(1);
232 }
233 
234 static void xs_init(pTHX)
235 {
236  char const *file = __FILE__;
237 
238  /* DynaLoader is a special case */
239  newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
240 
241  newXS("radiusd::log",XS_radiusd_log, "rlm_perl");
242  newXS("radiusd::xlat",XS_radiusd_xlat, "rlm_perl");
243 }
244 
245 /** Convert a list of value boxes to a Perl array for passing to subroutines
246  *
247  * The Perl array object should be created before calling this
248  * to populate it.
249  *
250  * @param[in,out] av Perl array object to append values to.
251  * @param[in] head of VB list.
252  * @return
253  * - 0 on success
254  * - -1 on failure
255  */
256 static int perl_vblist_to_av(AV *av, fr_value_box_list_t *head) {
257  fr_value_box_t *vb = NULL;
258  SV *sv;
259 
260  while ((vb = fr_value_box_list_next(head, vb))) {
261  switch (vb->type) {
262  case FR_TYPE_STRING:
263  sv = newSVpvn(vb->vb_strvalue, vb->vb_length);
264  break;
265 
266  case FR_TYPE_OCTETS:
267  sv = newSVpvn((char const *)vb->vb_octets, vb->vb_length);
268  break;
269 
270  case FR_TYPE_GROUP:
271  {
272  AV *sub_av;
273  sub_av = newAV();
274  perl_vblist_to_av(sub_av, &vb->vb_group);
275  sv = newRV_inc((SV *)sub_av);
276  }
277  break;
278  default:
279  {
280  char buffer[1024];
281  ssize_t slen;
282 
283  slen = fr_value_box_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), vb, NULL);
284  if (slen < 0) return -1;
285  sv = newSVpvn(buffer, (size_t)slen);
286  }
287  break;
288  }
289  if (!sv) return -1;
290  if (vb->tainted) SvTAINT(sv);
291  av_push(av, sv);
292  }
293  return 0;
294 }
295 
296 /** Parse a Perl SV and create value boxes, appending to a list
297  *
298  * For parsing values passed back from a Perl subroutine
299  *
300  * When hashes are returned, first the key is added as a value box then the value
301  *
302  * @param[in] ctx to allocate boxes in.
303  * @param[out] list to append value boxes to.
304  * @param[in] request being handled - only used for debug messages
305  * @param[in] sv to parse
306  * @return
307  * - 0 on success
308  * - -1 on failure
309  */
310 static int perl_sv_to_vblist(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, SV *sv) {
311  fr_value_box_t *vb = NULL;
312  char *tmp;
313  STRLEN len;
314  AV *av;
315  HV *hv;
316  I32 sv_len, i;
317  int type;
318 
319  type = SvTYPE(sv);
320 
321  switch (type) {
322  case SVt_IV:
323  /* Integer or Reference */
324  if (SvROK(sv)) {
325  DEBUG3("Reference returned");
326  if (perl_sv_to_vblist(ctx, list, request, SvRV(sv)) < 0) return -1;
327  break;
328  }
329  DEBUG3("Integer returned");
330  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_INT32, NULL));
331  vb->vb_int32 = SvIV(sv);
332  break;
333 
334  case SVt_NV:
335  /* Float */
336  DEBUG3("Float returned");
337  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_FLOAT64, NULL));
338  vb->vb_float64 = SvNV(sv);
339  break;
340 
341  case SVt_PV:
342  /* String */
343  DEBUG3("String returned");
344  tmp = SvPVutf8(sv, len);
345  MEM(vb = fr_value_box_alloc_null(ctx));
346  if (fr_value_box_bstrndup(vb, vb, NULL, tmp, len, SvTAINTED(sv)) < 0) {
347  talloc_free(vb);
348  RPEDEBUG("Failed to allocate %ld for output", len);
349  return -1;
350  }
351  break;
352 
353  case SVt_PVAV:
354  /* Array */
355  {
356  SV **av_sv;
357  DEBUG3("Array returned");
358  av = (AV*)sv;
359  sv_len = av_len(av);
360  for (i = 0; i <= sv_len; i++) {
361  av_sv = av_fetch(av, i, 0);
362  if (SvOK(*av_sv)) {
363  if (perl_sv_to_vblist(ctx, list, request, *av_sv) < 0) return -1;
364  }
365  }
366  }
367  break;
368 
369  case SVt_PVHV:
370  /* Hash */
371  {
372  SV *hv_sv;
373  DEBUG3("Hash returned");
374  hv = (HV*)sv;
375  for (i = hv_iterinit(hv); i > 0; i--) {
376  hv_sv = hv_iternextsv(hv, &tmp, &sv_len);
377  /*
378  * Add key first
379  */
380  MEM(vb = fr_value_box_alloc_null(ctx));
381  if (fr_value_box_bstrndup(vb, vb, NULL, tmp, sv_len, SvTAINTED(hv_sv)) < 0) {
382  talloc_free(vb);
383  RPEDEBUG("Failed to allocate %d for output", sv_len);
384  return -1;
385  }
386  fr_value_box_list_insert_tail(list, vb);
387 
388  /*
389  * Now process value
390  */
391  if (perl_sv_to_vblist(ctx, list, request, hv_sv) < 0) return -1;
392 
393  }
394  /*
395  * Box has already been added to list - return
396  */
397  return 0;
398  }
399 
400  case SVt_NULL:
401  break;
402 
403  default:
404  RPEDEBUG("Perl returned unsupported data type %d", type);
405  return -1;
406 
407  }
408 
409  if (vb) {
410  vb->tainted = SvTAINTED(sv);
411  fr_value_box_list_insert_tail(list, vb);
412  }
413 
414  return 0;
415 }
416 
418  { .required = true, .single = true, .type = FR_TYPE_STRING },
419  { .variadic = XLAT_ARG_VARIADIC_EMPTY_KEEP, .type = FR_TYPE_VOID },
421 };
422 
423 /** Call perl code using an xlat
424  *
425  * @ingroup xlat_functions
426  */
427 static xlat_action_t perl_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
428  xlat_ctx_t const *xctx,
429  request_t *request, fr_value_box_list_t *in)
430 {
432  int count, i;
434  STRLEN n_a;
435  fr_value_box_t *func = fr_value_box_list_pop_head(in);
436  fr_value_box_t *child;
437  SV *sv;
438  AV *av;
439  fr_value_box_list_t list, sub_list;
440  fr_value_box_t *vb = NULL;
441 
442  fr_value_box_list_init(&list);
443  fr_value_box_list_init(&sub_list);
444 
445  {
446  dTHXa(t->perl);
447  PERL_SET_CONTEXT(t->perl);
448  }
449 
450  {
451  dSP;
452  ENTER;SAVETMPS;
453 
454  PUSHMARK(SP);
455 
457  fr_assert(arg->type == FR_TYPE_GROUP);
458  if (fr_value_box_list_empty(&arg->vb_group)) continue;
459 
460  if (fr_value_box_list_num_elements(&arg->vb_group) == 1) {
461  child = fr_value_box_list_head(&arg->vb_group);
462  /*
463  * Single child value - add as scalar
464  */
465  if (child->vb_length == 0) continue;
466  DEBUG3("Passing single value %pV", child);
467  sv = newSVpvn(child->vb_strvalue, child->vb_length);
468  if (child->tainted) SvTAINT(sv);
469  XPUSHs(sv_2mortal(sv));
470  continue;
471  }
472 
473  /*
474  * Multiple child values - create array and pass reference
475  */
476  av = newAV();
477  perl_vblist_to_av(av, &arg->vb_group);
478  DEBUG3("Passing list as array %pM", &arg->vb_group);
479  sv = newRV_inc((SV *)av);
480  XPUSHs(sv_2mortal(sv));
481  }
482 
483  PUTBACK;
484 
485  count = call_pv(func->vb_strvalue, G_ARRAY | G_EVAL);
486 
487  SPAGAIN;
488  if (SvTRUE(ERRSV)) {
489  REDEBUG("Exit %s", SvPV(ERRSV,n_a));
490  (void)POPs;
491  goto cleanup;
492  }
493 
494  /*
495  * As results are popped from a stack, they are in reverse
496  * sequence. Add to a temporary list and then prepend to
497  * main list.
498  */
499  for (i = 0; i < count; i++) {
500  sv = POPs;
501  if (perl_sv_to_vblist(ctx, &sub_list, request, sv) < 0) goto cleanup;
502  fr_value_box_list_move_head(&list, &sub_list);
503  }
504  ret = XLAT_ACTION_DONE;
505 
506  /*
507  * Move the assembled list of boxes to the output
508  */
509  while ((vb = fr_value_box_list_pop_head(&list))) fr_dcursor_append(out, vb);
510 
511  cleanup:
512  PUTBACK;
513  FREETMPS;
514  LEAVE;
515 
516  }
517 
518  return ret;
519 }
520 
521 /*
522  * Parse a configuration section, and populate a HV.
523  * This function is recursively called (allows to have nested hashes.)
524  */
525 static void perl_parse_config(CONF_SECTION *cs, int lvl, HV *rad_hv)
526 {
527  int indent_section = (lvl + 1) * 4;
528  int indent_item = (lvl + 2) * 4;
529 
530  if (!cs || !rad_hv) return;
531 
532  DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
533 
534  for (CONF_ITEM *ci = NULL; (ci = cf_item_next(cs, ci)); ) {
535  /*
536  * This is a section.
537  * Create a new HV, store it as a reference in current HV,
538  * Then recursively call perl_parse_config with this section and the new HV.
539  */
540  if (cf_item_is_section(ci)) {
541  CONF_SECTION *sub_cs = cf_item_to_section(ci);
542  char const *key = cf_section_name1(sub_cs); /* hash key */
543  HV *sub_hv;
544  SV *ref;
545 
546  if (!key) continue;
547 
548  if (hv_exists(rad_hv, key, strlen(key))) {
549  WARN("Ignoring duplicate config section '%s'", key);
550  continue;
551  }
552 
553  sub_hv = newHV();
554  ref = newRV_inc((SV*) sub_hv);
555 
556  (void)hv_store(rad_hv, key, strlen(key), ref, 0);
557 
558  perl_parse_config(sub_cs, lvl + 1, sub_hv);
559  } else if (cf_item_is_pair(ci)){
560  CONF_PAIR *cp = cf_item_to_pair(ci);
561  char const *key = cf_pair_attr(cp); /* hash key */
562  char const *value = cf_pair_value(cp); /* hash value */
563 
564  if (!key || !value) continue;
565 
566  /*
567  * This is an item.
568  * Store item attr / value in current HV.
569  */
570  if (hv_exists(rad_hv, key, strlen(key))) {
571  WARN("Ignoring duplicate config item '%s'", key);
572  continue;
573  }
574 
575  (void)hv_store(rad_hv, key, strlen(key), newSVpvn(value, strlen(value)), 0);
576 
577  DEBUG("%*s%s = %s", indent_item, " ", key, value);
578  }
579  }
580 
581  DEBUG("%*s}", indent_section, " ");
582 }
583 
584 static int mod_bootstrap(module_inst_ctx_t const *mctx)
585 {
586  xlat_t *xlat;
587 
588  xlat = xlat_func_register_module(NULL, mctx, NULL, perl_xlat, FR_TYPE_VOID);
590 
591  return 0;
592 }
593 
594 static void perl_vp_to_svpvn_element(request_t *request, AV *av, fr_pair_t const *vp,
595  int *i, const char *hash_name, const char *list_name)
596 {
597 
598  SV *sv;
599 
600  switch (vp->vp_type) {
601  case FR_TYPE_STRING:
602  RDEBUG2("$%s{'%s'}[%i] = &%s.%s -> '%s'", hash_name, vp->da->name, *i,
603  list_name, vp->da->name, vp->vp_strvalue);
604  sv = newSVpvn(vp->vp_strvalue, vp->vp_length);
605  break;
606 
607  case FR_TYPE_OCTETS:
608  RDEBUG2("$%s{'%s'}[%i] = &%s.%s -> 0x%pH", hash_name, vp->da->name, *i,
609  list_name, vp->da->name, &vp->data);
610  sv = newSVpvn((char const *)vp->vp_octets, vp->vp_length);
611  break;
612 
613  default:
614  {
615  char buffer[1024];
616  ssize_t slen;
617 
619  if (slen < 0) return;
620 
621  RDEBUG2("$%s{'%s'}[%i] = &%s.%s -> '%pV'", hash_name, vp->da->name, *i,
622  list_name, vp->da->name, fr_box_strvalue_len(buffer, (size_t)slen));
623  sv = newSVpvn(buffer, (size_t)slen);
624  }
625  break;
626  }
627 
628  if (!sv) return;
629  SvTAINT(sv);
630  av_push(av, sv);
631  (*i)++;
632 }
633 
634 /*
635  * get the vps and put them in perl hash
636  * If one VP have multiple values it is added as array_ref
637  * Example for this is Vendor-Specific.Cisco.AVPair that holds multiple values.
638  * Which will be available as array_ref in $RAD_REQUEST{'Vendor-Specific.Cisco.AVPair'}
639  */
640 static void perl_store_vps(UNUSED TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vps, HV *rad_hv,
641  const char *hash_name, const char *list_name)
642 {
643  fr_pair_t *vp;
644  fr_dcursor_t cursor;
645 
646  hv_undef(rad_hv);
647 
648  RINDENT();
650  for (vp = fr_pair_dcursor_init(&cursor, vps);
651  vp;
652  vp = fr_dcursor_next(&cursor)) {
653  fr_pair_t *next;
654  char const *name;
655  name = vp->da->name;
656 
657  /*
658  * We've sorted by type, then tag, so attributes of the
659  * same type/tag should follow on from each other.
660  */
661  if ((next = fr_dcursor_next_peek(&cursor)) && ATTRIBUTE_EQ(vp, next)) {
662  int i = 0;
663  AV *av;
664 
665  av = newAV();
666  perl_vp_to_svpvn_element(request, av, vp, &i, hash_name, list_name);
667  do {
668  perl_vp_to_svpvn_element(request, av, next, &i, hash_name, list_name);
669  fr_dcursor_next(&cursor);
670  } while ((next = fr_dcursor_next_peek(&cursor)) && ATTRIBUTE_EQ(vp, next));
671  (void)hv_store(rad_hv, name, strlen(name), newRV_noinc((SV *)av), 0);
672 
673  continue;
674  }
675 
676  /*
677  * It's a normal single valued attribute
678  */
679  switch (vp->vp_type) {
680  case FR_TYPE_STRING:
681  RDEBUG2("$%s{'%s'} = &%s.%s -> '%pV'", hash_name, vp->da->name, list_name,
682  vp->da->name, &vp->data);
683  (void)hv_store(rad_hv, name, strlen(name), newSVpvn(vp->vp_strvalue, vp->vp_length), 0);
684  break;
685 
686  case FR_TYPE_OCTETS:
687  RDEBUG2("$%s{'%s'} = &%s.%s -> %pV", hash_name, vp->da->name, list_name,
688  vp->da->name, &vp->data);
689  (void)hv_store(rad_hv, name, strlen(name),
690  newSVpvn((char const *)vp->vp_octets, vp->vp_length), 0);
691  break;
692 
693  default:
694  {
695  char buffer[1024];
696  ssize_t slen;
697 
699  RDEBUG2("$%s{'%s'} = &%s.%s -> '%pV'", hash_name, vp->da->name,
700  list_name, vp->da->name, fr_box_strvalue_len(buffer, (size_t)slen));
701  (void)hv_store(rad_hv, name, strlen(name),
702  newSVpvn(buffer, (size_t)(slen)), 0);
703  }
704  break;
705  }
706  }
707  REXDENT();
708 }
709 
710 /*
711  *
712  * Verify that a Perl SV is a string and save it in FreeRadius
713  * Value Pair Format
714  *
715  */
716 static int pairadd_sv(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vps, char *key, SV *sv,
717  const char *hash_name, const char *list_name)
718 {
719  char *val;
720  fr_pair_t *vp;
721  STRLEN len;
722  fr_dict_attr_t const *da;
723 
724  if (!SvOK(sv)) return -1;
725 
726  val = SvPV(sv, len);
727 
728  da = fr_dict_attr_search_by_qualified_oid(NULL, request->dict, key, true, true);
729  if (!da) {
730  REDEBUG("Ignoring unknown attribute '%s'", key);
731  return -1;
732  }
733  fr_assert(da != NULL);
734 
735  vp = fr_pair_afrom_da_nested(ctx, vps, da);
736  if (!vp) {
737  fail:
738  RPEDEBUG("Failed to create pair %s.%s = %s", list_name, key, val);
739  return -1;
740  }
741 
742  switch (vp->vp_type) {
743  case FR_TYPE_STRING:
744  fr_pair_value_bstrndup(vp, val, len, true);
745  break;
746 
747  case FR_TYPE_OCTETS:
748  fr_pair_value_memdup(vp, (uint8_t const *)val, len, true);
749  break;
750 
751  default:
752  if (fr_pair_value_from_str(vp, val, len, NULL, false) < 0) goto fail;
753  }
754 
755  PAIR_VERIFY(vp);
756 
757  RDEBUG2("&%s.%s = $%s{'%s'} -> '%s'", list_name, key, hash_name, key, val);
758  return 0;
759 }
760 
761 /*
762  * Gets the content from hashes
763  */
764 static int get_hv_content(TALLOC_CTX *ctx, request_t *request, HV *my_hv, fr_pair_list_t *vps,
765  const char *hash_name, const char *list_name)
766 {
767  SV *res_sv, **av_sv;
768  AV *av;
769  char *key;
770  I32 key_len, len, i, j;
771  int ret = 0;
772 
773  for (i = hv_iterinit(my_hv); i > 0; i--) {
774  res_sv = hv_iternextsv(my_hv,&key,&key_len);
775  if (SvROK(res_sv) && (SvTYPE(SvRV(res_sv)) == SVt_PVAV)) {
776  av = (AV*)SvRV(res_sv);
777  len = av_len(av);
778  for (j = 0; j <= len; j++) {
779  av_sv = av_fetch(av, j, 0);
780  if (pairadd_sv(ctx, request, vps, key, *av_sv, hash_name, list_name) < 0) continue;
781  ret++;
782  }
783  } else {
784  if (pairadd_sv(ctx, request, vps, key, res_sv, hash_name, list_name) < 0) continue;
785  ret++;
786  }
787  }
788 
789  if (!fr_pair_list_empty(vps)) PAIR_LIST_VERIFY(vps);
790 
791  return ret;
792 }
793 
794 /*
795  * Call the function_name inside the module
796  * Store all vps in hashes %RAD_CONFIG %RAD_REPLY %RAD_REQUEST
797  *
798  */
799 static unlang_action_t do_perl(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request,
800  PerlInterpreter *interp, char const *function_name)
801 {
802 
803  rlm_perl_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_perl_t);
804  fr_pair_list_t vps;
805  int ret=0, count;
806  STRLEN n_a;
807 
808  HV *rad_reply_hv;
809  HV *rad_config_hv;
810  HV *rad_request_hv;
811  HV *rad_state_hv;
812 
813  /*
814  * Radius has told us to call this function, but none
815  * is defined.
816  */
817  if (!function_name) RETURN_MODULE_FAIL;
818 
819  {
820  dTHXa(interp);
821  PERL_SET_CONTEXT(interp);
822  }
823 
824  {
825  dSP;
826 
827  ENTER;
828  SAVETMPS;
829 
830  rad_reply_hv = get_hv("RAD_REPLY", 1);
831  rad_config_hv = get_hv("RAD_CONFIG", 1);
832  rad_request_hv = get_hv("RAD_REQUEST", 1);
833  rad_state_hv = get_hv("RAD_STATE", 1);
834 
835  perl_store_vps(request->request_ctx, request, &request->request_pairs, rad_request_hv, "RAD_REQUEST", "request");
836  perl_store_vps(request->reply_ctx, request, &request->reply_pairs, rad_reply_hv, "RAD_REPLY", "reply");
837  perl_store_vps(request->control_ctx, request, &request->control_pairs, rad_config_hv, "RAD_CONFIG", "control");
838  perl_store_vps(request->session_state_ctx, request, &request->session_state_pairs, rad_state_hv, "RAD_STATE", "session-state");
839 
840  /*
841  * Store pointer to request structure globally so radiusd::xlat works
842  */
843  rlm_perl_request = request;
844 
845  PUSHMARK(SP);
846  /*
847  * This way %RAD_xx can be pushed onto stack as sub parameters.
848  * XPUSHs( newRV_noinc((SV *)rad_request_hv) );
849  * XPUSHs( newRV_noinc((SV *)rad_reply_hv) );
850  * XPUSHs( newRV_noinc((SV *)rad_config_hv) );
851  * PUTBACK;
852  */
853 
854  count = call_pv(function_name, G_SCALAR | G_EVAL | G_NOARGS);
855 
856  rlm_perl_request = NULL;
857 
858  SPAGAIN;
859 
860  if (SvTRUE(ERRSV)) {
861  REDEBUG("perl_embed:: module = %s , func = %s exit status= %s\n",
862  inst->module, function_name, SvPV(ERRSV,n_a));
863  (void)POPs;
864  ret = RLM_MODULE_FAIL;
865  } else if (count == 1) {
866  ret = POPi;
867  if (ret >= 100 || ret < 0) {
868  ret = RLM_MODULE_FAIL;
869  }
870  }
871 
872 
873  PUTBACK;
874  FREETMPS;
875  LEAVE;
876 
877  fr_pair_list_init(&vps);
878  if ((get_hv_content(request->request_ctx, request, rad_request_hv, &vps, "RAD_REQUEST", "request")) > 0) {
879  fr_pair_list_free(&request->request_pairs);
880  fr_pair_list_append(&request->request_pairs, &vps);
881  }
882 
883  if ((get_hv_content(request->reply_ctx, request, rad_reply_hv, &vps, "RAD_REPLY", "reply")) > 0) {
884  fr_pair_list_free(&request->reply_pairs);
885  fr_pair_list_append(&request->reply_pairs, &vps);
886  }
887 
888  if ((get_hv_content(request->control_ctx, request, rad_config_hv, &vps, "RAD_CONFIG", "control")) > 0) {
889  fr_pair_list_free(&request->control_pairs);
890  fr_pair_list_append(&request->control_pairs, &vps);
891  }
892 
893  if ((get_hv_content(request->session_state_ctx, request, rad_state_hv, &vps, "RAD_STATE", "session-state")) > 0) {
894  fr_pair_list_free(&request->session_state_pairs);
895  fr_pair_list_append(&request->session_state_pairs, &vps);
896  }
897  }
898 
899  RETURN_MODULE_RCODE(ret);
900 }
901 
902 #define RLM_PERL_FUNC(_x) \
903 static unlang_action_t CC_HINT(nonnull) mod_##_x(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) \
904 { \
905  rlm_perl_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_perl_t); \
906  return do_perl(p_result, mctx, request, \
907  ((rlm_perl_thread_t *)talloc_get_type_abort(mctx->thread, rlm_perl_thread_t))->perl, \
908  inst->func_##_x); \
909 }
910 
911 RLM_PERL_FUNC(authorize)
912 RLM_PERL_FUNC(authenticate)
913 RLM_PERL_FUNC(post_auth)
914 RLM_PERL_FUNC(preacct)
915 RLM_PERL_FUNC(accounting)
916 
918 DIAG_OFF(shadow)
919 static void rlm_perl_interp_free(PerlInterpreter *perl)
920 {
921  void **handles;
922 
923  {
924  dTHXa(perl);
925  PERL_SET_CONTEXT(perl);
926  }
927 
928  handles = rlm_perl_get_handles(aTHX);
929  if (handles) rlm_perl_close_handles(handles);
930 
931  PL_perl_destruct_level = 2;
932 
933  PL_origenviron = environ;
934 
935  /*
936  * FIXME: This shouldn't happen
937  *
938  */
939  while (PL_scopestack_ix > 1) LEAVE;
940 
941  perl_destruct(perl);
942  perl_free(perl);
943 }
944 DIAG_ON(shadow)
946 
948 {
949  rlm_perl_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_perl_t);
950  rlm_perl_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_perl_thread_t);
951  PerlInterpreter *interp;
952  UV clone_flags = 0;
953 
954  PERL_SET_CONTEXT(inst->perl);
955 
956  interp = perl_clone(inst->perl, clone_flags);
957  {
958  dTHXa(interp); /* Sets the current thread's interpreter */
959  }
960 # if PERL_REVISION >= 5 && PERL_VERSION <8
961  call_pv("CLONE", 0);
962 # endif
963  ptr_table_free(PL_ptr_table);
964  PL_ptr_table = NULL;
965 
966  PERL_SET_CONTEXT(aTHX);
968 
969  t->perl = interp; /* Store perl interp for easy freeing later */
970 
971  return 0;
972 }
973 
975 {
976  rlm_perl_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_perl_thread_t);
977 
979 
980  return 0;
981 }
982 
983 /*
984  * Do any per-module initialization that is separate to each
985  * configured instance of the module. e.g. set up connections
986  * to external databases, read configuration files, set up
987  * dictionary entries, etc.
988  *
989  * If configuration information is given in the config section
990  * that must be referenced in later calls, store a handle to it
991  * in *instance otherwise put a null pointer there.
992  *
993  * Setup a hashes which we will use later
994  * parse a module and give it a chance to live
995  *
996  */
997 static int mod_instantiate(module_inst_ctx_t const *mctx)
998 {
999  rlm_perl_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_perl_t);
1000  CONF_SECTION *conf = mctx->inst->conf;
1001  AV *end_AV;
1002 
1003  char const **embed_c; /* Stupid Perl and lack of const consistency */
1004  char **embed;
1005  int ret = 0, argc = 0;
1006  char arg[] = "0";
1007 
1008  CONF_SECTION *cs;
1009 
1010  /*
1011  * Setup the argument array we pass to the perl interpreter
1012  */
1013  MEM(embed_c = talloc_zero_array(inst, char const *, 4));
1014  memcpy(&embed, &embed_c, sizeof(embed));
1015  embed_c[0] = NULL;
1016  if (inst->perl_flags) {
1017  embed_c[1] = inst->perl_flags;
1018  embed_c[2] = inst->module;
1019  embed_c[3] = arg;
1020  argc = 4;
1021  } else {
1022  embed_c[1] = inst->module;
1023  embed_c[2] = arg;
1024  argc = 3;
1025  }
1026 
1027  /*
1028  * Allocate a new perl interpreter to do the parsing
1029  */
1030  if ((inst->perl = perl_alloc()) == NULL) {
1031  ERROR("No memory for allocating new perl interpreter!");
1032  return -1;
1033  }
1034  perl_construct(inst->perl); /* ...and initialise it */
1035 
1036  PL_perl_destruct_level = 2;
1037  {
1038  dTHXa(inst->perl);
1039  }
1040  PERL_SET_CONTEXT(inst->perl);
1041 
1042 #if PERL_REVISION >= 5 && PERL_VERSION >=8
1043  PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
1044 #endif
1045 
1046  ret = perl_parse(inst->perl, xs_init, argc, embed, NULL);
1047 
1048  end_AV = PL_endav;
1049  PL_endav = (AV *)NULL;
1050 
1051  if (ret) {
1052  ERROR("Perl_parse failed: %s not found or has syntax errors", inst->module);
1053  return -1;
1054  }
1055 
1056  /* parse perl configuration sub-section */
1057  cs = cf_section_find(conf, "config", NULL);
1058  if (cs) {
1059  inst->rad_perlconf_hv = get_hv("RAD_PERLCONF", 1);
1060  perl_parse_config(cs, 0, inst->rad_perlconf_hv);
1061  }
1062 
1063  inst->perl_parsed = true;
1064  perl_run(inst->perl);
1065 
1066  PL_endav = end_AV;
1067 
1068  return 0;
1069 }
1070 
1071 /*
1072  * Detach a instance give a chance to a module to make some internal setup ...
1073  */
1074 DIAG_OFF(nested-externs)
1075 static int mod_detach(module_detach_ctx_t const *mctx)
1076 {
1077  rlm_perl_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_perl_t);
1078  int ret = 0, count = 0;
1079 
1080 
1081  if (inst->perl_parsed) {
1082  dTHXa(inst->perl);
1083  PERL_SET_CONTEXT(inst->perl);
1084  if (inst->rad_perlconf_hv != NULL) hv_undef(inst->rad_perlconf_hv);
1085 
1086  if (inst->func_detach) {
1087  dSP; ENTER; SAVETMPS;
1088  PUSHMARK(SP);
1089 
1090  count = call_pv(inst->func_detach, G_SCALAR | G_EVAL );
1091  SPAGAIN;
1092 
1093  if (count == 1) {
1094  ret = POPi;
1095  if (ret >= 100 || ret < 0) {
1096  ret = RLM_MODULE_FAIL;
1097  }
1098  }
1099  PUTBACK;
1100  FREETMPS;
1101  LEAVE;
1102  }
1103  }
1104 
1105  rlm_perl_interp_free(inst->perl);
1106 
1107  return ret;
1108 }
1109 DIAG_ON(nested-externs)
1110 
1111 static int mod_load(void)
1112 {
1113  char const **embed_c; /* Stupid Perl and lack of const consistency */
1114  char **embed;
1115  char **envp = NULL;
1116  int argc = 0;
1117 
1118 #define LOAD_INFO(_fmt, ...) fr_log(LOG_DST, L_INFO, __FILE__, __LINE__, "rlm_perl - " _fmt, ## __VA_ARGS__)
1119 #define LOAD_WARN(_fmt, ...) fr_log_perror(LOG_DST, L_WARN, __FILE__, __LINE__, \
1120  &(fr_log_perror_format_t){ \
1121  .first_prefix = "rlm_perl - ", \
1122  .subsq_prefix = "rlm_perl - ", \
1123  }, \
1124  _fmt, ## __VA_ARGS__)
1125 
1126  LOAD_INFO("Perl version: %s", PERL_API_VERSION_STRING);
1127  dependency_version_number_add(NULL, "perl", PERL_API_VERSION_STRING);
1128 
1129  /*
1130  * Load perl using RTLD_GLOBAL and dlopen.
1131  * This fixes issues where Perl C extensions
1132  * can't find the symbols they need.
1133  */
1134  perl_dlhandle = dl_open_by_sym("perl_construct", RTLD_NOW | RTLD_GLOBAL);
1135  if (!perl_dlhandle) LOAD_WARN("Failed loading libperl symbols into global symbol table");
1136 
1137  /*
1138  * Setup the argument array we pass to the perl interpreter
1139  */
1140  MEM(embed_c = talloc_zero_array(NULL, char const *, 1));
1141  memcpy(&embed, &embed_c, sizeof(embed));
1142  embed_c[0] = NULL;
1143  argc = 1;
1144 
1145  PERL_SYS_INIT3(&argc, &embed, &envp);
1146 
1147  talloc_free(embed_c);
1148 
1149  return 0;
1150 }
1151 
1152 static void mod_unload(void)
1153 {
1154  if (perl_dlhandle) dlclose(perl_dlhandle);
1155  PERL_SYS_TERM();
1156 }
1157 
1158 
1159 /*
1160  * The module name should be the only globally exported symbol.
1161  * That is, everything else should be 'static'.
1162  *
1163  * If the module needs to temporarily modify it's instantiation
1164  * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
1165  * The server will then take care of ensuring that the module
1166  * is single-threaded.
1167  */
1168 extern module_rlm_t rlm_perl;
1170  .common = {
1171  .magic = MODULE_MAGIC_INIT,
1172  .name = "perl",
1173  .flags = MODULE_TYPE_THREAD_SAFE,
1174  .inst_size = sizeof(rlm_perl_t),
1175 
1176  .config = module_config,
1177  .onload = mod_load,
1178  .unload = mod_unload,
1179  .bootstrap = mod_bootstrap,
1181  .detach = mod_detach,
1182 
1183  .thread_inst_size = sizeof(rlm_perl_thread_t),
1184  .thread_instantiate = mod_thread_instantiate,
1185  .thread_detach = mod_thread_detach,
1186  },
1187  .method_names = (module_method_name_t[]){
1188  /*
1189  * Hack to support old configurations
1190  */
1191  { .name1 = "authorize", .name2 = CF_IDENT_ANY, .method = mod_authorize },
1192 
1193  { .name1 = "recv", .name2 = "accounting-request", .method = mod_preacct },
1194  { .name1 = "recv", .name2 = CF_IDENT_ANY, .method = mod_authorize },
1195  { .name1 = "accounting", .name2 = CF_IDENT_ANY, .method = mod_accounting },
1196  { .name1 = "authenticate", .name2 = CF_IDENT_ANY, .method = mod_authenticate },
1197  { .name1 = "send", .name2 = CF_IDENT_ANY, .method = mod_post_auth },
1199  }
1200 };
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:574
int const char * file
Definition: acutest.h:702
log_entry msg
Definition: acutest.h:794
#define RCSID(id)
Definition: build.h:444
#define DIAG_UNKNOWN_PRAGMAS
Definition: build.h:417
#define DIAG_ON(_x)
Definition: build.h:419
#define UNUSED
Definition: build.h:313
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
#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:268
#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:256
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition: cf_parse.h:406
@ CONF_FLAG_FILE_INPUT
File matching value must exist, and must be readable.
Definition: cf_parse.h:412
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
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:89
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition: cf_util.c:597
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: cf_util.c:629
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition: cf_util.c:1495
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:970
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1511
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: cf_util.c:649
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition: cf_util.c:583
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1112
#define cf_item_next(_ci, _prev)
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:385
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:405
static void * fr_dcursor_next_peek(fr_dcursor_t *cursor)
Return the next iterator item without advancing the cursor.
Definition: dcursor.h:302
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
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:146
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
fr_dict_attr_t const * fr_dict_attr_search_by_qualified_oid(fr_dict_attr_err_t *err, fr_dict_t const *dict_def, char const *attr, bool internal, bool foreign))
Locate a qualified fr_dict_attr_t by its name and a dictionary qualifier.
Definition: dict_util.c:2678
static fr_slen_t in
Definition: dict.h:645
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
void *_CONST data
Module instance's parsed configuration.
Definition: dl_module.h:165
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
CONF_SECTION *_CONST conf
Module's instance configuration.
Definition: dl_module.h:166
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:427
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:443
#define DEBUG3(_fmt,...)
Definition: log.h:266
#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:290
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:599
#define ENTER(_x)
Definition: machine.h:93
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_INT32
32 Bit signed integer.
Definition: merged_model.c:105
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
@ FR_TYPE_FLOAT64
Double precision floating point.
Definition: merged_model.c:109
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
void * thread
Thread specific instance data.
Definition: module_ctx.h:43
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:52
void * thread
Thread instance data.
Definition: module_ctx.h:62
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:42
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:51
Temporary structure to hold arguments for thread_instantiation calls.
Definition: module_ctx.h:58
Specifies a module method identifier.
Definition: module_method.c:36
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:37
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:2978
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
Definition: pair.c:462
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:2781
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, bool tainted)
Convert string value to native attribute value.
Definition: pair.c:2586
int8_t fr_pair_cmp_by_da(void const *a, void const *b)
Order attributes by their da, and tag.
Definition: pair.c:1841
static const conf_parser_t config[]
Definition: base.c:188
#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
#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 unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_chap.c:228
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_chap.c:176
static unlang_action_t mod_accounting(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Write accounting data to Couchbase documents.
static unlang_action_t mod_post_auth(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_detail.c:400
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:310
static int mod_detach(module_detach_ctx_t const *mctx)
Definition: rlm_perl.c:1075
static int mod_load(void)
Definition: rlm_perl.c:1111
PerlInterpreter * perl
Thread specific perl interpreter.
Definition: rlm_perl.c:83
#define RLM_PERL_FUNC(_x)
Definition: rlm_perl.c:902
static xlat_arg_parser_t const perl_xlat_args[]
Definition: rlm_perl.c:417
static XS(XS_radiusd_log)
Definition: rlm_perl.c:181
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:525
#define RLM_PERL_CONF(_x)
Definition: rlm_perl.c:91
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition: rlm_perl.c:584
#define dl_modules
Definition: rlm_perl.c:117
module_rlm_t rlm_perl
Definition: rlm_perl.c:1169
static void rlm_perl_interp_free(PerlInterpreter *perl)
Definition: rlm_perl.c:919
static unlang_action_t do_perl(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request, PerlInterpreter *interp, char const *function_name)
Definition: rlm_perl.c:799
static void mod_unload(void)
Definition: rlm_perl.c:1152
static void xs_init(pTHX)
Definition: rlm_perl.c:234
#define LOAD_WARN(_fmt,...)
static void rlm_perl_close_handles(void **handles)
Definition: rlm_perl.c:160
rlm_perl_t
Definition: rlm_perl.c:80
static void perl_store_vps(UNUSED TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vps, HV *rad_hv, const char *hash_name, const char *list_name)
Definition: rlm_perl.c:640
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Definition: rlm_perl.c:947
static void ** rlm_perl_get_handles(pTHX)
Definition: rlm_perl.c:126
DIAG_OFF(compound-token-split-by-macro) typedef struct
Definition: rlm_perl.c:37
static int pairadd_sv(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vps, char *key, SV *sv, const char *hash_name, const char *list_name)
Definition: rlm_perl.c:716
#define dl_librefs
Definition: rlm_perl.c:116
static void perl_vp_to_svpvn_element(request_t *request, AV *av, fr_pair_t const *vp, int *i, const char *hash_name, const char *list_name)
Definition: rlm_perl.c:594
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:256
static void * perl_dlhandle
To allow us to load perl's symbols into the global symbol table.
Definition: rlm_perl.c:86
#define LOAD_INFO(_fmt,...)
static const conf_parser_t module_config[]
Definition: rlm_perl.c:94
static _Thread_local request_t * rlm_perl_request
Definition: rlm_perl.c:114
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Definition: rlm_perl.c:974
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_perl.c:997
static int get_hv_content(TALLOC_CTX *ctx, request_t *request, HV *my_hv, fr_pair_list_t *vps, const char *hash_name, const char *list_name)
Definition: rlm_perl.c:764
static void rlm_perl_clear_handles(pTHX)
Definition: rlm_perl.c:118
static char const * name
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1312
static unlang_action_t mod_preacct(rlm_rcode_t *p_result, module_ctx_t const *mctx, UNUSED request_t *request)
Definition: rlm_test.c:248
#define FR_SBUFF_OUT(_start, _len_or_end)
@ MODULE_TYPE_THREAD_SAFE
Module is threadsafe.
Definition: module.h:49
#define MODULE_NAME_TERMINATOR
Definition: module.h:135
return count
Definition: module.c:175
RETURN_MODULE_FAIL
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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:270
@ T_BARE_WORD
Definition: token.h:120
bool required
Argument must be present, and non-empty.
Definition: xlat.h:146
@ XLAT_ARG_VARIADIC_EMPTY_KEEP
Empty argument groups are left alone, and either passed through as empty groups or null boxes.
Definition: xlat.h:137
static fr_slen_t head
Definition: xlat.h:408
#define XLAT_ARG_PARSER_TERMINATOR
Definition: xlat.h:166
xlat_action_t
Definition: xlat.h:35
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition: xlat.h:42
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition: xlat.h:41
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:1470
Definition for a single argument consumend by an xlat function.
Definition: xlat.h:145
#define ATTRIBUTE_EQ(_x, _y)
Definition: pair.h:147
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
Definition: pair_inline.c:125
#define PAIR_VERIFY(_x)
Definition: pair.h:190
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.
Definition: pair_inline.c:140
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Definition: pair_inline.c:113
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.
Definition: pair_inline.c:182
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:40
#define PAIR_LIST_VERIFY(_x)
Definition: pair.h:193
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.h:590
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:5301
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:4097
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:608
#define fr_box_strvalue_len(_val, _len)
Definition: value.h:279
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition: value.h:619
#define fr_value_box_list_foreach(_list_head, _iter)
Definition: value.h:199
static size_t char ** out
Definition: value.h:984
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition: xlat_ctx.h:45
An xlat calling ctx.
Definition: xlat_ctx.h:42
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition: xlat_func.c:360
xlat_t * xlat_func_register_module(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function for a module.
Definition: xlat_func.c:274