Coverage Report

Created: 2026-04-12 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/server/module_rlm.c
Line
Count
Source
1
/*
2
 *   This program 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
5
 *   (at 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: e448fdac7ab12ff57480adcf5f0d83b44c68eb63 $
19
 *
20
 * @file src/lib/server/module_rlm.c
21
 * @brief Defines functions for rlm module (re-)initialisation.
22
 *
23
 * @copyright 2003,2006,2016 The FreeRADIUS server project
24
 * @copyright 2016,2024 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25
 * @copyright 2000 Alan DeKok (aland@freeradius.org)
26
 * @copyright 2000 Alan Curry (pacman@world.std.com)
27
 */
28
29
RCSID("$Id: e448fdac7ab12ff57480adcf5f0d83b44c68eb63 $")
30
31
#include <freeradius-devel/server/cf_file.h>
32
33
#include <freeradius-devel/server/global_lib.h>
34
#include <freeradius-devel/server/modpriv.h>
35
#include <freeradius-devel/server/module_rlm.h>
36
#include <freeradius-devel/server/pair.h>
37
38
#include <freeradius-devel/util/atexit.h>
39
40
#include <freeradius-devel/unlang/compile.h>
41
42
#include <freeradius-devel/unlang/xlat_func.h>
43
#include <freeradius-devel/unlang/xlat_redundant.h>
44
45
46
/** Lookup virtual module by name
47
 */
48
static fr_rb_tree_t *module_rlm_virtual_name_tree;
49
50
typedef struct {
51
  fr_rb_node_t      name_node;  //!< Entry in the name tree.
52
  char const      *name;    //!< module name
53
  CONF_SECTION      *cs;    //!< CONF_SECTION where it is defined
54
  bool        all_same;
55
} module_rlm_virtual_t;
56
57
/** Compare virtual modules by name
58
 */
59
static int8_t module_rlm_virtual_name_cmp(void const *one, void const *two)
60
0
{
61
0
  module_rlm_virtual_t const *a = one;
62
0
  module_rlm_virtual_t const *b = two;
63
0
  int ret;
64
65
0
  ret = strcmp(a->name, b->name);
66
0
  return CMP(ret, 0);
67
0
}
68
69
/** Global module list for all backend modules
70
 *
71
 */
72
static module_list_t *rlm_modules_static;
73
74
/** Runtime instantiated list
75
 *
76
 */
77
static module_list_t *rlm_modules_dynamic;
78
79
/** Print information on all loaded modules
80
 *
81
 */
82
void module_rlm_list_debug(void)
83
0
{
84
0
  module_list_debug(rlm_modules_static);
85
0
}
86
87
/** Initialise a module specific exfile handle
88
 *
89
 * @see exfile_init
90
 *
91
 * @param[in] ctx   to bind the lifetime of the exfile handle to.
92
 * @param[in] module    section.
93
 * @param[in] max_entries Max file descriptors to cache, and manage locks for.
94
 * @param[in] max_idle    Maximum time a file descriptor can be idle before it's closed.
95
 * @param[in] locking   Whether or not to lock the files.
96
 * @param[in] triggers    Should triggers be enabled.
97
 * @param[in] trigger_prefix  if NULL will be set automatically from the module CONF_SECTION.
98
 * @param[in] trigger_args  to make available in any triggers executed by the connection pool.
99
 * @return
100
 *  - New connection pool.
101
 *  - NULL on error.
102
 */
103
exfile_t *module_rlm_exfile_init(TALLOC_CTX *ctx,
104
         CONF_SECTION *module,
105
         uint32_t max_entries,
106
         fr_time_delta_t max_idle,
107
         bool locking,
108
         bool triggers,
109
         char const *trigger_prefix,
110
         fr_pair_list_t *trigger_args)
111
0
{
112
0
  char    trigger_prefix_buff[128];
113
0
  bool    prefix_set = trigger_prefix ? true : false;
114
0
  exfile_t  *handle;
115
116
0
  if (!trigger_prefix) {
117
0
    snprintf(trigger_prefix_buff, sizeof(trigger_prefix_buff), "modules.%s.file", cf_section_name1(module));
118
0
    trigger_prefix = trigger_prefix_buff;
119
0
  }
120
121
0
  handle = exfile_init(ctx, max_entries, max_idle, locking);
122
0
  if (!handle) return NULL;
123
124
0
  if (triggers) exfile_enable_triggers(handle, prefix_set ? module : cf_section_find(module, "file", NULL),
125
0
               trigger_prefix, trigger_args);
126
127
0
  return handle;
128
0
}
129
130
/** Resolve polymorphic item's from a module's #CONF_SECTION to a subsection in another module
131
 *
132
 * This allows certain module sections to reference module sections in other instances
133
 * of the same module and share #CONF_DATA associated with them.
134
 *
135
 * @verbatim
136
   example {
137
    data {
138
      ...
139
    }
140
   }
141
142
   example inst {
143
    data = example
144
   }
145
 * @endverbatim
146
 *
147
 * @param[out] out where to write the pointer to a module's config section.  May be NULL on success,
148
 *  indicating the config item was not found within the module #CONF_SECTION
149
 *  or the chain of module references was followed and the module at the end of the chain
150
 *  did not a subsection.
151
 * @param[in] module #CONF_SECTION.
152
 * @param[in] name of the polymorphic sub-section.
153
 * @return
154
 *  - 0 on success with referenced section.
155
 *  - 1 on success with local section.
156
 *  - -1 on failure.
157
 */
158
int module_rlm_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char const *name)
159
0
{
160
0
  CONF_PAIR   *cp;
161
0
  CONF_SECTION    *cs;
162
0
  CONF_DATA const   *cd;
163
164
165
0
  module_instance_t *mi;
166
0
  char const    *inst_name;
167
168
0
#define FIND_SIBLING_CF_KEY "find_sibling"
169
170
0
  *out = NULL;
171
172
  /*
173
   *  Is a real section (not referencing sibling module).
174
   */
175
0
  cs = cf_section_find(module, name, NULL);
176
0
  if (cs) {
177
0
    *out = cs;
178
0
    return 0;
179
0
  }
180
181
  /*
182
   *  Item omitted completely from module config.
183
   */
184
0
  cp = cf_pair_find(module, name);
185
0
  if (!cp) return 0;
186
187
0
  if (cf_data_find(module, CONF_SECTION, FIND_SIBLING_CF_KEY)) {
188
0
    cf_log_err(cp, "Module reference loop found");
189
0
    return -1;
190
0
  }
191
0
  cd = cf_data_add(module, module, FIND_SIBLING_CF_KEY, false);
192
193
  /*
194
   *  Item found, resolve it to a module instance.
195
   *  This triggers module loading, so we don't have
196
   *  instantiation order issues.
197
   */
198
0
  inst_name = cf_pair_value(cp);
199
0
  mi = module_instance_by_name(rlm_modules_static, NULL, inst_name);
200
0
  if (!mi) {
201
0
    cf_log_err(cp, "Unknown module instance \"%s\"", inst_name);
202
0
  error:
203
0
    cf_data_remove_by_data(module, cd);
204
0
    return -1;
205
0
  }
206
207
0
  if ((mi->state != MODULE_INSTANCE_INSTANTIATED) &&
208
0
      (module_instantiate(module_instance_by_name(rlm_modules_static, NULL, inst_name)) < 0)) {
209
0
        goto error;
210
0
  }
211
212
  /*
213
   *  Remove the config data we added for loop
214
   *  detection.
215
   */
216
0
  cf_data_remove_by_data(module, cd);
217
218
  /*
219
   *  Check the module instances are of the same type.
220
   */
221
0
  if (strcmp(cf_section_name1(mi->conf), cf_section_name1(module)) != 0) {
222
0
    cf_log_err(cp, "Referenced module is a rlm_%s instance, must be a rlm_%s instance",
223
0
            cf_section_name1(mi->conf), cf_section_name1(module));
224
0
    return -1;
225
0
  }
226
227
0
  *out = cf_section_find(mi->conf, name, NULL);
228
229
0
  return 1;
230
0
}
231
232
xlat_t *module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx,
233
         char const *name, xlat_func_t func, fr_type_t return_type)
234
{
235
  module_instance_t *mi = mctx->mi;
236
  module_rlm_instance_t *mri = talloc_get_type_abort(mi->uctx, module_rlm_instance_t);
237
  module_rlm_xlat_t *mrx;
238
  xlat_t      *x;
239
  char      inst_name[256];
240
241
  fr_assert_msg(name != mctx->mi->name, "`name` must not be the same as the module "
242
          "instance name.  Pass a NULL `name` arg if this is required");
243
244
  if (!name) {
245
    name = mctx->mi->name;
246
  } else {
247
    if ((size_t)snprintf(inst_name, sizeof(inst_name), "%s.%s", mctx->mi->name, name) >= sizeof(inst_name)) {
248
      ERROR("%s: Instance name too long", __FUNCTION__);
249
      return NULL;
250
    }
251
    name = inst_name;
252
  }
253
254
  x = xlat_func_register(ctx, name, func, return_type);
255
  if (unlikely(x == NULL)) return NULL;
256
257
  xlat_mctx_set(x, mctx);
258
259
  MEM(mrx = talloc(mi, module_rlm_xlat_t));
260
  mrx->xlat = x;
261
  mrx->mi = mi;
262
263
  fr_dlist_insert_tail(&mri->xlats, mrx);
264
265
  return x;
266
}
267
268
/** Initialise a module specific connection pool
269
 *
270
 * @see fr_pool_init
271
 *
272
 * @param[in] module    section.
273
 * @param[in] opaque    data pointer to pass to callbacks.
274
 * @param[in] c     Callback to create new connections.
275
 * @param[in] a     Callback to check the status of connections.
276
 * @param[in] log_prefix  override, if NULL will be set automatically from the module CONF_SECTION.
277
 * @param[in] trigger_prefix  if NULL will be set automatically from the module CONF_SECTION.
278
 * @param[in] trigger_args  to make available in any triggers executed by the connection pool.
279
 * @return
280
 *  - New connection pool.
281
 *  - NULL on error.
282
 */
283
fr_pool_t *module_rlm_connection_pool_init(CONF_SECTION *module,
284
             void *opaque,
285
             fr_pool_connection_create_t c,
286
             fr_pool_connection_alive_t a,
287
             char const *log_prefix,
288
             char const *trigger_prefix,
289
             fr_pair_list_t *trigger_args)
290
0
{
291
0
  CONF_SECTION *cs, *mycs;
292
0
  char log_prefix_buff[128];
293
0
  char trigger_prefix_buff[128];
294
295
0
  fr_pool_t *pool;
296
0
  char const *mod_name1, *mod_name2;
297
298
0
  int ret;
299
300
0
#define parent_name(_x) cf_section_name(cf_item_to_section(cf_parent(_x)))
301
302
0
  mod_name1 = cf_section_name1(module);
303
0
  mod_name2 = cf_section_name2(module);
304
0
  if (!mod_name2) mod_name2 = mod_name1;
305
306
0
  if (!trigger_prefix) {
307
0
    snprintf(trigger_prefix_buff, sizeof(trigger_prefix_buff), "modules.%s.pool", mod_name1);
308
0
    trigger_prefix = trigger_prefix_buff;
309
0
  }
310
311
0
  if (!log_prefix) {
312
0
    snprintf(log_prefix_buff, sizeof(log_prefix_buff), "rlm_%s (%s)", mod_name1, mod_name2);
313
0
    log_prefix = log_prefix_buff;
314
0
  }
315
316
  /*
317
   *  Get sibling's pool config section
318
   */
319
0
  ret = module_rlm_sibling_section_find(&cs, module, "pool");
320
0
  switch (ret) {
321
0
  case -1:
322
0
    return NULL;
323
324
0
  case 1:
325
0
    DEBUG4("%s: Using pool section from \"%s\"", log_prefix, parent_name(cs));
326
0
    break;
327
328
0
  case 0:
329
0
    DEBUG4("%s: Using local pool section", log_prefix);
330
0
    break;
331
0
  }
332
333
  /*
334
   *  Get our pool config section
335
   */
336
0
  mycs = cf_section_find(module, "pool", NULL);
337
0
  if (!mycs) {
338
0
    DEBUG4("%s: Adding pool section to module configuration \"%s\" to store pool references", log_prefix,
339
0
           mod_name2);
340
341
0
    mycs = cf_section_alloc(module, module, "pool", NULL);
342
0
    if (!mycs) return NULL;
343
0
  }
344
345
  /*
346
   *  Sibling didn't have a pool config section
347
   *  Use our own local pool.
348
   */
349
0
  if (!cs) {
350
0
    DEBUG4("%s: \"%s.pool\" section not found, using \"%s.pool\"", log_prefix,
351
0
           mod_name1, parent_name(mycs));
352
0
    cs = mycs;
353
0
  }
354
355
  /*
356
   *  If fr_pool_init has already been called
357
   *  for this config section, reuse the previous instance.
358
   *
359
   *  This allows modules to pass in the config sections
360
   *  they would like to use the connection pool from.
361
   */
362
0
  pool = cf_data_value(cf_data_find(cs, fr_pool_t, NULL));
363
0
  if (!pool) {
364
0
    DEBUG4("%s: No pool reference found for config item \"%s.pool\"", log_prefix, parent_name(cs));
365
0
    pool = fr_pool_init(cs, cs, opaque, c, a, log_prefix);
366
0
    if (!pool) return NULL;
367
368
0
    fr_pool_enable_triggers(pool, trigger_prefix, trigger_args);
369
370
0
    if (fr_pool_start(pool) < 0) {
371
0
      ERROR("%s: Starting initial connections failed", log_prefix);
372
0
      return NULL;
373
0
    }
374
375
0
    DEBUG4("%s: Adding pool reference %p to config item \"%s.pool\"", log_prefix, pool, parent_name(cs));
376
0
    cf_data_add(cs, pool, NULL, false);
377
0
    return pool;
378
0
  }
379
0
  fr_pool_ref(pool);
380
381
0
  DEBUG4("%s: Found pool reference %p in config item \"%s.pool\"", log_prefix, pool, parent_name(cs));
382
383
  /*
384
   *  We're reusing pool data add it to our local config
385
   *  section. This allows other modules to transitively
386
   *  reuse a pool through this module.
387
   */
388
0
  if (mycs != cs) {
389
0
    DEBUG4("%s: Copying pool reference %p from config item \"%s.pool\" to config item \"%s.pool\"",
390
0
           log_prefix, pool, parent_name(cs), parent_name(mycs));
391
0
    cf_data_add(mycs, pool, NULL, false);
392
0
  }
393
394
0
  return pool;
395
0
}
396
397
/** Set the next section type if it's not already set
398
 *
399
 * @param[in] request   The current request.
400
 * @param[in] type_da   to use.  Usually attr_auth_type.
401
 * @param[in] enumv   Enumeration value of the specified type_da.
402
 */
403
bool module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv)
404
0
{
405
0
  fr_pair_t *vp;
406
407
0
  switch (pair_update_control(&vp, type_da)) {
408
0
  case 0:
409
0
    if (unlikely(fr_value_box_copy(vp, &vp->data, enumv->value) < 0)) {
410
0
      fr_strerror_printf("Failed to set control.%pP to %s", vp, enumv->name);
411
0
      return false;
412
0
    }
413
0
    vp->data.enumv = vp->da;  /* So we get the correct string alias */
414
0
    RDEBUG2("Setting control.%pP", vp);
415
0
    return true;
416
417
0
  case 1:
418
0
    RDEBUG2("control.%s already set.  Not setting to %s", vp->da->name, enumv->name);
419
0
    return false;
420
421
0
  default:
422
0
    return false;
423
0
  }
424
0
}
425
426
/** Iterate over an array of named module methods, looking for matches
427
 *
428
 * @param[in] mmg   A structure containing a terminated array of
429
 *        module method bindings. pre-sorted using #section_name_cmp
430
 *        with name2 sublists populated.
431
 * @param[in] section   name1 of the method being called can be one of the following:
432
 *        - An itenfier.
433
 *        - CF_IDENT_ANY if the method is a wildcard.
434
 *        name2 of the method being called can be one of the following:
435
 *        - An itenfier.
436
 *        - NULL to match section names with only a name1.
437
 *        - CF_IDENT_ANY if the method is a wildcard.
438
 * @return
439
 *  - The module_method_name_t on success.
440
 *  - NULL on not found.
441
 */
442
static CC_HINT(nonnull)
443
module_method_binding_t const *module_binding_find(module_method_group_t const *mmg, section_name_t const *section)
444
0
{
445
0
  module_method_group_t const *mmg_p = mmg;
446
0
  module_method_binding_t const *p;
447
448
0
  while (mmg_p) {
449
    /*
450
     *  This could potentially be improved by using a binary search
451
     *  but given the small number of items, reduced branches and
452
     *  sequential access just scanning the list, it's probably not
453
     *  worth it.
454
     */
455
0
    for (p = mmg_p->bindings; p->section; p++) {
456
0
      switch (section_name_match(p->section, section)) {
457
0
      case 1:   /* match */
458
0
        return p;
459
460
0
      case -1:  /* name1 didn't match, skip to the end of the sub-list */
461
0
        p = fr_dlist_tail(&p->same_name1);
462
0
        break;
463
464
0
      case 0:   /* name1 did match - see if we can find a matching name2 */
465
0
      {
466
0
        fr_dlist_head_t const *same_name1 = &p->same_name1;
467
468
0
        while ((p = fr_dlist_next(same_name1, p))) {
469
0
          if (section_name2_match(p->section, section)) return p;
470
0
        }
471
0
        p = fr_dlist_tail(same_name1);
472
0
      }
473
0
        break;
474
0
      }
475
#ifdef __clang_analyzer__
476
      /* Will never be NULL, worse case, p doesn't change*/
477
      if (!p) break;
478
#endif
479
0
    }
480
481
    /*
482
     *  Failed to match, search the next deepest group in the chain.
483
     */
484
0
    mmg_p = mmg_p->next;
485
0
  }
486
487
0
  return NULL;
488
0
}
489
490
/** Dump the available bindings for the module into the strerror stack
491
 *
492
 * @note Methods from _all_ linked module method groups will be pushed onto the error stack.
493
 *
494
 * @param[in] mmg module method group to evaluate.
495
 */
496
static void module_rlm_methods_to_strerror(module_method_group_t const *mmg)
497
0
{
498
0
  module_method_group_t const *mmg_p = mmg;
499
0
  module_method_binding_t const *mmb_p;
500
0
  bool        first = true;
501
502
0
  while (mmg_p) {
503
0
    mmb_p = mmg_p->bindings;
504
505
0
    if (!mmb_p || !mmb_p[0].section) goto next;
506
507
0
    if (first) {
508
0
      fr_strerror_const_push("Available methods are:");
509
0
      first = false;
510
0
    }
511
512
0
    for (; mmb_p->section; mmb_p++) {
513
0
      char const *name1 = section_name_str(mmb_p->section->name1);
514
0
      char const *name2 = section_name_str(mmb_p->section->name2);
515
516
0
      fr_strerror_printf_push("  %s%s%s",
517
0
            name1, name2 ? "." : "", name2 ? name2 : "");
518
0
    }
519
0
  next:
520
0
    mmg_p = mmg_p->next;
521
0
  }
522
523
0
  if (first) {
524
0
    fr_strerror_const_push("No methods available");
525
0
  }
526
0
}
527
528
/** Find an existing module instance and verify it implements the specified method
529
 *
530
 * Extracts the method from the module name where the format is @verbatim <module>[.<method1>[.<method2>]] @endverbatim
531
 * and ensures the module implements the specified method.
532
 *
533
 * @param[in] ctx   to allocate the dynamic module key tmpl from.
534
 * @param[out] mmc_out    the result from resolving the module method,
535
 *        plus the key tmpl for dynamic modules.
536
 *        This is not allocated from the ctx to save the runtime
537
 *        dereference.
538
 * @param[in] vs    Virtual server to search for alternative module names in.
539
 * @param[in] section   Section name containing the module call.
540
 * @param[in] name    The module method call i.e. module[<key>][.<method>]
541
 * @param[in] t_rules   for resolving the dynamic module key.
542
 * @return
543
 *  - The module instance on success.
544
 *  - NULL on not found
545
 *
546
 *  If the module exists but the method doesn't exist, then `method` is set to NULL.
547
 */
548
fr_slen_t module_rlm_by_name_and_method(TALLOC_CTX *ctx, module_method_call_t *mmc_out,
549
                virtual_server_t const *vs, section_name_t const *section, fr_sbuff_t *name,
550
          tmpl_rules_t const *t_rules)
551
0
{
552
0
  fr_sbuff_term_t const   *dyn_tt = &FR_SBUFF_TERMS(
553
0
            L(""),
554
0
            L("\t"),
555
0
            L("\n"),
556
0
            L(" "),
557
0
            L("[")
558
0
          );
559
560
0
  fr_sbuff_term_t const   *elem_tt = &FR_SBUFF_TERMS(
561
0
            L(""),
562
0
            L("\t"),
563
0
            L("\n"),
564
0
            L(" "),
565
0
            L(".")
566
0
          );
567
568
0
  fr_sbuff_t      *elem1;
569
0
  module_method_call_t    *mmc;
570
0
  module_method_call_t    mmc_tmp;
571
0
  module_method_binding_t const *mmb;
572
573
0
  fr_sbuff_marker_t   meth_start;
574
0
  bool        softfail;
575
576
0
  fr_slen_t     slen;
577
0
  fr_sbuff_t      our_name = FR_SBUFF(name);
578
579
0
  mmc = mmc_out ? mmc_out : &mmc_tmp;
580
0
  if (mmc_out) *mmc_out = (module_method_call_t) {};
581
582
0
  softfail = fr_sbuff_next_if_char(&our_name, '-');
583
584
  /*
585
   *  Advance until the start of the dynamic selector
586
   *  (if it exists).
587
   */
588
0
  if (fr_sbuff_adv_until(&our_name, SIZE_MAX, dyn_tt, '\0') == 0) {
589
0
    fr_strerror_printf("Invalid module method name");
590
0
    return fr_sbuff_error(&our_name);
591
0
  }
592
593
0
  FR_SBUFF_TALLOC_THREAD_LOCAL(&elem1, MODULE_INSTANCE_LEN_MAX, (MODULE_INSTANCE_LEN_MAX + 1) * 10);
594
595
  /*
596
   *  If the method string contains a '['
597
   *
598
   *  Search for a dynamic module method, e.g. `elem1[<key>]`.
599
   */
600
0
  if (fr_sbuff_is_char(&our_name, '[')) {
601
0
    fr_sbuff_marker_t end, s_end;
602
0
    fr_sbuff_marker(&end, &our_name);
603
604
0
    slen = tmpl_afrom_substr(ctx, &mmc->key, &our_name, T_BARE_WORD, NULL, t_rules);
605
0
    if (slen < 0) {
606
0
      fr_strerror_const_push("Invalid dynamic module selector expression");
607
0
      return slen;
608
0
    }
609
610
0
    if (!fr_sbuff_is_char(&our_name, ']')) {
611
0
      fr_strerror_const_push("Missing terminating ']' for dynamic module selector");
612
0
    error:
613
0
      return fr_sbuff_error(&our_name);
614
0
    }
615
0
    fr_sbuff_marker(&s_end, &our_name);
616
617
0
    fr_sbuff_set_to_start(&our_name);
618
0
    slen = fr_sbuff_out_bstrncpy(elem1, &our_name, fr_sbuff_ahead(&end));
619
0
    if (slen < 0) {
620
0
      fr_strerror_const("Module method string too long");
621
0
      goto error;
622
0
    }
623
0
    mmc->mi = module_instance_by_name(rlm_modules_dynamic, NULL, elem1->start);
624
0
    if (!mmc->mi) {
625
0
      fr_strerror_printf("No such dynamic module '%s'", elem1->start);
626
0
      goto error;
627
0
    }
628
0
    mmc->rlm = module_rlm_from_module(mmc->mi->exported);
629
630
0
    fr_sbuff_set(&our_name, &s_end);
631
0
    fr_sbuff_advance(&our_name, 1); /* Skip the ']' */
632
  /*
633
   *  With elem1.elem2.elem3
634
   *
635
   *  Search for a static module matching one of the following:
636
   *
637
   *  - elem1.elem2.elem3
638
   *  - elem1.elem2
639
   *  - elem1
640
   */
641
0
  } else {
642
0
    char *p;
643
644
0
    fr_sbuff_set_to_start(&our_name);
645
646
0
    slen = fr_sbuff_out_bstrncpy_until(elem1, &our_name, SIZE_MAX, dyn_tt, NULL);
647
0
    if (slen == 0) {
648
0
      fr_strerror_const("Invalid module name");
649
0
      goto error;
650
0
    }
651
0
    if (slen < 0) {
652
0
      fr_strerror_const("Module method string too long");
653
0
      goto error;
654
0
    }
655
656
    /*
657
     *  Now we have a mutable buffer, we can start chopping
658
     *  it up to find the module.
659
     */
660
0
    for (;;) {
661
0
      mmc->mi = (module_instance_t *)module_rlm_static_by_name(NULL, elem1->start);
662
0
      if (mmc->mi) {
663
0
        mmc->rlm = module_rlm_from_module(mmc->mi->exported);
664
0
        break;  /* Done */
665
0
      }
666
667
0
      p = strrchr(elem1->start, '.');
668
0
      if (!p) break; /* No more '.' */
669
0
      *p = '\0';  /* Chop off the last '.' */
670
0
    }
671
672
0
    if (!mmc->mi) {
673
0
      if (softfail) return fr_sbuff_set(name, &our_name);
674
675
0
      fr_strerror_printf("No such module '%pV'", fr_box_strvalue_len(our_name.start, slen));
676
0
      return -1;
677
0
    }
678
679
0
    fr_sbuff_set_to_start(&our_name);
680
0
    fr_sbuff_advance(&our_name, strlen(elem1->start));  /* Advance past the module name */
681
0
    if (fr_sbuff_is_char(&our_name, '.')) {
682
0
      fr_sbuff_advance(&our_name, 1);     /* Static module method, search directly */
683
0
    } else {
684
0
      fr_sbuff_marker(&meth_start, &our_name);  /* for the errors... */
685
0
      goto by_section;        /* Get the method dynamically from the section*/
686
0
    }
687
0
  }
688
689
  /*
690
   *  For both cases, the buffer should be pointing
691
   *  at the start of the method string.
692
   */
693
0
  fr_sbuff_marker(&meth_start, &our_name);
694
695
  /*
696
   *  If a module method was provided, search for it in the named
697
   *  methods provided by the module.
698
   *
699
   *  The method name should be either:
700
   *
701
   *  - name1
702
   *  - name1.name2
703
   */
704
0
  {
705
0
    section_name_t  method;
706
0
    fr_sbuff_t  *elem2;
707
708
0
    fr_sbuff_set_to_start(elem1); /* May have used this already for module lookups */
709
710
0
    slen = fr_sbuff_out_bstrncpy_until(elem1, &our_name, SIZE_MAX, elem_tt, NULL);
711
0
    if (slen < 0) {
712
0
      fr_strerror_const("Module method string too long");
713
0
      return fr_sbuff_error(&our_name);
714
0
    }
715
0
    if (slen == 0) goto by_section; /* This works for both dynamic and static modules */
716
717
0
    FR_SBUFF_TALLOC_THREAD_LOCAL(&elem2, MODULE_INSTANCE_LEN_MAX, MODULE_INSTANCE_LEN_MAX);
718
719
0
    if (fr_sbuff_is_char(&our_name, '.')) {
720
0
      fr_sbuff_advance(&our_name, 1);
721
0
      if (fr_sbuff_out_bstrncpy_until(elem2, &our_name, SIZE_MAX,
722
0
              elem_tt, NULL) == MODULE_INSTANCE_LEN_MAX) {
723
0
        fr_strerror_const("Module method string too long");
724
0
        goto error;
725
0
      }
726
0
    }
727
728
0
    method = (section_name_t) {
729
0
      .name1 = elem1->start,
730
0
      .name2 = fr_sbuff_used(elem2) ? elem2->start : NULL
731
0
    };
732
733
0
    mmb = module_binding_find(&mmc->rlm->method_group, &method);
734
0
    if (!mmb) {
735
0
      fr_strerror_printf("Module \"%s\" does not have method %s%s%s",
736
0
             mmc->mi->name,
737
0
             method.name1,
738
0
             method.name2 ? "." : "",
739
0
             method.name2 ? method.name2 : ""
740
0
             );
741
742
0
      module_rlm_methods_to_strerror(&mmc->rlm->method_group);
743
0
      return fr_sbuff_error(&meth_start);
744
0
    }
745
0
    mmc->mmb = *mmb;  /* For locality of reference and fewer derefs */
746
0
    if (mmc_out) section_name_dup(ctx, &mmc->asked, &method);
747
748
0
    return fr_sbuff_set(name, &our_name);
749
0
  }
750
751
0
by_section:
752
  /*
753
   *  First look for the section name in the module's
754
   *  bindings.  If that fails, look for the alt
755
   *  section names from the virtual server section.
756
   *
757
   *  If that fails, we're done.
758
   */
759
0
  mmb = module_binding_find(&mmc->rlm->method_group, section);
760
0
  if (!mmb) {
761
0
    section_name_t const **alt_p = virtual_server_section_methods(vs, section);
762
0
    if (alt_p) {
763
0
      for (; *alt_p; alt_p++) {
764
0
        mmb = module_binding_find(&mmc->rlm->method_group, *alt_p);
765
0
        if (mmb) {
766
0
          if (mmc_out) section_name_dup(ctx, &mmc->asked, *alt_p);
767
0
          break;
768
0
        }
769
0
      }
770
0
    }
771
0
  } else {
772
0
    if (mmc_out) section_name_dup(ctx, &mmc->asked, section);
773
0
  }
774
0
  if (!mmb) {
775
0
    fr_strerror_printf("Module \"%s\" has no method for section %s %s { ... }, i.e. %s%s%s",
776
0
           mmc->mi->name,
777
0
           section->name1,
778
0
           section->name2 ? section->name2 : "",
779
0
           section->name1,
780
0
           section->name2 ? "." : "",
781
0
           section->name2 ? section->name2 : ""
782
0
           );
783
0
    module_rlm_methods_to_strerror(&mmc->rlm->method_group);
784
785
0
    return fr_sbuff_error(&meth_start);
786
0
  }
787
0
  mmc->mmb = *mmb;  /* For locality of reference and fewer derefs */
788
789
0
  return fr_sbuff_set(name, &our_name);
790
0
}
791
792
CONF_SECTION *module_rlm_virtual_by_name(char const *asked_name)
793
0
{
794
0
  module_rlm_virtual_t *inst;
795
796
0
  inst = fr_rb_find(module_rlm_virtual_name_tree,
797
0
        &(module_rlm_virtual_t){
798
0
        .name = asked_name,
799
0
        });
800
0
  if (!inst) return NULL;
801
802
0
  return inst->cs;
803
0
}
804
805
module_instance_t *module_rlm_dynamic_by_name(module_instance_t const *parent, char const *asked_name)
806
0
{
807
0
  return module_instance_by_name(rlm_modules_dynamic, parent, asked_name);
808
0
}
809
810
module_instance_t *module_rlm_static_by_name(module_instance_t const *parent, char const *asked_name)
811
0
{
812
0
  return module_instance_by_name(rlm_modules_static, parent, asked_name);
813
0
}
814
815
/** Create a virtual module.
816
 *
817
 * @param[in] cs  that defines the virtual module.
818
 * @return
819
 *  - 0 on success.
820
 *  - -1 on failure.
821
 */
822
static int module_rlm_bootstrap_virtual(CONF_SECTION *cs)
823
{
824
  char const    *name;
825
  bool      all_same;
826
  CONF_ITEM     *sub_ci = NULL;
827
  CONF_PAIR   *cp;
828
  module_instance_t *mi;
829
  module_rlm_virtual_t  *inst;
830
831
  name = cf_section_name1(cs);
832
833
  /*
834
   *  Groups, etc. must have a name.
835
   */
836
  if ((strcmp(name, "group") == 0) ||
837
      (strcmp(name, "redundant") == 0) ||
838
      (strcmp(name, "redundant-load-balance") == 0) ||
839
      (strcmp(name, "load-balance") == 0)) {
840
    name = cf_section_name2(cs);
841
    if (!name) {
842
      cf_log_err(cs, "Keyword module must have a second name");
843
      return -1;
844
    }
845
846
    /*
847
     *  name2 was already checked in modules_rlm_bootstrap()
848
     */
849
    fr_assert(!unlang_compile_is_keyword(name));
850
  } else {
851
    cf_log_err(cs, "Module names cannot be unlang keywords '%s'", name);
852
    return -1;
853
  }
854
855
  /*
856
   *  Ensure that the module doesn't exist.
857
   */
858
  mi = module_instance_by_name(rlm_modules_static, NULL, name);
859
  if (mi) {
860
    ERROR("Duplicate module \"%s\" in file %s[%d] and file %s[%d]",
861
          name,
862
          cf_filename(cs),
863
          cf_lineno(cs),
864
          cf_filename(mi->conf),
865
          cf_lineno(mi->conf));
866
    return -1;
867
  }
868
869
  /*
870
   *  Don't bother registering redundant xlats for a simple "group".
871
   */
872
  all_same = (strcmp(cf_section_name1(cs), "group") != 0);
873
874
  {
875
    module_t const    *last = NULL;
876
877
    /*
878
    * Ensure that the modules we reference here exist.
879
    */
880
    while ((sub_ci = cf_item_next(cs, sub_ci))) {
881
      if (cf_item_is_pair(sub_ci)) {
882
        cp = cf_item_to_pair(sub_ci);
883
        if (cf_pair_value(cp)) {
884
          cf_log_err(sub_ci, "Cannot set return codes in a %s block", cf_section_name1(cs));
885
          return -1;
886
        }
887
888
        mi = module_rlm_static_by_name(NULL, cf_pair_attr(cp));
889
        if (!mi) {
890
          cf_log_perr(sub_ci, "Failed resolving module reference '%s' in %s block",
891
                cf_pair_attr(cp), cf_section_name1(cs));
892
          return -1;
893
        }
894
895
        if (all_same) {
896
          if (!last) {
897
            last = mi->exported;
898
          } else if (last != mi->exported) {
899
            last = NULL;
900
            all_same = false;
901
          }
902
        }
903
      } else {
904
        all_same = false;
905
      }
906
907
      /*
908
      * Don't check subsections for now.  That check
909
      * happens later in the unlang compiler.
910
      */
911
    } /* loop over things in a virtual module section */
912
  }
913
914
  inst = talloc_zero(cs, module_rlm_virtual_t);
915
  if (!inst) return -1;
916
917
  inst->cs = cs;
918
  MEM(inst->name = talloc_strdup(inst, name));
919
  inst->all_same = all_same;
920
921
  if (!fr_cond_assert(fr_rb_insert(module_rlm_virtual_name_tree, inst))) {
922
    talloc_free(inst);
923
    return -1;
924
  }
925
926
  return 0;
927
}
928
929
/** Generic conf_parser_t func for loading drivers
930
 *
931
 */
932
int module_rlm_submodule_parse(TALLOC_CTX *ctx, void *out, void *parent,
933
             CONF_ITEM *ci, conf_parser_t const *rule)
934
0
{
935
0
  conf_parser_t our_rule = *rule;
936
937
0
  our_rule.uctx = &rlm_modules_static;
938
939
0
  return module_submodule_parse(ctx, out, parent, ci, &our_rule);
940
0
}
941
942
/** Frees thread-specific data for all registered backend modules
943
 *
944
 */
945
void modules_rlm_thread_detach(void)
946
0
{
947
0
  modules_thread_detach(rlm_modules_static);
948
0
}
949
950
/** Allocates thread-specific data for all registered backend modules
951
 *
952
 * @param[in] ctx To allocate any thread-specific data in.
953
 * @param[in] el  to register events.
954
 * @return
955
 *  - 0 if all modules were instantiated successfully.
956
 *  - -1 if a module failed instantiation.
957
 */
958
int modules_rlm_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
959
0
{
960
0
  return modules_thread_instantiate(ctx, rlm_modules_static, el);
961
0
}
962
963
/** Runs the coord_attach method of all registered backend modules
964
 *
965
 * @param[in] el  to register events.
966
 * @return
967
 *  - 0 if all calls succeeded.
968
 *  - -1 if a call failed.
969
 */
970
int modules_rlm_coord_attach(fr_event_list_t *el)
971
0
{
972
0
  return modules_coord_attach(rlm_modules_static, el);
973
0
}
974
975
/** Performs the instantiation phase for all backend modules
976
 *
977
 * @return
978
 *  - 0 if all modules were instantiated successfully.
979
 *  - -1 if a module failed instantiation.
980
 */
981
int modules_rlm_instantiate(void)
982
0
{
983
0
  return modules_instantiate(rlm_modules_static);
984
0
}
985
986
/** Compare the section names of two module_method_binding_t structures
987
 */
988
static int8_t binding_name_cmp(void const *one, void const *two)
989
0
{
990
0
  module_method_binding_t const *a = one;
991
0
  module_method_binding_t const *b = two;
992
993
0
  return section_name_cmp(a->section, b->section);
994
0
}
995
996
static int module_method_group_validate(module_method_group_t *group)
997
0
{
998
0
  module_method_binding_t *p, *srt_p;
999
0
  fr_dlist_head_t   bindings;
1000
0
  bool      in_order = true;
1001
1002
  /*
1003
   *  Not all modules export module method bindings
1004
   */
1005
0
  if (!group || !group->bindings || group->validated) return 0;
1006
1007
0
  fr_dlist_init(&bindings, module_method_binding_t, entry);
1008
1009
0
  for (p = group->bindings; p->section; p++) {
1010
0
    if (!fr_cond_assert_msg(p->section->name1,
1011
0
          "First section identifier can't be NULL")) return -1;
1012
1013
    /*
1014
     *  All the bindings go in a list so we can sort them
1015
     *  and produce the list in the correct order.
1016
     */
1017
0
    fr_dlist_insert_tail(&bindings, p);
1018
0
  }
1019
1020
0
  fr_dlist_sort(&bindings, binding_name_cmp);
1021
1022
  /*
1023
   *  Iterate over the sorted list of bindings,
1024
   *  and the original list, to ensure they're
1025
   *  in the correct order.
1026
   */
1027
0
  for (srt_p = fr_dlist_head(&bindings), p = group->bindings;
1028
0
       srt_p;
1029
0
       srt_p = fr_dlist_next(&bindings, srt_p), p++) {
1030
0
    if (p != srt_p) {
1031
0
      in_order = false;
1032
0
      break;
1033
0
    }
1034
0
  }
1035
1036
  /*
1037
   *  Rebuild the binding list in the correct order.
1038
   */
1039
0
  if (!in_order) {
1040
0
    module_method_binding_t *ordered;
1041
1042
0
    MEM(ordered = talloc_array(NULL, module_method_binding_t, fr_dlist_num_elements(&bindings)));
1043
0
    for (srt_p = fr_dlist_head(&bindings), p = ordered;
1044
0
         srt_p;
1045
0
         srt_p = fr_dlist_next(&bindings, srt_p), p++) {
1046
0
      *p = *srt_p;
1047
0
    }
1048
0
    memcpy(group->bindings, ordered, fr_dlist_num_elements(&bindings) * sizeof(*ordered));
1049
0
    talloc_free(ordered);
1050
0
  }
1051
1052
  /*
1053
   *  Build the "skip" list of name1 entries
1054
   */
1055
0
  {
1056
0
    module_method_binding_t *last_binding = NULL;
1057
1058
0
    for (p = group->bindings; p->section; p++) {
1059
0
      if (!last_binding ||
1060
0
        (
1061
0
          (last_binding->section->name1 != p->section->name1) &&
1062
0
          (
1063
0
            (last_binding->section->name1 == CF_IDENT_ANY) ||
1064
0
            (p->section->name1 == CF_IDENT_ANY) ||
1065
0
            (strcmp(last_binding->section->name1, p->section->name1) != 0)
1066
0
          )
1067
0
        )
1068
0
      ) {
1069
0
        fr_dlist_init(&p->same_name1, module_method_binding_t, entry);
1070
0
        last_binding = p;
1071
0
      }
1072
0
      fr_dlist_insert_tail(&last_binding->same_name1, p);
1073
0
    }
1074
0
  }
1075
0
  group->validated = true;
1076
1077
0
  return module_method_group_validate(group->next);
1078
0
}
1079
1080
static int module_method_validate(module_instance_t *mi)
1081
0
{
1082
0
  module_rlm_t *mrlm = module_rlm_from_module(mi->exported);
1083
1084
0
  return module_method_group_validate(&mrlm->method_group);
1085
0
}
1086
1087
/** Allocate a rlm module instance
1088
 *
1089
 * These have extra space allocated to hold the dlist of associated xlats.
1090
 *
1091
 * @param[in] ml    Module list to allocate from.
1092
 * @param[in] parent    Parent module instance.
1093
 * @param[in] type    Type of module instance.
1094
 * @param[in] mod_name    Name of the module.
1095
 * @param[in] inst_name   Name of the instance.
1096
 * @param[in] init_state  Initial state of the module instance.
1097
 * @return
1098
 *  - The allocated module instance on success.
1099
 *  - NULL on failure.
1100
 */
1101
static inline CC_HINT(always_inline)
1102
module_instance_t *module_rlm_instance_alloc(module_list_t *ml,
1103
               module_instance_t const *parent,
1104
               dl_module_type_t type, char const *mod_name, char const *inst_name,
1105
               module_instance_state_t init_state)
1106
{
1107
  module_instance_t *mi;
1108
  module_rlm_instance_t *mri;
1109
1110
  mi = module_instance_alloc(ml, parent, type, mod_name, inst_name, init_state);
1111
  if (unlikely(mi == NULL)) return NULL;
1112
1113
  MEM(mri = talloc(mi, module_rlm_instance_t));
1114
  module_instance_uctx_set(mi, mri);
1115
1116
  fr_dlist_talloc_init(&mri->xlats, module_rlm_xlat_t, entry);
1117
1118
  return mi;
1119
}
1120
1121
static int module_conf_parse(module_list_t *ml, CONF_SECTION *mod_conf)
1122
0
{
1123
0
  char const    *name;
1124
0
  char const    *inst_name;
1125
0
  module_instance_t *mi = NULL;
1126
0
  CONF_SECTION    *actions;
1127
1128
  /*
1129
   *  name2 can't be a keyword
1130
   */
1131
0
  name = cf_section_name2(mod_conf);
1132
0
  if (name && unlang_compile_is_keyword(name)) {
1133
0
  invalid_name:
1134
0
    cf_log_err(mod_conf, "Module names cannot be unlang keywords '%s'", name);
1135
0
    return -1;
1136
0
  }
1137
1138
0
  name = cf_section_name1(mod_conf);
1139
1140
  /*
1141
   *  For now, ignore name1 which is a keyword.
1142
   */
1143
0
  if (unlang_compile_is_keyword(name)) {
1144
0
    if (!cf_section_name2(mod_conf)) {
1145
0
      cf_log_err(mod_conf, "Missing second name at '%s'", name);
1146
0
      return -1;
1147
0
    }
1148
0
    if (module_rlm_bootstrap_virtual(mod_conf) < 0) return -1;
1149
0
    return 0;
1150
0
  }
1151
1152
  /*
1153
   *  Skip inline templates, and disallow "template { ... }"
1154
   */
1155
0
  if (strcmp(name, "template") == 0) {
1156
0
    if (!cf_section_name2(mod_conf)) goto invalid_name;
1157
0
    return 0;
1158
0
  }
1159
1160
0
  if (module_instance_name_from_conf(&inst_name, mod_conf) < 0) goto invalid_name;
1161
1162
0
  mi = module_rlm_instance_alloc(ml, NULL, DL_MODULE_TYPE_MODULE, name, inst_name, 0);
1163
0
  if (unlikely(mi == NULL)) {
1164
0
    cf_log_perr(mod_conf, "Failed loading module");
1165
0
    return -1;
1166
0
  }
1167
1168
  /*
1169
   *  First time we've loaded the dl module, so we need to
1170
   *  check the module methods to make sure they're ordered
1171
   *  correctly, and to add the "skip list" style name2
1172
   *  entries.
1173
   */
1174
0
  if ((mi->module->refs == 1) && (module_method_validate(mi) < 0)) {
1175
0
    talloc_free(mi);
1176
0
    return -1;
1177
0
  }
1178
1179
0
  if (module_instance_conf_parse(mi, mod_conf) < 0) {
1180
0
    cf_log_perr(mod_conf, "Failed parsing module config");
1181
0
    talloc_free(mi);
1182
0
    return -1;
1183
0
  }
1184
1185
  /*
1186
   *  Compile the default "actions" subsection, which includes retries.
1187
   */
1188
0
  actions = cf_section_find(mod_conf, "actions", NULL);
1189
0
  if (actions && !unlang_compile_actions(&mi->actions, actions, (mi->exported->flags & MODULE_TYPE_RETRY))) {
1190
0
    talloc_free(mi);
1191
0
    return -1;
1192
0
  }
1193
1194
0
  return 0;
1195
0
}
1196
1197
/** Bootstrap modules and virtual modules
1198
 *
1199
 * Parse the module config sections, and load and call each module's init() function.
1200
 *
1201
 * @param[in] root of the server configuration.
1202
 * @return
1203
 *  - 0 if all modules were bootstrapped successfully.
1204
 *  - -1 if a module/virtual module failed to bootstrap.
1205
 */
1206
int modules_rlm_bootstrap(CONF_SECTION *root)
1207
0
{
1208
0
  CONF_SECTION    *cs, *modules, *static_cs, *dynamic_cs;
1209
0
  module_rlm_virtual_t  *vm;
1210
0
  fr_rb_iter_inorder_t  iter;
1211
1212
  /*
1213
   *  Ensure any libraries the modules depend on are instantiated
1214
   */
1215
0
  global_lib_instantiate();
1216
1217
  /*
1218
   *  Remember where the modules were stored.
1219
   */
1220
0
  modules = cf_section_find(root, "modules", NULL);
1221
0
  if (!modules) {
1222
0
    WARN("Cannot find a \"modules\" section in the configuration file!");
1223
0
    return 0;
1224
0
  }
1225
1226
0
  static_cs = cf_section_find(modules, "static", NULL);
1227
0
  if (!static_cs) {
1228
0
    static_cs = cf_section_alloc(modules, NULL, "static", NULL);
1229
0
    cf_section_foreach(modules, mod_cs) {
1230
0
      CONF_ITEM *prev;
1231
0
      char const *name1 = cf_section_name1(mod_cs);
1232
1233
      /*
1234
       *  Skip over the dynamic section
1235
       */
1236
0
      if ((strcmp(name1, "dynamic") == 0) && !cf_section_name2(mod_cs)) continue;
1237
1238
      /*
1239
       *  Ignore this section if it is commented out with a magic name.
1240
       */
1241
0
      if (*name1 == '-') continue;
1242
1243
      /*
1244
       *  Move all modules which are not in
1245
       *  the dynamic section into the static
1246
       *  section for backwards compatibility.
1247
       */
1248
0
      prev = cf_item_remove(modules, mod_cs);
1249
0
      cf_item_add(static_cs, mod_cs);
1250
1251
      /*
1252
       *  Find the previous item that's a section
1253
       */
1254
0
      while (prev && !cf_item_is_section(prev)) prev = cf_item_prev(modules, prev);
1255
1256
      /*
1257
       *  Resume iterating from that item
1258
       */
1259
0
      mod_cs = cf_item_to_section(prev);
1260
0
    }
1261
0
    cf_item_add(modules, static_cs);
1262
0
  }
1263
0
  DEBUG2("#### Bootstrapping static modules ####");
1264
0
  cf_log_debug(modules, " modules {");
1265
0
  cf_log_debug(modules, "    static {");
1266
0
  cf_section_foreach(static_cs, mod_conf) {
1267
0
    if (module_conf_parse(rlm_modules_static, mod_conf) < 0) return -1;
1268
0
  }
1269
0
  cf_log_debug(modules, "    } # static");
1270
1271
  /*
1272
   *  Now we have a module tree, run bootstrap on all the modules.
1273
   *  This will bootstrap modules and then submodules.
1274
   */
1275
0
  if (unlikely(modules_bootstrap(rlm_modules_static) < 0)) return -1;
1276
1277
0
  if (fr_command_register_hook(NULL, NULL, static_cs, module_cmd_list_table) < 0) {
1278
0
    PERROR("Failed registering radmin commands for modules");
1279
0
    return -1;
1280
0
  }
1281
1282
  /*
1283
   *  Build the configuration and parse dynamic modules
1284
   */
1285
0
  dynamic_cs = cf_section_find(modules, "dynamic", NULL);
1286
0
  if (dynamic_cs) {
1287
0
    DEBUG2("#### Bootstrapping dynamic modules ####");
1288
    /*
1289
    * Parse and then instantiate any dynamic modules configure
1290
    */
1291
0
    cf_log_debug(modules, "    dynamic {");
1292
0
    cf_section_foreach(dynamic_cs, mod_conf) {
1293
0
      if (unlikely(module_conf_parse(rlm_modules_dynamic, mod_conf) < 0)) return -1;
1294
0
    }
1295
0
    cf_log_debug(modules, "    } # dynamic");
1296
0
    if (unlikely(modules_bootstrap(rlm_modules_dynamic) < 0)) return -1;
1297
0
    cf_log_debug(modules, " } # modules");
1298
0
  }
1299
1300
  /*
1301
   *  Check for duplicate policies.  They're treated as
1302
   *  modules, so we might as well check them here.
1303
   */
1304
0
  cs = cf_section_find(root, "policy", NULL);
1305
0
  if (cs) {
1306
0
    cf_section_foreach(cs, policy_cs) {
1307
0
      CONF_SECTION  *problemcs;
1308
0
      char const  *name1 = cf_section_name1(policy_cs);
1309
1310
0
      if (unlang_compile_is_keyword(name1)) {
1311
0
        cf_log_err(policy_cs, "Policy name '%s' cannot be an unlang keyword", name1);
1312
0
        return -1;
1313
0
      }
1314
1315
0
      if (cf_section_name2(policy_cs)) {
1316
0
        cf_log_err(policy_cs, "Policies cannot have two names");
1317
0
        return -1;
1318
0
      }
1319
1320
0
      problemcs = cf_section_find_next(cs, policy_cs, name1, CF_IDENT_ANY);
1321
0
      if (!problemcs) continue;
1322
1323
0
      cf_log_err(problemcs, "Duplicate policy '%s' is forbidden.",
1324
0
           cf_section_name1(policy_cs));
1325
0
      return -1;
1326
0
    }
1327
0
  }
1328
1329
  /*
1330
   *  Now that all of the xlat things have been registered,
1331
   *  register our redundant xlats.  But only when all of
1332
   *  the items in such a section are the same.
1333
   */
1334
0
  for (vm = fr_rb_iter_init_inorder(module_rlm_virtual_name_tree, &iter);
1335
0
       vm;
1336
0
       vm = fr_rb_iter_next_inorder(module_rlm_virtual_name_tree, &iter)) {
1337
0
    if (!vm->all_same) continue;
1338
1339
0
    if (xlat_register_redundant(vm->cs) < 0) return -1;
1340
0
  }
1341
1342
0
  return 0;
1343
0
}
1344
1345
/** Cleanup all global structures
1346
 *
1347
 * Automatically called on exit.
1348
 */
1349
int modules_rlm_free(void)
1350
0
{
1351
0
  if (talloc_free(rlm_modules_static) < 0) return -1;
1352
0
  rlm_modules_static = NULL;
1353
1354
0
  if (talloc_free(rlm_modules_dynamic) < 0) return -1;
1355
0
  rlm_modules_dynamic = NULL;
1356
1357
0
  if (talloc_free(module_rlm_virtual_name_tree) < 0) return -1;
1358
0
  module_rlm_virtual_name_tree = NULL;
1359
1360
0
  return 0;
1361
0
}
1362
1363
static int _modules_rlm_free_atexit(UNUSED void *uctx)
1364
0
{
1365
0
  return modules_rlm_free();
1366
0
}
1367
1368
/** Initialise the module list structure
1369
 *
1370
 */
1371
int modules_rlm_init(void)
1372
{
1373
  MEM(rlm_modules_static = module_list_alloc(NULL, &module_list_type_global, "rlm", true));
1374
  MEM(rlm_modules_dynamic = module_list_alloc(NULL, &module_list_type_thread_local, "rlm", true));
1375
  module_list_mask_set(rlm_modules_dynamic, MODULE_INSTANCE_INSTANTIATED);  /* Ensure we never instantiate dynamic modules */
1376
1377
  MEM(module_rlm_virtual_name_tree = fr_rb_inline_alloc(NULL, module_rlm_virtual_t, name_node,
1378
                    module_rlm_virtual_name_cmp, NULL));
1379
  fr_atexit_global(_modules_rlm_free_atexit, NULL);
1380
1381
  return 0;
1382
}